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 +4 -4
- data/README.md +11 -5
- data/THOUGHTS +3 -0
- data/lib/resque_stuck_queue.rb +29 -30
- data/lib/resque_stuck_queue/config.rb +1 -1
- data/lib/resque_stuck_queue/signals.rb +7 -4
- data/lib/resque_stuck_queue/version.rb +1 -1
- data/test/test_helper.rb +7 -0
- data/test/test_resque_2.rb +7 -13
- data/test/test_resque_stuck_queue.rb +9 -6
- data/test/test_ver_2.rb +45 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b23678d316199cc108bef89177912ff5eb396d89
|
4
|
+
data.tar.gz: 055f4654e2f966a573fd398f2f55cbc56b21b766
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
+

|
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]
|
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]
|
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
|
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
data/lib/resque_stuck_queue.rb
CHANGED
@@ -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
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
17
|
+
# do something meaningful
|
18
|
+
#trap("SIGUSR2") do
|
19
|
+
# require 'pry'
|
20
|
+
# binding.pry
|
21
|
+
#end
|
19
22
|
|
20
23
|
end
|
21
24
|
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
|
data/test/test_resque_2.rb
CHANGED
@@ -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
|
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
|
-
#
|
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
|
-
|
47
|
-
|
48
|
-
|
49
|
-
assert
|
50
|
-
|
51
|
-
|
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
|
data/test/test_ver_2.rb
ADDED
@@ -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.
|
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-
|
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
|