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.
Files changed (3) hide show
  1. data/lib/resque/plugins/lock.rb +24 -1
  2. data/test/lock_test.rb +20 -0
  3. metadata +24 -55
@@ -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
- Resque.redis.setnx(lock(*args), true)
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)
@@ -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
- hash: 23
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
- description: |
24
- A Resque plugin. If you want only one instance of your job
25
- queued at a time, extend it with this module.
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
- hash: 3
65
- segments:
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
- hash: 3
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.5.2
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 time.
52
+ summary: A Resque plugin for ensuring only one instance of your job is queued at a
53
+ time.
84
54
  test_files: []
85
-