resque-lock-timeout 0.3.3 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY.md +7 -3
- data/README.md +26 -2
- data/lib/resque/plugins/lock_timeout.rb +113 -26
- data/test/lock_test.rb +38 -1
- data/test/redis-test.conf +8 -8
- data/test/test_helper.rb +20 -17
- data/test/test_jobs.rb +34 -1
- metadata +53 -18
data/HISTORY.md
CHANGED
@@ -1,7 +1,11 @@
|
|
1
|
+
## 0.4.0 (2012-11-09)
|
2
|
+
|
3
|
+
* Add `@loner` boolean option to prevent job being enqueued if already
|
4
|
+
running/enqueued. (Thanks to @ssaunier)
|
5
|
+
|
1
6
|
## 0.3.3 (2012-03-09)
|
2
|
-
## 0.3.2 (2012-03-09)
|
3
7
|
|
4
|
-
*
|
8
|
+
* Tested against v1.20.0 of resque.
|
5
9
|
|
6
10
|
## 0.3.1 (2011-07-16)
|
7
11
|
|
@@ -23,4 +27,4 @@
|
|
23
27
|
## 0.2.0 (2010-05-05)
|
24
28
|
|
25
29
|
* Initial release as `resque-lock-timeout`, forked from Chris Wanstrath'
|
26
|
-
`resque-lock`.
|
30
|
+
`resque-lock`.
|
data/README.md
CHANGED
@@ -6,7 +6,7 @@ A [Resque][rq] plugin. Requires Resque >= v1.8.0.
|
|
6
6
|
resque-lock-timeout adds locking, with optional timeout/deadlock handling to
|
7
7
|
resque jobs.
|
8
8
|
|
9
|
-
Using a `lock_timeout` allows you to re-
|
9
|
+
Using a `lock_timeout` allows you to re-acquire the lock should your worker
|
10
10
|
fail, crash, or is otherwise unable to relase the lock. **i.e.** Your server
|
11
11
|
unexpectedly looses power. Very handy for jobs that are recurring or may be
|
12
12
|
retried.
|
@@ -37,7 +37,23 @@ Default behaviour...
|
|
37
37
|
|
38
38
|
Please see below for more information about the identifer/lock key.
|
39
39
|
|
40
|
-
###
|
40
|
+
### Enqueued Exclusivity (Loner Option)
|
41
|
+
|
42
|
+
Setting the `@loner` boolean to `true` will ensure the job is not enqueued if
|
43
|
+
the job (identified by the `identifier` method) is already running/enqueued.
|
44
|
+
|
45
|
+
class LonelyJob
|
46
|
+
extend Resque::Plugins::LockTimeout
|
47
|
+
@queue = :loners
|
48
|
+
|
49
|
+
@loner = true
|
50
|
+
|
51
|
+
def self.perform(repo_id)
|
52
|
+
heavy_lifting
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
### Lock Expiry/Timeout
|
41
57
|
|
42
58
|
The locking algorithm used can be found in the [Redis SETNX][redis-setnx]
|
43
59
|
documentation.
|
@@ -158,11 +174,19 @@ Several callbacks are available to override and implement your own logic, e.g.
|
|
158
174
|
# Lock may be held for upto an hour.
|
159
175
|
@lock_timeout = 3600
|
160
176
|
|
177
|
+
# No same job get enqueued if one already running/enqueued
|
178
|
+
@loner = true
|
179
|
+
|
161
180
|
# Job failed to acquire lock. You may implement retry or other logic.
|
162
181
|
def self.lock_failed(repo_id)
|
163
182
|
raise LockFailed
|
164
183
|
end
|
165
184
|
|
185
|
+
# Unable to enqueue job because its running or already enqueued.
|
186
|
+
def self.loner_enqueue_failed(repo_id)
|
187
|
+
raise EnqueueFailed
|
188
|
+
end
|
189
|
+
|
166
190
|
# Job has complete; but the lock expired before we could relase it.
|
167
191
|
# The lock wasn't released; as its *possible* the lock is now held
|
168
192
|
# by another job.
|
@@ -3,32 +3,51 @@ module Resque
|
|
3
3
|
# If you want only one instance of your job running at a time,
|
4
4
|
# extend it with this module:
|
5
5
|
#
|
6
|
-
#
|
6
|
+
# require 'resque-lock-timeout'
|
7
7
|
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
8
|
+
# class UpdateNetworkGraph
|
9
|
+
# extend Resque::Plugins::LockTimeout
|
10
|
+
# @queue = :network_graph
|
11
11
|
#
|
12
|
-
#
|
13
|
-
#
|
12
|
+
# def self.perform(repo_id)
|
13
|
+
# heavy_lifting
|
14
|
+
# end
|
14
15
|
# end
|
15
|
-
# end
|
16
16
|
#
|
17
|
-
# If you wish to limit the
|
17
|
+
# If you wish to limit the duration a lock may be held for, you can
|
18
18
|
# set/override `lock_timeout`. e.g.
|
19
19
|
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
20
|
+
# class UpdateNetworkGraph
|
21
|
+
# extend Resque::Plugins::LockTimeout
|
22
|
+
# @queue = :network_graph
|
23
23
|
#
|
24
|
-
#
|
25
|
-
#
|
24
|
+
# # lock may be held for upto an hour.
|
25
|
+
# @lock_timeout = 3600
|
26
26
|
#
|
27
|
-
#
|
28
|
-
#
|
27
|
+
# def self.perform(repo_id)
|
28
|
+
# heavy_lifting
|
29
|
+
# end
|
29
30
|
# end
|
30
|
-
# end
|
31
31
|
#
|
32
|
+
# If you wish that only one instance of the job defined by #identifier may be
|
33
|
+
# enqueued or running, you can set/override `loner`. e.g.
|
34
|
+
#
|
35
|
+
# class PdfExport
|
36
|
+
# extend Resque::Plugins::LockTimeout
|
37
|
+
# @queue = :exports
|
38
|
+
#
|
39
|
+
# # only one job can be running/enqueued at a time. For instance a button
|
40
|
+
# # to run a PDF export. If the user clicks several times on it, enqueue
|
41
|
+
# # the job if and only if
|
42
|
+
# # - the same export is not currently running
|
43
|
+
# # - the same export is not currently queued.
|
44
|
+
# # ('same' being defined by `identifier`)
|
45
|
+
# @loner = true
|
46
|
+
#
|
47
|
+
# def self.perform(repo_id)
|
48
|
+
# heavy_lifting
|
49
|
+
# end
|
50
|
+
# end
|
32
51
|
module LockTimeout
|
33
52
|
# @abstract You may override to implement a custom identifier,
|
34
53
|
# you should consider doing this if your job arguments
|
@@ -56,8 +75,7 @@ module Resque
|
|
56
75
|
# Override to fully control the lock key used. It is passed
|
57
76
|
# the job arguments.
|
58
77
|
#
|
59
|
-
# The default looks like this:
|
60
|
-
# `resque-lock-timeout:<class name>:<identifier>`
|
78
|
+
# The default looks like this: `lock:<class name>:<identifier>`
|
61
79
|
#
|
62
80
|
# @param [Array] args job arguments
|
63
81
|
# @return [String] redis key
|
@@ -65,6 +83,16 @@ module Resque
|
|
65
83
|
['lock', name, identifier(*args)].compact.join(':')
|
66
84
|
end
|
67
85
|
|
86
|
+
# Builds lock key used by `@loner` option. Passed job arguments.
|
87
|
+
#
|
88
|
+
# The default looks like this: `loner:lock:<class name>:<identifier>`
|
89
|
+
#
|
90
|
+
# @param [Array] args job arguments
|
91
|
+
# @return [String] redis key
|
92
|
+
def redis_loner_lock_key(*args)
|
93
|
+
['loner', redis_lock_key(*args)].compact.join(':')
|
94
|
+
end
|
95
|
+
|
68
96
|
# Number of seconds the lock may be held for.
|
69
97
|
# A value of 0 or below will lock without a timeout.
|
70
98
|
#
|
@@ -74,6 +102,14 @@ module Resque
|
|
74
102
|
@lock_timeout ||= 0
|
75
103
|
end
|
76
104
|
|
105
|
+
# Whether one instance of the job should be running or enqueued.
|
106
|
+
#
|
107
|
+
# @param [Array] args job arguments
|
108
|
+
# @return [TrueClass || FalseClass]
|
109
|
+
def loner(*args)
|
110
|
+
@loner ||= false
|
111
|
+
end
|
112
|
+
|
77
113
|
# Convenience method, not used internally.
|
78
114
|
#
|
79
115
|
# @return [Boolean] true if the job is locked by someone
|
@@ -82,12 +118,19 @@ module Resque
|
|
82
118
|
end
|
83
119
|
|
84
120
|
# @abstract
|
85
|
-
# Hook method; called when a were unable to
|
121
|
+
# Hook method; called when a were unable to acquire the lock.
|
86
122
|
#
|
87
123
|
# @param [Array] args job arguments
|
88
124
|
def lock_failed(*args)
|
89
125
|
end
|
90
126
|
|
127
|
+
# @abstract
|
128
|
+
# Hook method; called when a were unable to enqueue loner job.
|
129
|
+
#
|
130
|
+
# @param [Array] args job arguments
|
131
|
+
def loner_enqueue_failed(*args)
|
132
|
+
end
|
133
|
+
|
91
134
|
# @abstract
|
92
135
|
# Hook method; called when the lock expired before we released it.
|
93
136
|
#
|
@@ -95,17 +138,49 @@ module Resque
|
|
95
138
|
def lock_expired_before_release(*args)
|
96
139
|
end
|
97
140
|
|
98
|
-
#
|
141
|
+
# @abstract
|
142
|
+
# if the job is a `loner`, enqueue only if no other same job
|
143
|
+
# is already running/enqueued
|
99
144
|
#
|
100
|
-
#
|
145
|
+
# @param [Array] args job arguments
|
146
|
+
def before_enqueue_lock(*args)
|
147
|
+
if loner
|
148
|
+
if locked?(*args)
|
149
|
+
# Same job is currently running
|
150
|
+
loner_enqueue_failed(*args)
|
151
|
+
false
|
152
|
+
else
|
153
|
+
acquire_loner_lock!(*args)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# Try to acquire a lock for running the job.
|
159
|
+
# @return [Boolean, Fixnum]
|
160
|
+
def acquire_lock!(*args)
|
161
|
+
acquire_lock_impl!(:redis_lock_key, :lock_failed, *args)
|
162
|
+
end
|
163
|
+
|
164
|
+
# Try to acquire a lock to enqueue a loner job.
|
165
|
+
# @return [Boolean, Fixnum]
|
166
|
+
def acquire_loner_lock!(*args)
|
167
|
+
acquire_lock_impl!(:redis_loner_lock_key, :loner_enqueue_failed, *args)
|
168
|
+
end
|
169
|
+
|
170
|
+
# Generic implementation of the locking logic
|
171
|
+
#
|
172
|
+
# Returns false; when unable to acquire the lock.
|
101
173
|
# * Returns true; when lock acquired, without a timeout.
|
102
174
|
# * Returns timestamp; when lock acquired with a timeout, timestamp is
|
103
175
|
# when the lock timeout expires.
|
104
176
|
#
|
177
|
+
# @param [Symbol] lock_key_method the method returning redis key to lock
|
178
|
+
# @param [Symbol] failed_hook the method called if lock failed
|
179
|
+
# @param [Array] args job arguments
|
105
180
|
# @return [Boolean, Fixnum]
|
106
|
-
def
|
181
|
+
def acquire_lock_impl!(lock_key_method, failed_hook, *args)
|
107
182
|
acquired = false
|
108
|
-
lock_key =
|
183
|
+
lock_key = self.send lock_key_method, *args
|
109
184
|
|
110
185
|
unless lock_timeout(*args) > 0
|
111
186
|
# Acquire without using a timeout.
|
@@ -115,11 +190,11 @@ module Resque
|
|
115
190
|
acquired, lock_until = acquire_lock_algorithm!(lock_key, *args)
|
116
191
|
end
|
117
192
|
|
118
|
-
|
193
|
+
self.send(failed_hook, *args) if !acquired
|
119
194
|
lock_until && acquired ? lock_until : acquired
|
120
195
|
end
|
121
196
|
|
122
|
-
# Attempts to
|
197
|
+
# Attempts to acquire the lock using a timeout / deadlock algorithm.
|
123
198
|
#
|
124
199
|
# Locking algorithm: http://code.google.com/p/redis/wiki/SetnxCommand
|
125
200
|
#
|
@@ -154,6 +229,13 @@ module Resque
|
|
154
229
|
lock_redis.del(redis_lock_key(*args))
|
155
230
|
end
|
156
231
|
|
232
|
+
# Release the enqueue lock for loner jobs
|
233
|
+
#
|
234
|
+
# @param [Array] args job arguments
|
235
|
+
def release_loner_lock!(*args)
|
236
|
+
lock_redis.del(redis_loner_lock_key(*args))
|
237
|
+
end
|
238
|
+
|
157
239
|
# Refresh the lock.
|
158
240
|
#
|
159
241
|
# @param [Array] args job arguments
|
@@ -167,8 +249,13 @@ module Resque
|
|
167
249
|
#
|
168
250
|
# @param [Array] args job arguments
|
169
251
|
def around_perform_lock(*args)
|
252
|
+
lock_until = acquire_lock!(*args)
|
253
|
+
|
254
|
+
# Release loner lock as job has been dequeued
|
255
|
+
release_loner_lock!(*args) if loner
|
256
|
+
|
170
257
|
# Abort if another job holds the lock.
|
171
|
-
return unless lock_until
|
258
|
+
return unless lock_until
|
172
259
|
|
173
260
|
begin
|
174
261
|
yield
|
data/test/lock_test.rb
CHANGED
@@ -2,7 +2,7 @@ require File.dirname(__FILE__) + '/test_helper'
|
|
2
2
|
|
3
3
|
class LockTest < MiniTest::Unit::TestCase
|
4
4
|
def setup
|
5
|
-
$success = $lock_failed = $lock_expired = 0
|
5
|
+
$success = $lock_failed = $lock_expired = $enqueue_failed = 0
|
6
6
|
Resque.redis.flushall
|
7
7
|
@worker = Resque::Worker.new(:test)
|
8
8
|
end
|
@@ -155,4 +155,41 @@ class LockTest < MiniTest::Unit::TestCase
|
|
155
155
|
diff = latest_lock - initial_lock
|
156
156
|
assert diff >= 1, 'diff between initial lock and refreshed lock should be at least 1 second'
|
157
157
|
end
|
158
|
+
|
159
|
+
def test_cannot_enqueue_two_loner_jobs
|
160
|
+
Resque.enqueue(LonelyJob)
|
161
|
+
Resque.enqueue(LonelyJob)
|
162
|
+
assert_equal 1, Resque.size(:test), '1 job should be enqueued'
|
163
|
+
|
164
|
+
Resque.enqueue(LonelyTimeoutJob)
|
165
|
+
Resque.enqueue(LonelyTimeoutJob)
|
166
|
+
assert_equal 2, Resque.size(:test), '2 jobs should be enqueued'
|
167
|
+
end
|
168
|
+
|
169
|
+
def test_loner_job_should_not_be_enqued_if_already_running
|
170
|
+
Resque.enqueue(LonelyJob)
|
171
|
+
thread = Thread.new { @worker.process }
|
172
|
+
|
173
|
+
sleep 0.1 # The LonelyJob should be running (perfom is 0.2 seconds long)
|
174
|
+
Resque.enqueue(LonelyJob)
|
175
|
+
assert_equal 0, Resque.size(:test)
|
176
|
+
assert_equal 1, $enqueue_failed, 'One job callback should increment enqueue_failed'
|
177
|
+
|
178
|
+
thread.join
|
179
|
+
assert_equal 1, $success, 'One job should increment success'
|
180
|
+
end
|
181
|
+
|
182
|
+
def test_loner_job_with_timeout_should_not_be_enqued_if_already_running
|
183
|
+
Resque.enqueue(LonelyTimeoutJob)
|
184
|
+
thread = Thread.new { @worker.process }
|
185
|
+
|
186
|
+
sleep 0.1 # Job should be running (perfom is 0.2 seconds long)
|
187
|
+
Resque.enqueue(LonelyTimeoutJob)
|
188
|
+
assert_equal 0, Resque.size(:test)
|
189
|
+
assert_equal 1, $enqueue_failed, 'One job callback should increment enqueue_failed'
|
190
|
+
|
191
|
+
thread.join
|
192
|
+
assert_equal 1, $success, 'One job should increment success'
|
193
|
+
end
|
194
|
+
|
158
195
|
end
|
data/test/redis-test.conf
CHANGED
@@ -6,10 +6,10 @@ daemonize yes
|
|
6
6
|
|
7
7
|
# When run as a daemon, Redis write a pid file in /var/run/redis.pid by default.
|
8
8
|
# You can specify a custom pid file location here.
|
9
|
-
pidfile ./test/redis-test.pid
|
9
|
+
#pidfile ./test/redis-test.pid
|
10
10
|
|
11
11
|
# Accept connections on the specified port, default is 6379
|
12
|
-
port
|
12
|
+
port 9737
|
13
13
|
|
14
14
|
# If you want you can bind a single interface, if the bind option is not
|
15
15
|
# specified all the interfaces will listen for connections.
|
@@ -30,16 +30,16 @@ timeout 300
|
|
30
30
|
# after 900 sec (15 min) if at least 1 key changed
|
31
31
|
# after 300 sec (5 min) if at least 10 keys changed
|
32
32
|
# after 60 sec if at least 10000 keys changed
|
33
|
-
save 900 1
|
34
|
-
save 300 10
|
35
|
-
save 60 10000
|
33
|
+
#save 900 1
|
34
|
+
#save 300 10
|
35
|
+
#save 60 10000
|
36
36
|
|
37
37
|
# The filename where to dump the DB
|
38
|
-
dbfilename dump.rdb
|
38
|
+
#dbfilename dump.rdb
|
39
39
|
|
40
40
|
# For default save/load DB in/from the working directory
|
41
41
|
# Note that you must specify a directory not a file name.
|
42
|
-
dir ./test/
|
42
|
+
#dir ./test/
|
43
43
|
|
44
44
|
# Set server verbosity to 'debug'
|
45
45
|
# it can be one of:
|
@@ -112,4 +112,4 @@ databases 16
|
|
112
112
|
# Glue small output buffers together in order to send small replies in a
|
113
113
|
# single TCP packet. Uses a bit more CPU but most of the times it is a win
|
114
114
|
# in terms of number of queries per second. Use 'yes' if unsure.
|
115
|
-
glueoutputbuf yes
|
115
|
+
# glueoutputbuf yes
|
data/test/test_helper.rb
CHANGED
@@ -5,36 +5,39 @@ $TESTING = true
|
|
5
5
|
require 'rubygems'
|
6
6
|
require 'minitest/unit'
|
7
7
|
require 'minitest/pride'
|
8
|
-
require 'simplecov'
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
# Run code coverage in MRI 1.9 only.
|
10
|
+
if RUBY_VERSION >= '1.9' && RUBY_ENGINE == 'ruby'
|
11
|
+
require 'simplecov'
|
12
|
+
SimpleCov.start do
|
13
|
+
add_filter '/test/'
|
14
|
+
end
|
15
|
+
end
|
13
16
|
|
14
17
|
require 'resque-lock-timeout'
|
15
18
|
require dir + '/test_jobs'
|
16
19
|
|
17
|
-
# make sure we can run redis
|
20
|
+
# make sure we can run redis-server
|
18
21
|
if !system('which redis-server')
|
19
|
-
puts '', "**
|
20
|
-
puts '** try running `sudo rake install`'
|
22
|
+
puts '', "** `redis-server` was not found in your PATH"
|
21
23
|
abort ''
|
22
24
|
end
|
23
25
|
|
24
|
-
#
|
25
|
-
|
26
|
+
# make sure we can shutdown the server using cli.
|
27
|
+
if !system('which redis-cli')
|
28
|
+
puts '', "** `redis-cli` was not found in your PATH"
|
29
|
+
abort ''
|
30
|
+
end
|
31
|
+
|
32
|
+
# This code is run `at_exit` to setup everything before running the tests.
|
33
|
+
# Redis server is started before this code block runs.
|
26
34
|
at_exit do
|
27
35
|
next if $!
|
28
36
|
|
29
37
|
exit_code = MiniTest::Unit.new.run(ARGV)
|
30
|
-
|
31
|
-
pid = `ps -e -o pid,command | grep [r]edis-test`.split(' ')[0]
|
32
|
-
puts 'Killing test redis server...'
|
33
|
-
`rm -f #{dir}/dump.rdb`
|
34
|
-
`kill -9 #{pid}`
|
35
|
-
exit(exit_code)
|
38
|
+
`redis-cli -p 9737 shutdown nosave`
|
36
39
|
end
|
37
40
|
|
38
|
-
puts
|
41
|
+
puts "Starting redis for testing at localhost:9737..."
|
39
42
|
`redis-server #{dir}/redis-test.conf`
|
40
|
-
Resque.redis = '127.0.0.1:
|
43
|
+
Resque.redis = '127.0.0.1:9737'
|
data/test/test_jobs.rb
CHANGED
@@ -112,4 +112,37 @@ class RefreshLockJob
|
|
112
112
|
extend Resque::Plugins::LockTimeout
|
113
113
|
@queue = :test
|
114
114
|
@lock_timeout = 60
|
115
|
-
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# Job that prevents the job being enqueued if already enqueued/running.
|
118
|
+
class LonelyJob
|
119
|
+
extend Resque::Plugins::LockTimeout
|
120
|
+
@queue = :test
|
121
|
+
@loner = true
|
122
|
+
|
123
|
+
def self.perform
|
124
|
+
$success += 1
|
125
|
+
sleep 0.2
|
126
|
+
end
|
127
|
+
|
128
|
+
def self.loner_enqueue_failed(*args)
|
129
|
+
$enqueue_failed += 1
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# Exclusive job (only one queued/running) with a timeout.
|
134
|
+
class LonelyTimeoutJob
|
135
|
+
extend Resque::Plugins::LockTimeout
|
136
|
+
@queue = :test
|
137
|
+
@loner = true
|
138
|
+
@lock_timeout = 60
|
139
|
+
|
140
|
+
def self.perform
|
141
|
+
$success += 1
|
142
|
+
sleep 0.2
|
143
|
+
end
|
144
|
+
|
145
|
+
def self.loner_enqueue_failed(*args)
|
146
|
+
$enqueue_failed += 1
|
147
|
+
end
|
148
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: resque-lock-timeout
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -11,11 +11,11 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2012-
|
14
|
+
date: 2012-11-09 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: resque
|
18
|
-
requirement:
|
18
|
+
requirement: !ruby/object:Gem::Requirement
|
19
19
|
none: false
|
20
20
|
requirements:
|
21
21
|
- - ! '>='
|
@@ -23,10 +23,15 @@ dependencies:
|
|
23
23
|
version: 1.8.0
|
24
24
|
type: :runtime
|
25
25
|
prerelease: false
|
26
|
-
version_requirements:
|
26
|
+
version_requirements: !ruby/object:Gem::Requirement
|
27
|
+
none: false
|
28
|
+
requirements:
|
29
|
+
- - ! '>='
|
30
|
+
- !ruby/object:Gem::Version
|
31
|
+
version: 1.8.0
|
27
32
|
- !ruby/object:Gem::Dependency
|
28
33
|
name: rake
|
29
|
-
requirement:
|
34
|
+
requirement: !ruby/object:Gem::Requirement
|
30
35
|
none: false
|
31
36
|
requirements:
|
32
37
|
- - ! '>='
|
@@ -34,10 +39,15 @@ dependencies:
|
|
34
39
|
version: '0'
|
35
40
|
type: :development
|
36
41
|
prerelease: false
|
37
|
-
version_requirements:
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
none: false
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
38
48
|
- !ruby/object:Gem::Dependency
|
39
49
|
name: minitest
|
40
|
-
requirement:
|
50
|
+
requirement: !ruby/object:Gem::Requirement
|
41
51
|
none: false
|
42
52
|
requirements:
|
43
53
|
- - ! '>='
|
@@ -45,10 +55,15 @@ dependencies:
|
|
45
55
|
version: '0'
|
46
56
|
type: :development
|
47
57
|
prerelease: false
|
48
|
-
version_requirements:
|
58
|
+
version_requirements: !ruby/object:Gem::Requirement
|
59
|
+
none: false
|
60
|
+
requirements:
|
61
|
+
- - ! '>='
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0'
|
49
64
|
- !ruby/object:Gem::Dependency
|
50
65
|
name: json
|
51
|
-
requirement:
|
66
|
+
requirement: !ruby/object:Gem::Requirement
|
52
67
|
none: false
|
53
68
|
requirements:
|
54
69
|
- - ! '>='
|
@@ -56,10 +71,15 @@ dependencies:
|
|
56
71
|
version: '0'
|
57
72
|
type: :development
|
58
73
|
prerelease: false
|
59
|
-
version_requirements:
|
74
|
+
version_requirements: !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ! '>='
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
60
80
|
- !ruby/object:Gem::Dependency
|
61
81
|
name: yard
|
62
|
-
requirement:
|
82
|
+
requirement: !ruby/object:Gem::Requirement
|
63
83
|
none: false
|
64
84
|
requirements:
|
65
85
|
- - ! '>='
|
@@ -67,10 +87,15 @@ dependencies:
|
|
67
87
|
version: '0'
|
68
88
|
type: :development
|
69
89
|
prerelease: false
|
70
|
-
version_requirements:
|
90
|
+
version_requirements: !ruby/object:Gem::Requirement
|
91
|
+
none: false
|
92
|
+
requirements:
|
93
|
+
- - ! '>='
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
71
96
|
- !ruby/object:Gem::Dependency
|
72
97
|
name: rdiscount
|
73
|
-
requirement:
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
74
99
|
none: false
|
75
100
|
requirements:
|
76
101
|
- - ! '>='
|
@@ -78,10 +103,15 @@ dependencies:
|
|
78
103
|
version: '0'
|
79
104
|
type: :development
|
80
105
|
prerelease: false
|
81
|
-
version_requirements:
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
none: false
|
108
|
+
requirements:
|
109
|
+
- - ! '>='
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
82
112
|
- !ruby/object:Gem::Dependency
|
83
113
|
name: simplecov
|
84
|
-
requirement:
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
85
115
|
none: false
|
86
116
|
requirements:
|
87
117
|
- - ! '>='
|
@@ -89,9 +119,14 @@ dependencies:
|
|
89
119
|
version: 0.3.0
|
90
120
|
type: :development
|
91
121
|
prerelease: false
|
92
|
-
version_requirements:
|
122
|
+
version_requirements: !ruby/object:Gem::Requirement
|
123
|
+
none: false
|
124
|
+
requirements:
|
125
|
+
- - ! '>='
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
version: 0.3.0
|
93
128
|
description: ! " A Resque plugin. Adds locking, with optional timeout/deadlock handling
|
94
|
-
to\n resque jobs.\n\n Using a `lock_timeout` allows you to re-
|
129
|
+
to\n resque jobs.\n\n Using a `lock_timeout` allows you to re-acquire the lock
|
95
130
|
should your worker\n fail, crash, or is otherwise unable to relase the lock.\n
|
96
131
|
\ \n i.e. Your server unexpectedly looses power. Very handy for jobs that are\n
|
97
132
|
\ recurring or may be retried.\n"
|
@@ -130,7 +165,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
130
165
|
version: '0'
|
131
166
|
requirements: []
|
132
167
|
rubyforge_project:
|
133
|
-
rubygems_version: 1.8.
|
168
|
+
rubygems_version: 1.8.24
|
134
169
|
signing_key:
|
135
170
|
specification_version: 3
|
136
171
|
summary: A Resque plugin adding locking, with optional timeout/deadlock handling to
|