resque_stuck_queue 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ Zjg2N2FjNjcwNjA2MTZiNTQ1NGJjZjQwZmNiZjI5YzcyYjcxZDdmYw==
5
+ data.tar.gz: !binary |-
6
+ ZDAxNGUwYzUxYTg5NmY2N2Q0OGQ0ZTI0MzQ2MzVlNmJiNDJjY2I3OA==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ MWMxODVkOTM5NGJlMGQwZWQ5YWU1YTNjN2Q0NWM1NGUzYmExZjBmZjFkN2Yx
10
+ MjA5MGIzNDliY2YwYzU5NGEwNTY4NmYxMDNhZGY5MWNkYjU0ZGM1MDhjZmNk
11
+ ZGU4YzU1NGM2ZTc5Y2Y0OTIyYWU0NGE0OTQwNmM1ZjdmZTZhZWM=
12
+ data.tar.gz: !binary |-
13
+ M2VmNmZmY2YwMDExNzdlYzZjM2ZhMWUxZTM4NDViNjBjYjc2NmYzOWI1NDkz
14
+ MjRjNmZlNmM1MjA0MGJhYzAzNWUyNWIwMjVhMGVjZTFhNjM4MjkzMDA0NjQx
15
+ Yjg2M2VmZDU3ZWM0MWUyODFlNTI1YWVmOWQ4NjlhNzNmM2Y0NWU=
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ *gem
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'resque'
4
+
5
+ # TEST
6
+ gem 'minitest'
7
+ gem 'mocha'
8
+ gem 'resque-mock'
9
+ gem 'pry'
10
+ gem 'rake'
11
+ gem 'm'
12
+ gem 'resque-scheduler'
data/Gemfile.lock ADDED
@@ -0,0 +1,61 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ coderay (1.1.0)
5
+ m (1.3.2)
6
+ method_source (>= 0.6.7)
7
+ rake (>= 0.9.2.2)
8
+ metaclass (0.0.1)
9
+ method_source (0.8.2)
10
+ minitest (5.2.0)
11
+ mocha (0.14.0)
12
+ metaclass (~> 0.0.1)
13
+ mono_logger (1.1.0)
14
+ multi_json (1.8.2)
15
+ pry (0.9.12.4)
16
+ coderay (~> 1.0)
17
+ method_source (~> 0.8)
18
+ slop (~> 3.4)
19
+ rack (1.5.2)
20
+ rack-protection (1.5.1)
21
+ rack
22
+ rake (10.1.0)
23
+ redis (3.0.6)
24
+ redis-namespace (1.4.1)
25
+ redis (~> 3.0.4)
26
+ resque (1.25.1)
27
+ mono_logger (~> 1.0)
28
+ multi_json (~> 1.0)
29
+ redis-namespace (~> 1.2)
30
+ sinatra (>= 0.9.2)
31
+ vegas (~> 0.1.2)
32
+ resque-mock (0.1.1)
33
+ resque
34
+ resque-scheduler (2.0.1)
35
+ redis (>= 2.0.1)
36
+ resque (>= 1.20.0)
37
+ rufus-scheduler
38
+ rufus-scheduler (2.0.19)
39
+ tzinfo (>= 0.3.23)
40
+ sinatra (1.4.4)
41
+ rack (~> 1.4)
42
+ rack-protection (~> 1.4)
43
+ tilt (~> 1.3, >= 1.3.4)
44
+ slop (3.4.7)
45
+ tilt (1.4.1)
46
+ tzinfo (0.3.38)
47
+ vegas (0.1.11)
48
+ rack (>= 1.0.0)
49
+
50
+ PLATFORMS
51
+ ruby
52
+
53
+ DEPENDENCIES
54
+ m
55
+ minitest
56
+ mocha
57
+ pry
58
+ rake
59
+ resque
60
+ resque-mock
61
+ resque-scheduler
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Shai Rosenfeld
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,61 @@
1
+ ## Resque stuck queue
2
+
3
+ Ever run into that? Sucks, eh?
4
+
5
+ This should enable a way to fire some handler when jobs aren't occurring within a certain timeframe.
6
+
7
+ ## How it works
8
+
9
+ When you call `start` you are essentially starting two threads that will continiously run until `stop` is called or until the process shuts down.
10
+
11
+ 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.
12
+
13
+ The other thread is a continious loop that will check redis (bypassing resque) for that key and check what the latest time the hearbeat job successfully updated that key.
14
+
15
+ It will trigger a pre-defined proc (see below) if the last time the hearbeat job updated that key is older than the trigger_timeout setting (see below).
16
+
17
+ ## Usage
18
+
19
+ Add this to wherever you're setting up resque (config/initializers or wherever).
20
+
21
+ Configure it first:
22
+
23
+ <pre>
24
+ # how often to push that 'heartbeat' job to refresh the latest time it worked.
25
+ Resque::StuckQueue.config[:heartbeat] = 5.minutes
26
+
27
+ # since there is an realistic and acceptable lag for job queues, set this to how much you're
28
+ # willing to accept between the current time and when the last hearbeat job went through.
29
+ #
30
+ # obviously, take the heartbeat into consideration when setting this
31
+ Resque::StuckQueue.config[:trigger_timeout] = 10.hours
32
+
33
+ # what gets triggered when resque-stuck-queue will detect the latest heartbeat is older than the trigger_timeout time set above.
34
+ Resque::StuckQueue.config[:handler] = proc { send_email }
35
+
36
+ # optional, in case you want to set your own name for the key that will be used as the last good hearbeat time
37
+ Resque::StuckQueue.config[:global_key] = "name-the-refresh-key-as-you-please"
38
+
39
+ # optional, if you want the resque-stuck-queue threads to explicitly raise, default is false
40
+ Resque::StuckQueue.config[:abort_on_exception] = true
41
+ </pre>
42
+
43
+ Then start it:
44
+
45
+ <pre>
46
+ Resque::StuckQueue.start # blocking
47
+ Resque::StuckQueue.start_in_background # sugar for Thread.new { Resque::StuckQueue.start }
48
+ </pre>
49
+
50
+ Stopping it consists of the same idea:
51
+
52
+ <pre>
53
+ Resque::StuckQueue.stop # this will block until the threads end their current iteration
54
+ Resque::StuckQueue.force_stop! # force kill those threads and let's move on
55
+ </pre>
56
+
57
+ ## Tests
58
+
59
+ Run the tests:
60
+
61
+ `bundle; bundle exec rake`
data/Rakefile ADDED
@@ -0,0 +1,18 @@
1
+ require 'rake/testtask'
2
+
3
+ task :default => :test
4
+ Rake::TestTask.new do |t|
5
+ t.pattern = "test/test_*rb"
6
+ end
7
+
8
+ require 'resque/tasks'
9
+
10
+ task :'resque:setup' do
11
+ # https://github.com/resque/resque/issues/773
12
+ # have the jobs loaded in memory
13
+ Dir["./test/resque/*.rb"].each {|file| require file}
14
+ end
15
+
16
+ require 'resque_scheduler/tasks'
17
+ task "resque:scheduler_setup"
18
+
data/THOUGHTS ADDED
@@ -0,0 +1,21 @@
1
+ other resources:
2
+
3
+ http://vitobotta.com/resque-automatically-kill-stuck-workers-retry-failed-jobs/#sthash.oQsaNeb5.dpbs
4
+ http://stackoverflow.com/questions/10757758/find-out-if-a-resque-job-is-still-running-and-kill-it-if-its-stuck
5
+
6
+ heartbeat?
7
+
8
+ redis scenario
9
+ different processes (cant share state in Resque memory etc.)
10
+ different boxes! (redis is shared state)
11
+ if this is included in servers, you have clusters os unicorn/mongrel etc,
12
+ ensure it works across multiple running instances of this lib?
13
+
14
+ Thing.setup_checker_thread
15
+ Thing.enqueue_repeating_refresh_job
16
+
17
+ reproduce the error and integrate test like that
18
+
19
+ ## TODOS
20
+
21
+ verify @config options, raise if no handler, etc.
@@ -0,0 +1,5 @@
1
+ module Resque
2
+ module StuckQueue
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,157 @@
1
+ require "resque_stuck_queue/version"
2
+
3
+ # TODO move this require into a configurable?
4
+ require 'resque'
5
+
6
+ module Resque
7
+ module StuckQueue
8
+
9
+ GLOBAL_KEY = "resque-stuck-queue"
10
+ VERIFIED_KEY = "resque-stuck-queue-ran-once"
11
+ HEARTBEAT = 60 * 60 # check/refresh every hour
12
+ TRIGGER_TIMEOUT = 5 * 60 * 60 # warn/trigger 5 hours
13
+ HANDLER = proc { $stderr.puts("Shit gone bad with them queues.") }
14
+
15
+ class << self
16
+
17
+ attr_accessor :config
18
+
19
+ # # how often we refresh the key
20
+ # :heartbeat = 5 * 60
21
+ #
22
+ # # this could just be :heartbeat but it's possible there's an acceptable lag/bottleneck
23
+ # # in the queue that we want to allow to be before we think it's bad.
24
+ # :trigger_timeout = 10 * 60
25
+ #
26
+ # # The global key that will be used to check the latest time
27
+ # :global_key = "resque-stuck-queue"
28
+ #
29
+ # # for threads involved here. default is false
30
+ # :abort_on_exception
31
+ #
32
+ # # default handler
33
+ # config[:handler] = proc { send_mail }
34
+ def config
35
+ @config ||= {}
36
+ end
37
+
38
+ def start_in_background
39
+ Thread.new do
40
+ self.start
41
+ end
42
+ end
43
+
44
+ def stop_in_background
45
+ Thread.new do
46
+ self.start
47
+ end
48
+ end
49
+
50
+ # call this after setting config. once started you should't be allowed to modify it
51
+ def start
52
+ @running = true
53
+ @stopped = false
54
+ @threads = []
55
+ config.freeze
56
+
57
+ mark_first_use
58
+
59
+ Thread.abort_on_exception = config[:abort_on_exception]
60
+
61
+ enqueue_repeating_refresh_job
62
+ setup_checker_thread
63
+
64
+ # fo-eva.
65
+ @threads.map(&:join)
66
+
67
+ @stopped = true
68
+ end
69
+
70
+ # for tests
71
+ def stop
72
+ @config = config.dup #unfreeze
73
+ @running = false
74
+
75
+ # wait for clean thread shutdown
76
+ while @stopped == false
77
+ sleep 1
78
+ end
79
+ end
80
+
81
+ def force_stop!
82
+ @threads.map(&:kill)
83
+ end
84
+
85
+ private
86
+
87
+ def enqueue_repeating_refresh_job
88
+ @threads << Thread.new do
89
+ while @running
90
+ wait_for_it
91
+ # we want to go through resque jobs, because that's what we're trying to test here:
92
+ # ensure that jobs get executed and the time is updated!
93
+ #
94
+ # TODO REDIS 2.0 compat
95
+ Resque.enqueue(RefreshLatestTimestamp, global_key)
96
+ end
97
+ end
98
+ end
99
+
100
+ def setup_checker_thread
101
+ @threads << Thread.new do
102
+ while @running
103
+ wait_for_it
104
+ if Time.now.to_i - last_time_worked > max_wait_time
105
+ trigger_handler
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ def last_time_worked
112
+ time_set = read_from_redis
113
+ if has_been_used? && time_set.nil?
114
+ # if the first job ran, the redis key should always be set
115
+ # possible cases are (1) redis data wonky (2) resque jobs don't get run
116
+ trigger_handler
117
+ end
118
+ (time_set ? time_set : Time.now).to_i # don't trigger again if time is nil
119
+ end
120
+
121
+ def trigger_handler
122
+ (config[:handler] || HANDLER).call
123
+ end
124
+
125
+ def read_from_redis
126
+ Resque.redis.get(global_key)
127
+ end
128
+
129
+ def has_been_used?
130
+ Resque.redis.get(VERIFIED_KEY)
131
+ end
132
+
133
+ def mark_first_use
134
+ Resque.redis.set(VERIFIED_KEY, "true")
135
+ end
136
+
137
+ def wait_for_it
138
+ sleep config[:heartbeat] || HEARTBEAT
139
+ end
140
+
141
+ def global_key
142
+ config[:global_key] || GLOBAL_KEY
143
+ end
144
+
145
+ def max_wait_time
146
+ config[:trigger_timeout] || TRIGGER_TIMEOUT
147
+ end
148
+ end
149
+ end
150
+ end
151
+
152
+ class RefreshLatestTimestamp
153
+ @queue = :app
154
+ def self.perform(timestamp_key)
155
+ Resque.redis.set(timestamp_key, Time.now.to_i)
156
+ end
157
+ end
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'resque_stuck_queue/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "resque_stuck_queue"
8
+ spec.version = Resque::StuckQueue::VERSION
9
+ spec.authors = ["Shai Rosenfeld"]
10
+ spec.email = ["srosenfeld@engineyard.com"]
11
+ spec.summary = %q{fire a handler when your queues are wonky}
12
+ spec.description = %q{where the wild things are. err, when resque gets stuck}
13
+ spec.homepage = "https://github.com/shaiguitar/resque_stuck_queue/"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.5"
22
+ spec.add_development_dependency "rake"
23
+ end
@@ -0,0 +1,6 @@
1
+ class RefreshLatestTimestamp
2
+ @queue = :app
3
+ def self.perform(timestamp_key)
4
+ Resque.redis.set(timestamp_key, Time.now.to_i)
5
+ end
6
+ end
@@ -0,0 +1,8 @@
1
+ # fixture job
2
+ class SetRedisKey
3
+ NAME = "integration_test"
4
+ @queue = :app
5
+ def self.perform
6
+ Resque.redis.set(NAME, "1")
7
+ end
8
+ end
@@ -0,0 +1,83 @@
1
+ require 'minitest'
2
+ require "minitest/autorun"
3
+ require 'pry'
4
+
5
+ $:.unshift(".")
6
+ require 'resque_stuck_queue'
7
+ require File.join(File.expand_path(File.dirname(__FILE__)), "resque", "set_redis_key")
8
+ require File.join(File.expand_path(File.dirname(__FILE__)), "resque", "refresh_latest_timestamp")
9
+
10
+ class TestIntegration < Minitest::Test
11
+
12
+ # TODODS there's a better way to do this.
13
+ #
14
+ #
15
+ # run test with VVERBOSE=1 DEBUG=1 for more output
16
+ #
17
+ #
18
+ # => sleeping suckc
19
+ # => resque sleeps 5 between checking enqueed jobs, can be configurable?
20
+ #
21
+ # cleanup processes correctly?
22
+ # ps aux |grep resqu |awk '{print $2}' | xargs kill
23
+
24
+ def setup
25
+ end
26
+
27
+ def teardown
28
+ Process.kill("SIGQUIT", @resque_pid)
29
+ Resque::StuckQueue.stop
30
+ Process.waitpid(@resque_pid)
31
+ end
32
+
33
+ def run_resque
34
+ pid = fork { exec("QUEUE=* bundle exec rake --trace resque:work") }
35
+ sleep 3 # wait for resque to boot up
36
+ pid
37
+ end
38
+
39
+ def test_resque_enqueues_a_job_does_not_trigger
40
+
41
+ puts '1'
42
+ Resque::StuckQueue.config[:trigger_timeout] = 100 # wait a while so we don't trigger
43
+ Resque::StuckQueue.config[:heartbeat] = 2
44
+ @triggered = false
45
+ Resque::StuckQueue.config[:handler] = proc { @triggered = true }
46
+ Thread.new { Resque::StuckQueue.start }
47
+
48
+ # job gets enqueued successfully
49
+ @resque_pid = run_resque
50
+ Resque.redis.del(SetRedisKey::NAME)
51
+ Resque.enqueue(SetRedisKey)
52
+ sleep 6 # let resque pick up the job
53
+ assert_equal Resque.redis.get(SetRedisKey::NAME), "1"
54
+
55
+ # check handler did not get called
56
+ assert_equal @triggered, false
57
+ end
58
+
59
+ def test_resque_does_not_enqueues_a_job_does_trigger
60
+
61
+ puts '2'
62
+ Resque::StuckQueue.config[:trigger_timeout] = 2 # won't allow waiting too much and will complain (eg trigger) sooner than later
63
+ Resque::StuckQueue.config[:heartbeat] = 1
64
+ @triggered = false
65
+ Resque::StuckQueue.config[:handler] = proc { @triggered = true }
66
+ Thread.new { Resque::StuckQueue.start }
67
+
68
+ # job gets enqueued successfully
69
+ @resque_pid = run_resque
70
+ Resque.redis.del(SetRedisKey::NAME)
71
+ Process.kill("SIGSTOP", @resque_pid) # jic, do not process jobs so we definitely trigger
72
+ Resque.enqueue(SetRedisKey)
73
+ assert_equal Resque.redis.get(SetRedisKey::NAME), nil
74
+
75
+ # check handler did get called
76
+ assert_equal @triggered, true
77
+
78
+ # unstick the process so we can kill it in teardown
79
+ Process.kill("SIGCONT", @resque_pid)
80
+ end
81
+
82
+
83
+ end
@@ -0,0 +1,105 @@
1
+ require 'minitest'
2
+ require "minitest/autorun"
3
+ require 'mocha'
4
+
5
+ require 'resque/mock'
6
+
7
+ $:.unshift(".")
8
+ require 'resque_stuck_queue'
9
+
10
+ class TestResqueStuckQueue < Minitest::Test
11
+
12
+ def teardown
13
+ puts 'teardown'
14
+ Resque::StuckQueue.unstub(:has_been_used?)
15
+ Resque::StuckQueue.unstub(:read_from_redis)
16
+ end
17
+
18
+ def setup
19
+ puts 'setup'
20
+ # clean previous test runs
21
+ Resque.redis.flushall
22
+ Resque.mock!
23
+ Resque::StuckQueue.config[:heartbeat] = 1 # seconds
24
+ Resque::StuckQueue.config[:trigger_timeout] = 2
25
+ Resque::StuckQueue.config[:abort_on_exception] = true
26
+ end
27
+
28
+ # usually the key will be set from previous runs since it will persist (redis) between deploys etc.
29
+ # so you shouldn't be running into this scenario (nil key) other than
30
+ # 0) test setup clearing out this key
31
+ # 1) the VERY first time you use this lib when it first gets set.
32
+ # 2) redis gets wiped out
33
+ # 3) resque jobs never get run!
34
+ # this has the unfortunate meaning that if no jobs are *ever* enqueued, this lib won't catch that problem.
35
+ # so we split the funcationaliy to raise if no key is there, unless it's the first time it's being used since being started.
36
+ def test_thread_does_not_trigger_when_no_key_exists_on_first_use
37
+ puts '1'
38
+
39
+ # lib never ran, and key is not there
40
+ Resque::StuckQueue.stubs(:has_been_used?).returns(nil)
41
+ Resque::StuckQueue.stubs(:read_from_redis).returns(nil)
42
+ @triggered = false
43
+ Resque::StuckQueue.config[:handler] = proc { @triggered = true }
44
+ start_and_stop_loops_after(2)
45
+ assert_equal false, @triggered # "handler should not be called"
46
+ end
47
+
48
+ def test_thread_does_trigger_when_no_key_exists_on_any_other_use
49
+
50
+ puts '2'
51
+ # lib already ran, but key is not there
52
+ Resque::StuckQueue.stubs(:has_been_used?).returns(true)
53
+ Resque::StuckQueue.stubs(:read_from_redis).returns(nil)
54
+
55
+ @triggered = false
56
+ Resque::StuckQueue.config[:handler] = proc { @triggered = true }
57
+ start_and_stop_loops_after(2)
58
+ assert_equal true, @triggered # "handler should be called"
59
+ end
60
+
61
+ def test_configure_global_key
62
+ puts '3'
63
+ assert_nil Resque.redis.get("it-is-configurable"), "global key should not be set"
64
+ Resque::StuckQueue.config[:global_key] = "it-is-configurable"
65
+ start_and_stop_loops_after(2)
66
+ refute_nil Resque.redis.get("it-is-configurable"), "global key should be set"
67
+ end
68
+
69
+ def test_it_sets_a_verified_key_to_indicate_first_use
70
+ puts '4'
71
+ assert_nil Resque.redis.get(Resque::StuckQueue::VERIFIED_KEY), "should be nil before lib is used"
72
+ start_and_stop_loops_after(2)
73
+ refute_nil Resque.redis.get(Resque::StuckQueue::VERIFIED_KEY), "should set verified key after used"
74
+ end
75
+
76
+ def test_it_does_not_trigger_handler_if_under_max_time
77
+ puts '5'
78
+ Resque::StuckQueue.stubs(:read_from_redis).returns(Time.now.to_i)
79
+ @triggered = false
80
+ Resque::StuckQueue.config[:handler] = proc { @triggered = true }
81
+ start_and_stop_loops_after(2)
82
+ assert_equal false, @triggered # "handler should not be called"
83
+ end
84
+
85
+ def test_it_triggers_handler_if_over_trigger_timeout
86
+ puts '6'
87
+ last_time_too_old = Time.now.to_i - Resque::StuckQueue::TRIGGER_TIMEOUT
88
+ Resque::StuckQueue.stubs(:read_from_redis).returns(last_time_too_old.to_s)
89
+ @triggered = false
90
+ Resque::StuckQueue.config[:handler] = proc { @triggered = true }
91
+ start_and_stop_loops_after(2)
92
+ assert_equal true, @triggered # "handler should be called"
93
+ end
94
+
95
+ private
96
+
97
+ def start_and_stop_loops_after(secs)
98
+ ops = []
99
+ ops << Thread.new { Resque::StuckQueue.start }
100
+ ops << Thread.new { sleep secs; Resque::StuckQueue.stop }
101
+ ops.map(&:join)
102
+ end
103
+
104
+ end
105
+
metadata ADDED
@@ -0,0 +1,91 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: resque_stuck_queue
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Shai Rosenfeld
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-01-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.5'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: where the wild things are. err, when resque gets stuck
42
+ email:
43
+ - srosenfeld@engineyard.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - .gitignore
49
+ - Gemfile
50
+ - Gemfile.lock
51
+ - LICENSE.txt
52
+ - README.md
53
+ - Rakefile
54
+ - THOUGHTS
55
+ - lib/resque_stuck_queue.rb
56
+ - lib/resque_stuck_queue/version.rb
57
+ - resque_stuck_queue.gemspec
58
+ - test/resque/refresh_latest_timestamp.rb
59
+ - test/resque/set_redis_key.rb
60
+ - test/test_integration.rb
61
+ - test/test_resque_stuck_queue.rb
62
+ homepage: https://github.com/shaiguitar/resque_stuck_queue/
63
+ licenses:
64
+ - MIT
65
+ metadata: {}
66
+ post_install_message:
67
+ rdoc_options: []
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ! '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ! '>='
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ requirements: []
81
+ rubyforge_project:
82
+ rubygems_version: 2.0.3
83
+ signing_key:
84
+ specification_version: 4
85
+ summary: fire a handler when your queues are wonky
86
+ test_files:
87
+ - test/resque/refresh_latest_timestamp.rb
88
+ - test/resque/set_redis_key.rb
89
+ - test/test_integration.rb
90
+ - test/test_resque_stuck_queue.rb
91
+ has_rdoc: