resque_stuck_queue 0.4.3 → 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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