resque_stuck_queue 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/README.md +14 -2
- data/THOUGHTS +2 -1
- data/lib/resque_stuck_queue.rb +23 -5
- data/lib/resque_stuck_queue/version.rb +1 -1
- data/test/test_logger.rb +30 -0
- metadata +3 -1
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
Y2RiMWFkM2ZmMGJmOWI1YzcwYzg5MWUyNjU3MTEzNWQwYmZiOWQ1YQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
NjQ2ODNlOTNmMDMzZWU1MDU2NWE1NTc4YmQ1NzAwOGFlYzNlOTU5Nw==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
Mzc4ZTI4NjM2ZjlhY2ExNDM3NDhmMjU1NTA0ODE2Y2I3MzkwYzMxNDE3NTNk
|
10
|
+
YThjNjQ2ZDhkZjY5Nzk2YzAwMWZhZjgxOWNjMThiYzFhNGJlZWVjZjMzY2Rj
|
11
|
+
ZTZjZThlOGQyMzMwMzFlZmE1NTFmNDE4NzY4NmQ3ZTU1MDAwNDI=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
YzIzYWMxYWVkZGRiYjdhY2Y3ZDNlYzQ1NzcyYzQ2ZTcxZjM1NTE5NDgyMDU1
|
14
|
+
OTFkMmZjNWM5NjJiZmNkM2MyNDIyMWY5Y2Q4NTk4MDZkMTViMDY2ZDlhNDgz
|
15
|
+
NjQ0NGJiNzEwNDIyN2Y4NTJjZTYwODI0ZTRiYjgwYWM5OGI1MGU=
|
data/README.md
CHANGED
@@ -16,8 +16,6 @@ It will trigger a pre-defined proc (see below) if the last time the hearbeat job
|
|
16
16
|
|
17
17
|
## Usage
|
18
18
|
|
19
|
-
Add this to wherever you're setting up resque (config/initializers or wherever).
|
20
|
-
|
21
19
|
Configure it first:
|
22
20
|
|
23
21
|
<pre>
|
@@ -41,6 +39,10 @@ Resque::StuckQueue.config[:global_key] = "name-the-refresh-key-as-you-please"
|
|
41
39
|
|
42
40
|
# optional, if you want the resque-stuck-queue threads to explicitly raise, default is false
|
43
41
|
Resque::StuckQueue.config[:abort_on_exception] = true
|
42
|
+
|
43
|
+
# optional, pass a logger. Default a ruby logger will be instantiated. Needs to respond to that interface.
|
44
|
+
Resque::StuckQueue.config[:logger] = Logger.new($stdout)
|
45
|
+
|
44
46
|
</pre>
|
45
47
|
|
46
48
|
Then start it:
|
@@ -57,6 +59,16 @@ Resque::StuckQueue.stop # this will block until the threads end
|
|
57
59
|
Resque::StuckQueue.force_stop! # force kill those threads and let's move on
|
58
60
|
</pre>
|
59
61
|
|
62
|
+
## Deployment/Integration
|
63
|
+
|
64
|
+
* Include this in the app in a config initializer of some sort.
|
65
|
+
|
66
|
+
Note though, the resque-stuck threads will live alongside the app server process so you will need to explicitely handle `start` _and_ `stop`. If you're deployed in a forking-server environment and the whatever process has this does not get restarted the threads will keep on going indefinitely.
|
67
|
+
|
68
|
+
* Run this as a daemon somewhere alongside the app/in your setup.
|
69
|
+
|
70
|
+
<!-- TODO example -->
|
71
|
+
|
60
72
|
## Tests
|
61
73
|
|
62
74
|
Run the tests:
|
data/THOUGHTS
CHANGED
@@ -28,4 +28,5 @@ verify @config options, raise if no handler, etc.
|
|
28
28
|
- ensure it only runs from the server box and not the resque box??
|
29
29
|
(the deploy restarts the server but not resque workers)
|
30
30
|
|
31
|
-
|
31
|
+
add a 'resque_stuck_queue/tasks' bit? See tres eg
|
32
|
+
require 'resque/stuck_queue' instead?
|
data/lib/resque_stuck_queue.rb
CHANGED
@@ -7,13 +7,15 @@ Redis::Classy.db = Resque.redis
|
|
7
7
|
# TODO move this require into a configurable?
|
8
8
|
require 'resque'
|
9
9
|
|
10
|
+
require 'logger'
|
11
|
+
|
10
12
|
module Resque
|
11
13
|
module StuckQueue
|
12
14
|
|
13
15
|
GLOBAL_KEY = "resque-stuck-queue"
|
14
16
|
HEARTBEAT = 60 * 60 # check/refresh every hour
|
15
17
|
TRIGGER_TIMEOUT = 5 * 60 * 60 # warn/trigger 5 hours
|
16
|
-
HANDLER = proc { $
|
18
|
+
HANDLER = proc { $stdout.puts("Shit gone bad with them queues.") }
|
17
19
|
|
18
20
|
class << self
|
19
21
|
|
@@ -38,6 +40,10 @@ module Resque
|
|
38
40
|
@config ||= {}
|
39
41
|
end
|
40
42
|
|
43
|
+
def logger
|
44
|
+
@logger ||= (config[:logger] || Logger.new($stdout))
|
45
|
+
end
|
46
|
+
|
41
47
|
def start_in_background
|
42
48
|
Thread.new do
|
43
49
|
self.start
|
@@ -65,34 +71,44 @@ module Resque
|
|
65
71
|
# fo-eva.
|
66
72
|
@threads.map(&:join)
|
67
73
|
|
74
|
+
logger.info("threads stopped")
|
68
75
|
@stopped = true
|
69
76
|
end
|
70
77
|
|
71
|
-
# for tests
|
72
78
|
def stop
|
73
|
-
|
74
|
-
@running = false
|
75
|
-
|
79
|
+
reset!
|
76
80
|
# wait for clean thread shutdown
|
77
81
|
while @stopped == false
|
78
82
|
sleep 1
|
79
83
|
end
|
84
|
+
logger.info("Stopped")
|
80
85
|
end
|
81
86
|
|
82
87
|
def force_stop!
|
83
88
|
@threads.map(&:kill)
|
89
|
+
reset!
|
90
|
+
logger.info("Force stopped")
|
91
|
+
end
|
92
|
+
|
93
|
+
def reset!
|
94
|
+
# clean state so we can stop and start in the same process.
|
95
|
+
@config = config.dup #unfreeze
|
96
|
+
@logger = nil
|
97
|
+
@running = false
|
84
98
|
end
|
85
99
|
|
86
100
|
private
|
87
101
|
|
88
102
|
def enqueue_repeating_refresh_job
|
89
103
|
@threads << Thread.new do
|
104
|
+
logger.info("Starting heartbeat thread")
|
90
105
|
while @running
|
91
106
|
wait_for_it
|
92
107
|
# we want to go through resque jobs, because that's what we're trying to test here:
|
93
108
|
# ensure that jobs get executed and the time is updated!
|
94
109
|
#
|
95
110
|
# TODO REDIS 2.0 compat
|
111
|
+
logger.info("Sending refresh job")
|
96
112
|
Resque.enqueue(RefreshLatestTimestamp, global_key)
|
97
113
|
end
|
98
114
|
end
|
@@ -100,12 +116,14 @@ module Resque
|
|
100
116
|
|
101
117
|
def setup_checker_thread
|
102
118
|
@threads << Thread.new do
|
119
|
+
logger.info("Starting checker thread")
|
103
120
|
while @running
|
104
121
|
wait_for_it
|
105
122
|
mutex = Redis::Mutex.new('resque_stuck_queue_lock', block: 0)
|
106
123
|
if mutex.lock
|
107
124
|
begin
|
108
125
|
if Time.now.to_i - last_time_worked > max_wait_time
|
126
|
+
logger.info("Triggering handler at #{Time.now} (pid: #{Process.pid})")
|
109
127
|
trigger_handler
|
110
128
|
end
|
111
129
|
ensure
|
data/test/test_logger.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper")
|
2
|
+
|
3
|
+
class TestResqueStuckQueue < Minitest::Test
|
4
|
+
|
5
|
+
include TestHelper
|
6
|
+
|
7
|
+
def setup
|
8
|
+
Resque::StuckQueue.config[:trigger_timeout] = 1
|
9
|
+
Resque::StuckQueue.config[:heartbeat] = 1
|
10
|
+
Resque::StuckQueue.config[:abort_on_exception] = true
|
11
|
+
end
|
12
|
+
|
13
|
+
def teardown
|
14
|
+
Resque::StuckQueue.reset!
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_has_logger
|
18
|
+
puts "#{__method__}"
|
19
|
+
begin
|
20
|
+
Resque::StuckQueue.config[:logger] = Logger.new($stdout)
|
21
|
+
start_and_stop_loops_after(2)
|
22
|
+
assert true, "should not have raised"
|
23
|
+
rescue
|
24
|
+
assert false, "should have succeeded with good logger"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
|
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.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shai Rosenfeld
|
@@ -74,6 +74,7 @@ files:
|
|
74
74
|
- test/test_collision.rb
|
75
75
|
- test/test_helper.rb
|
76
76
|
- test/test_integration.rb
|
77
|
+
- test/test_logger.rb
|
77
78
|
- test/test_resque_stuck_queue.rb
|
78
79
|
homepage: https://github.com/shaiguitar/resque_stuck_queue/
|
79
80
|
licenses:
|
@@ -105,5 +106,6 @@ test_files:
|
|
105
106
|
- test/test_collision.rb
|
106
107
|
- test/test_helper.rb
|
107
108
|
- test/test_integration.rb
|
109
|
+
- test/test_logger.rb
|
108
110
|
- test/test_resque_stuck_queue.rb
|
109
111
|
has_rdoc:
|