resque_stuck_queue 0.4.3 → 0.4.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4e70424faa8ec9ad5fe004e176521d4563b6b585
4
- data.tar.gz: 11fb88f2d886993e99fbdd65ec2ec0f4a1b62d1a
3
+ metadata.gz: b23678d316199cc108bef89177912ff5eb396d89
4
+ data.tar.gz: 055f4654e2f966a573fd398f2f55cbc56b21b766
5
5
  SHA512:
6
- metadata.gz: 9c4b847e85b9b3741690a131a883d77cb7906099a1f8fada7b5139505e7a69f2a5c66a49c4ca3a35e0eab921d5c68fe0d43567291774d811ec69cc6256f510e7
7
- data.tar.gz: 62750b5b3736c284c9f10f58b37344e4750e4e0454d68a2016636d73854186b2eed89eef9eb7456866927103003c8803112aae48582a6e5050fd68f5241c4eea
6
+ metadata.gz: 9f4df0b59b1b092d6ee389ebea5c45a98a27a35c3e12f14a6566f07349f31d7950b9f55b582cc928303d0fbd952ad06cdf2846c9ac2e6ee5e26e8f50db42f1c0
7
+ data.tar.gz: 315ddbab2de9dbd42bfb803f768da71ad1cb3f34715a8beb974f5d804e9427791dd79cd626c0bf2f3fded698e29ac0141ef764ec655b79a0803b9a314196e296
data/README.md CHANGED
@@ -12,6 +12,12 @@ It will also fire a proc to notify you when it's recovered.
12
12
 
13
13
  ## How it works
14
14
 
15
+ It's a heartbeat mechanism:
16
+
17
+ ![meme](http://cdn.memegenerator.net/instances/500x/43575729.jpg)
18
+
19
+ Ok, seriously:
20
+
15
21
  When you call `start` you are essentially starting two threads that will continiously run until `stop` is called or until the process shuts down.
16
22
 
17
23
  One thread is responsible for pushing a 'heartbeat' job to resque which will essentially refresh a specific key in redis every time that job is processed.
@@ -37,20 +43,20 @@ require 'logger'
37
43
  # change to decent values that make sense for you
38
44
  Resque::StuckQueue.config[:heartbeat_interval] = 10.seconds
39
45
  Resque::StuckQueue.config[:watcher_interval] = 1.seconds
40
- Resque::StuckQueue.config[:trigger_timeout] = 30.seconds
46
+ Resque::StuckQueue.config[:trigger_timeout] = 30.seconds # acceptable lagtime
41
47
 
42
48
  # which queues to monitor
43
49
  Resque::StuckQueue.config[:queues] = [:app, :custom_queue]
44
50
 
45
51
  # handler for when a resque queue is being problematic
46
52
  Resque::StuckQueue.config[:triggered_handler] = proc { |bad_queue, lagtime|
47
- msg = "[BAD] AWSM #{Rails.env}'s Resque #{bad_queue} queue lagging job execution by #{lagtime} seconds."
53
+ msg = "[BAD] APPNAME #{Rails.env}'s Resque #{bad_queue} queue lagging job execution by #{lagtime} seconds."
48
54
  send_email(msg)
49
55
  }
50
56
 
51
57
  # handler for when a resque queue recovers
52
58
  Resque::StuckQueue.config[:recovered_handler] = proc { |good_queue, lagtime|
53
- msg = "[GOOD] AWSM #{Rails.env}'s Resque #{good_queue} queue lagging job execution by #{lagtime} seconds."
59
+ msg = "[GOOD] APPNAME #{Rails.env}'s Resque #{good_queue} queue lagging job execution by #{lagtime} seconds."
54
60
  send_email(msg)
55
61
  }
56
62
 
@@ -137,13 +143,13 @@ queues:
137
143
  optional, monitor specific queues you want to send a heartbeat/monitor to. default is [:app]
138
144
 
139
145
  abort_on_exception:
140
- optional, if you want the resque-stuck-queue threads to explicitly raise, default is false
146
+ optional, if you want the resque-stuck-queue threads to explicitly raise, default is true
141
147
 
142
148
  heartbeat_job:
143
149
  optional, your own custom refreshing job. if you are using something other than resque
144
150
 
145
151
  enable_signals:
146
- optional, allow resque::stuck's signal_handlers which do mostly nothing at this point.
152
+ optional, allow resque::stuck's signal_handlers which do mostly nothing at this point. possible future plan: log info, reopen log file, etc.
147
153
 
148
154
  </pre>
149
155
 
data/THOUGHTS CHANGED
@@ -2,3 +2,6 @@
2
2
 
3
3
  rm redis locking (since it works by keys now, no need for it, recover/trigger ping pong).
4
4
  rm require resque?
5
+
6
+ instead of trigggering once
7
+ add :warn_interval which will just continiously trigger for that interval until a recover hits.
@@ -131,8 +131,37 @@ module Resque
131
131
  @stopped
132
132
  end
133
133
 
134
+ def trigger_handler(queue_name, type)
135
+ raise 'Must trigger either the recovered or triggered handler!' unless (type == :recovered || type == :triggered)
136
+ handler_name = :"#{type}_handler"
137
+ logger.info("Triggering #{type} handler for #{queue_name} at #{Time.now}.")
138
+ (config[handler_name] || const_get(handler_name.upcase)).call(queue_name, lag_time(queue_name))
139
+ manual_refresh(queue_name, type)
140
+ rescue => e
141
+ logger.info("handler #{type} for #{queue_name} crashed: #{e.inspect}")
142
+ logger.info("\n#{e.backtrace.join("\n")}")
143
+ raise e
144
+ end
145
+
146
+ def log_starting_info
147
+ logger.info("Starting StuckQueue with config: #{self.config.inspect}")
148
+ end
149
+
150
+ def log_watcher_info(queue_name)
151
+ logger.info("Lag time for #{queue_name} is #{lag_time(queue_name).inspect} seconds.")
152
+ if triggered_ago = last_triggered(queue_name)
153
+ logger.info("Last triggered for #{queue_name} is #{triggered_ago.inspect} seconds.")
154
+ else
155
+ logger.info("No last trigger found for #{queue_name}.")
156
+ end
157
+ end
158
+
134
159
  private
135
160
 
161
+ def read_from_redis(keyname)
162
+ redis.get(keyname)
163
+ end
164
+
136
165
  def setup_heartbeat_thread
137
166
  @threads << Thread.new do
138
167
  Thread.current.abort_on_exception = abort_on_exception
@@ -240,36 +269,6 @@ module Resque
240
269
  end
241
270
  end
242
271
 
243
- def trigger_handler(queue_name, type)
244
- raise 'Must trigger either the recovered or triggered handler!' unless (type == :recovered || type == :triggered)
245
- handler_name = :"#{type}_handler"
246
- logger.info("Triggering #{type} handler for #{queue_name} at #{Time.now}.")
247
- (config[handler_name] || const_get(handler_name.upcase)).call(queue_name, lag_time(queue_name))
248
- manual_refresh(queue_name, type)
249
- rescue => e
250
- logger.info("handler #{type} for #{queue_name} crashed: #{e.inspect}")
251
- logger.info("\n#{e.backtrace.join("\n")}")
252
- force_stop!
253
- end
254
-
255
- def log_starting_info
256
- logger.info("Starting StuckQueue with config: #{self.config.inspect}")
257
- end
258
-
259
- def log_watcher_info(queue_name)
260
- logger.info("Lag time for #{queue_name} is #{lag_time(queue_name).inspect} seconds.")
261
- if triggered_ago = last_triggered(queue_name)
262
- logger.info("Last triggered for #{queue_name} is #{triggered_ago.inspect} seconds.")
263
- else
264
- logger.info("No last trigger found for #{queue_name}.")
265
- end
266
-
267
- end
268
-
269
- def read_from_redis(keyname)
270
- redis.get(keyname)
271
- end
272
-
273
272
  def wait_for_it(type)
274
273
  if type == :heartbeat_interval
275
274
  sleep config[:heartbeat_interval] || HEARTBEAT_INTERVAL
@@ -31,7 +31,7 @@ module Resque
31
31
  :queues => "optional, monitor specific queues you want to send a heartbeat/monitor to. default is [:app]",
32
32
  :abort_on_exception => "optional, if you want the resque-stuck-queue threads to explicitly raise, default is true",
33
33
  :heartbeat_job => "optional, your own custom refreshing job. if you are using something other than resque",
34
- :enable_signals => "optional, allow resque::stuck's signal_handlers which do mostly nothing at this point.",
34
+ :enable_signals => "optional, allow resque::stuck's signal_handlers which do mostly nothing at this point. possible future plan: log info, reopen log file, etc.",
35
35
  }
36
36
 
37
37
  OPTIONS = OPTIONS_DESCRIPTIONS.keys
@@ -9,13 +9,16 @@ module Resque
9
9
 
10
10
  trap("SIGUSR1") do
11
11
  ENV['SIGUSR1'] = "done be had"
12
+ Resque::StuckQueue.logger.info("Inspecting StuckQueue config: #{Resque::StuckQueue.config.inspect}")
13
+ Resque::StuckQueue.queues.each do |q| Resque::StuckQueue.log_watcher_info(q) end
12
14
  Resque::StuckQueue.logger.info("¯\_(ツ)_/¯ ...")
13
15
  end
14
16
 
15
- trap("SIGUSR2") do
16
- require 'pry'
17
- binding.pry
18
- end
17
+ # do something meaningful
18
+ #trap("SIGUSR2") do
19
+ # require 'pry'
20
+ # binding.pry
21
+ #end
19
22
 
20
23
  end
21
24
  end
@@ -1,5 +1,5 @@
1
1
  module Resque
2
2
  module StuckQueue
3
- VERSION = "0.4.3"
3
+ VERSION = "0.4.4"
4
4
  end
5
5
  end
data/test/test_helper.rb CHANGED
@@ -31,10 +31,17 @@ module TestHelper
31
31
  end
32
32
 
33
33
  def start_and_stop_loops_after(secs)
34
+ abort_or_not = Thread.abort_on_exception
35
+ Thread.abort_on_exception = Resque::StuckQueue.config[:abort_on_exception]
36
+
34
37
  ops = []
35
38
  ops << Thread.new { Resque::StuckQueue.start }
36
39
  ops << Thread.new { sleep secs; Resque::StuckQueue.stop }
37
40
  ops.map(&:join)
41
+
42
+ ensure
43
+ Thread.abort_on_exception = abort_or_not
44
+ Resque::StuckQueue.force_stop!
38
45
  end
39
46
 
40
47
  end
@@ -2,20 +2,15 @@
2
2
  # $ RESQUE_2=1 bi; RESQUE_2=1 be ruby -I. -Ilib/ test/test_resque_2.rb
3
3
  if !ENV['RESQUE_2'].nil?
4
4
 
5
- require 'minitest'
6
- require "minitest/autorun"
7
- require "pry"
8
- require "logger"
9
-
10
- $:.unshift(".")
11
- require "resque_stuck_queue"
12
- require File.join(File.expand_path(File.dirname(__FILE__)), "resque", "set_redis_key")
13
- require File.join(File.expand_path(File.dirname(__FILE__)), "resque", "refresh_latest_timestamp")
5
+ require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper")
14
6
 
15
7
  class TestResque2 < Minitest::Test
16
8
 
9
+ include TestHelper
10
+
17
11
  def setup
18
12
  assert (Resque::VERSION.match /^2\./), "must run in 2.0"
13
+ Resque.redis = Redis.new
19
14
  Resque::StuckQueue.config[:redis] = Redis.new
20
15
  Redis.new.flushall
21
16
  end
@@ -31,6 +26,7 @@ if !ENV['RESQUE_2'].nil?
31
26
  Resque::StuckQueue.config[:logger] = Logger.new($stdout)
32
27
  Resque::StuckQueue.config[:triggered_handler] = proc { Redis.new.incr("test-incr-key") }
33
28
  Resque::StuckQueue.config[:redis] = Redis.new
29
+ Resque::StuckQueue.config[:queues] = [:app]
34
30
 
35
31
  #binding.pry
36
32
  Resque::StuckQueue.start_in_background
@@ -38,11 +34,9 @@ if !ENV['RESQUE_2'].nil?
38
34
  @r2_pid = fork { Resque::StuckQueue.config[:redis] = Redis.new ; Resque::Worker.new("*", :graceful_term => true).work ; Process.waitall }
39
35
  sleep 10
40
36
 
41
- # did not trigger, resque picked up refresh jobs
37
+ # triggers once
42
38
  assert_equal Redis.new.get("test-incr-key").to_i, 0
43
-
44
- `kill #{@r2_pid}`
45
- Process.waitall
39
+ hax_kill_resque
46
40
  Resque::StuckQueue.force_stop!
47
41
  end
48
42
 
@@ -41,14 +41,17 @@ class TestResqueStuckQueue < Minitest::Test
41
41
  def test_stops_if_handler_raises
42
42
  puts "#{__method__}"
43
43
  Resque::StuckQueue.config[:trigger_timeout] = 1 # wait a short time, will trigger
44
+ Resque::StuckQueue.config[:abort_on_exception] = true # bubble up the raise
44
45
  last_time_too_old = Time.now.to_i - Resque::StuckQueue::TRIGGER_TIMEOUT
45
46
  Resque::StuckQueue.config[:triggered_handler] = proc { raise "handler had bad sad!" }
46
- Thread.new {
47
- sleep 3 # should have triggered
48
- Thread.current.abort_on_exception = true
49
- assert Resque::StuckQueue.stopped?, "should stop stuck_queue if handler raises."
50
- }
51
- start_and_stop_loops_after(4)
47
+ begin
48
+ start_and_stop_loops_after(4)
49
+ sleep 4
50
+ assert false, "should raise"
51
+ rescue => e
52
+ puts e.inspect
53
+ assert true, "should raise handler bad sad #{e.inspect}"
54
+ end
52
55
  end
53
56
 
54
57
  end
@@ -0,0 +1,45 @@
1
+ # run with
2
+ # $ RESQUE_2=1 bi; RESQUE_2=1 be ruby -I. -Ilib/ test/test_resque_2.rb
3
+ if !ENV['RESQUE_2'].nil?
4
+
5
+ require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper")
6
+
7
+ class TestResque2 < Minitest::Test
8
+
9
+ include TestHelper
10
+
11
+ def setup
12
+ assert (Resque::VERSION.match /^2\./), "must run in 2.0"
13
+ Resque.redis = Redis.new
14
+ Resque::StuckQueue.config[:redis] = Redis.new
15
+ Redis.new.flushall
16
+ end
17
+
18
+ def test_works_with_2_point_oh_do_not_trigger_because_key_is_updated
19
+
20
+ Resque::StuckQueue.config[:redis] = Redis.new
21
+
22
+ Resque::StuckQueue.config[:watcher_interval] = 1
23
+ Resque::StuckQueue.config[:heartbeat_interval] = 1
24
+ Resque::StuckQueue.config[:abort_on_exception] = true
25
+ Resque::StuckQueue.config[:trigger_timeout] = 5
26
+ Resque::StuckQueue.config[:logger] = Logger.new($stdout)
27
+ Resque::StuckQueue.config[:triggered_handler] = proc { Redis.new.incr("test-incr-key") }
28
+ Resque::StuckQueue.config[:redis] = Redis.new
29
+ Resque::StuckQueue.config[:queues] = [:app]
30
+
31
+ #binding.pry
32
+ Resque::StuckQueue.start_in_background
33
+
34
+ @r2_pid = fork { Resque::StuckQueue.config[:redis] = Redis.new ; Resque::Worker.new("*", :graceful_term => true).work ; Process.waitall }
35
+ sleep 10
36
+
37
+ # triggers once
38
+ assert_equal Redis.new.get("test-incr-key").to_i, 1
39
+ hax_kill_resque
40
+ Resque::StuckQueue.force_stop!
41
+ end
42
+
43
+ end
44
+
45
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: resque_stuck_queue
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.3
4
+ version: 0.4.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shai Rosenfeld
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2014-02-04 00:00:00 Z
12
+ date: 2014-02-12 00:00:00 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: redis-mutex
@@ -81,6 +81,7 @@ files:
81
81
  - test/test_resque_2.rb
82
82
  - test/test_resque_stuck_queue.rb
83
83
  - test/test_set_custom_refresh_job.rb
84
+ - test/test_ver_2.rb
84
85
  homepage: https://github.com/shaiguitar/resque_stuck_queue/
85
86
  licenses:
86
87
  - MIT
@@ -115,3 +116,4 @@ test_files:
115
116
  - test/test_resque_2.rb
116
117
  - test/test_resque_stuck_queue.rb
117
118
  - test/test_set_custom_refresh_job.rb
119
+ - test/test_ver_2.rb