resque-lock 1.0.0 → 1.1.0
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.
- data/lib/resque/plugins/lock.rb +24 -1
- data/test/lock_test.rb +20 -0
- metadata +24 -55
data/lib/resque/plugins/lock.rb
CHANGED
@@ -41,6 +41,14 @@ module Resque
|
|
41
41
|
# repo_id. Normally a job is locked using a combination of its
|
42
42
|
# class name and arguments.
|
43
43
|
module Lock
|
44
|
+
|
45
|
+
# Override in your job to control the lock experiation time. This is the
|
46
|
+
# time in seconds that the lock should be considered valid. The default
|
47
|
+
# is one hour (3600 seconds).
|
48
|
+
def lock_timeout
|
49
|
+
3600
|
50
|
+
end
|
51
|
+
|
44
52
|
# Override in your job to control the lock key. It is
|
45
53
|
# passed the same arguments as `perform`, that is, your job's
|
46
54
|
# payload.
|
@@ -48,8 +56,23 @@ module Resque
|
|
48
56
|
"lock:#{name}-#{args.to_s}"
|
49
57
|
end
|
50
58
|
|
59
|
+
# See the documentation for SETNX http://redis.io/commands/setnx for an
|
60
|
+
# explanation of this deadlock free locking pattern
|
51
61
|
def before_enqueue_lock(*args)
|
52
|
-
|
62
|
+
key = lock(*args)
|
63
|
+
now = Time.now.to_i
|
64
|
+
timeout = now + lock_timeout + 1
|
65
|
+
|
66
|
+
# return true if we successfully acquired the lock
|
67
|
+
return true if Resque.redis.setnx(key, timeout)
|
68
|
+
|
69
|
+
# see if the existing timeout is still valid and return false if it is
|
70
|
+
# (we cannot acquire the lock during the timeout period)
|
71
|
+
return false if now <= Resque.redis.get(key).to_i
|
72
|
+
|
73
|
+
# otherwise set the timeout and ensure that no other worker has
|
74
|
+
# acquired the lock
|
75
|
+
now > Resque.redis.getset(key, timeout).to_i
|
53
76
|
end
|
54
77
|
|
55
78
|
def around_perform_lock(*args)
|
data/test/lock_test.rb
CHANGED
@@ -9,6 +9,10 @@ class LockTest < Test::Unit::TestCase
|
|
9
9
|
extend Resque::Plugins::Lock
|
10
10
|
@queue = :lock_test
|
11
11
|
|
12
|
+
def self.lock_timeout
|
13
|
+
1
|
14
|
+
end
|
15
|
+
|
12
16
|
def self.perform
|
13
17
|
raise "Woah woah woah, that wasn't supposed to happen"
|
14
18
|
end
|
@@ -37,4 +41,20 @@ class LockTest < Test::Unit::TestCase
|
|
37
41
|
|
38
42
|
assert_equal 1, Resque.redis.llen('queue:lock_test')
|
39
43
|
end
|
44
|
+
|
45
|
+
def test_deadlock
|
46
|
+
now = Time.now.to_i
|
47
|
+
|
48
|
+
Resque.redis.set(Job.lock, now+60)
|
49
|
+
Resque.enqueue(Job)
|
50
|
+
assert_equal 0, Resque.redis.llen('queue:lock_test')
|
51
|
+
|
52
|
+
Resque.redis.set(Job.lock, now-1)
|
53
|
+
Resque.enqueue(Job)
|
54
|
+
assert_equal 1, Resque.redis.llen('queue:lock_test')
|
55
|
+
|
56
|
+
sleep 3
|
57
|
+
Resque.enqueue(Job)
|
58
|
+
assert_equal 2, Resque.redis.llen('queue:lock_test')
|
59
|
+
end
|
40
60
|
end
|
metadata
CHANGED
@@ -1,85 +1,54 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: resque-lock
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.1.0
|
5
5
|
prerelease:
|
6
|
-
segments:
|
7
|
-
- 1
|
8
|
-
- 0
|
9
|
-
- 0
|
10
|
-
version: 1.0.0
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
7
|
+
authors:
|
13
8
|
- Chris Wanstrath
|
14
9
|
- Ray Krueger
|
15
10
|
autorequire:
|
16
11
|
bindir: bin
|
17
12
|
cert_chain: []
|
18
|
-
|
19
|
-
date: 2011-08-18 00:00:00 -07:00
|
20
|
-
default_executable:
|
13
|
+
date: 2012-11-08 00:00:00.000000000 Z
|
21
14
|
dependencies: []
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
For example:
|
28
|
-
|
29
|
-
class UpdateNetworkGraph
|
30
|
-
extend Resque::Jobs::Locked
|
31
|
-
|
32
|
-
def self.perform(repo_id)
|
33
|
-
heavy_lifting
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
15
|
+
description: ! "A Resque plugin. If you want only one instance of your job\nqueued
|
16
|
+
at a time, extend it with this module.\n\nFor example:\n\n class UpdateNetworkGraph\n
|
17
|
+
\ extend Resque::Jobs::Locked\n\n def self.perform(repo_id)\n heavy_lifting\n
|
18
|
+
\ end\n end\n"
|
37
19
|
email: chris@ozmm.org
|
38
20
|
executables: []
|
39
|
-
|
40
21
|
extensions: []
|
41
|
-
|
42
22
|
extra_rdoc_files: []
|
43
|
-
|
44
|
-
files:
|
23
|
+
files:
|
45
24
|
- README.md
|
46
25
|
- Rakefile
|
47
26
|
- LICENSE
|
48
27
|
- lib/resque/plugins/lock.rb
|
49
28
|
- test/lock_test.rb
|
50
|
-
has_rdoc: true
|
51
29
|
homepage: http://github.com/defunkt/resque-lock
|
52
30
|
licenses: []
|
53
|
-
|
54
31
|
post_install_message:
|
55
32
|
rdoc_options: []
|
56
|
-
|
57
|
-
require_paths:
|
33
|
+
require_paths:
|
58
34
|
- lib
|
59
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
35
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
60
36
|
none: false
|
61
|
-
requirements:
|
62
|
-
- -
|
63
|
-
- !ruby/object:Gem::Version
|
64
|
-
|
65
|
-
|
66
|
-
- 0
|
67
|
-
version: "0"
|
68
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
69
42
|
none: false
|
70
|
-
requirements:
|
71
|
-
- -
|
72
|
-
- !ruby/object:Gem::Version
|
73
|
-
|
74
|
-
segments:
|
75
|
-
- 0
|
76
|
-
version: "0"
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
77
47
|
requirements: []
|
78
|
-
|
79
48
|
rubyforge_project:
|
80
|
-
rubygems_version: 1.
|
49
|
+
rubygems_version: 1.8.23
|
81
50
|
signing_key:
|
82
51
|
specification_version: 3
|
83
|
-
summary: A Resque plugin for ensuring only one instance of your job is queued at a
|
52
|
+
summary: A Resque plugin for ensuring only one instance of your job is queued at a
|
53
|
+
time.
|
84
54
|
test_files: []
|
85
|
-
|