resque-lock-timeout 0.3.0 → 0.3.1

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/HISTORY.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## 0.3.1 (2011-07-16)
2
+
3
+ * Pass job arguments to `lock_timeout`. (Bob Potter)
4
+ * Added `refresh_lock!` method for long running jobs. (Bob Potter)
5
+
1
6
  ## 0.3.0 (2011-07-16)
2
7
 
3
8
  * Ability to customize redis connection used for storing locks.
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  Resque Lock Timeout
2
2
  ===================
3
3
 
4
- A [Resque][rq] plugin. Requires Resque 1.8.0.
4
+ A [Resque][rq] plugin. Requires Resque >= 01.8.0.
5
5
 
6
6
  resque-lock-timeout adds locking, with optional timeout/deadlock handling to
7
7
  resque jobs.
@@ -110,6 +110,30 @@ change this you may override `lock_redis`.
110
110
  end
111
111
  end
112
112
 
113
+ ### Setting Timeout At Runtime
114
+
115
+ You may define the `lock_timeout` method to adjust the timeout at runtime
116
+ using job arguments. e.g.
117
+
118
+ class UpdateNetworkGraph
119
+ extend Resque::Plugins::LockTimeout
120
+ @queue = :network_graph
121
+
122
+ def self.lock_timeout(repo_id, timeout_minutes)
123
+ 60 * timeout_minutes
124
+ end
125
+
126
+ def self.perform(repo_id, timeout_minutes = 1)
127
+ heavy_lifting
128
+ end
129
+ end
130
+
131
+ ### Helper Methods
132
+
133
+ * `locked?` - checks if the lock is currently held.
134
+ * `refresh_lock!` - Refresh the lock, useful for jobs that are taking longer
135
+ then usual but your okay with them holding on to the lock a little longer.
136
+
113
137
  ### Callbacks
114
138
 
115
139
  Several callbacks are available to override and implement your own logic, e.g.
data/Rakefile CHANGED
@@ -14,7 +14,7 @@ desc 'Build Yardoc documentation.'
14
14
  YARD::Rake::YardocTask.new :yardoc do |t|
15
15
  t.files = ['lib/**/*.rb']
16
16
  t.options = ['--output-dir', "doc/",
17
- '--files', 'LICENSE',
17
+ '--files', 'LICENSE,HISTORY.md',
18
18
  '--readme', 'README.md',
19
19
  '--title', 'resque-lock-timeout documentation']
20
20
  end
@@ -59,6 +59,7 @@ module Resque
59
59
  # The default looks like this:
60
60
  # `resque-lock-timeout:<class name>:<identifier>`
61
61
  #
62
+ # @param [Array] args job arguments
62
63
  # @return [String] redis key
63
64
  def redis_lock_key(*args)
64
65
  ['lock', name, identifier(*args)].compact.join(":")
@@ -67,8 +68,9 @@ module Resque
67
68
  # Number of seconds the lock may be held for.
68
69
  # A value of 0 or below will lock without a timeout.
69
70
  #
71
+ # @param [Array] args job arguments
70
72
  # @return [Fixnum]
71
- def lock_timeout
73
+ def lock_timeout(*args)
72
74
  @lock_timeout ||= 0
73
75
  end
74
76
 
@@ -105,12 +107,12 @@ module Resque
105
107
  acquired = false
106
108
  lock_key = redis_lock_key(*args)
107
109
 
108
- unless lock_timeout > 0
110
+ unless lock_timeout(*args) > 0
109
111
  # Acquire without using a timeout.
110
112
  acquired = true if lock_redis.setnx(lock_key, true)
111
113
  else
112
114
  # Acquire using the timeout algorithm.
113
- acquired, lock_until = acquire_lock_algorithm!(lock_key)
115
+ acquired, lock_until = acquire_lock_algorithm!(lock_key, *args)
114
116
  end
115
117
 
116
118
  lock_failed(*args) if !acquired
@@ -120,9 +122,12 @@ module Resque
120
122
  # Attempts to aquire the lock using a timeout / deadlock algorithm.
121
123
  #
122
124
  # Locking algorithm: http://code.google.com/p/redis/wiki/SetnxCommand
123
- def acquire_lock_algorithm!(lock_key)
125
+ #
126
+ # @param [String] lock_key redis lock key
127
+ # @param [Array] args job arguments
128
+ def acquire_lock_algorithm!(lock_key, *args)
124
129
  now = Time.now.to_i
125
- lock_until = now + lock_timeout
130
+ lock_until = now + lock_timeout(*args)
126
131
  acquired = false
127
132
 
128
133
  return [true, lock_until] if lock_redis.setnx(lock_key, lock_until)
@@ -143,11 +148,24 @@ module Resque
143
148
  end
144
149
 
145
150
  # Release the lock.
151
+ #
152
+ # @param [Array] args job arguments
146
153
  def release_lock!(*args)
147
154
  lock_redis.del(redis_lock_key(*args))
148
155
  end
149
156
 
157
+ # Refresh the lock.
158
+ #
159
+ # @param [Array] args job arguments
160
+ def refresh_lock!(*args)
161
+ now = Time.now.to_i
162
+ lock_until = now + lock_timeout(*args)
163
+ lock_redis.set(redis_lock_key(*args), lock_until)
164
+ end
165
+
150
166
  # Where the magic happens.
167
+ #
168
+ # @param [Array] args job arguments
151
169
  def around_perform_lock(*args)
152
170
  # Abort if another job holds the lock.
153
171
  return unless lock_until = acquire_lock!(*args)
data/test/lock_test.rb CHANGED
@@ -126,4 +126,34 @@ class LockTest < Test::Unit::TestCase
126
126
  assert_nil lock_redis.get('specific_redis')
127
127
  assert_equal 1, $success, 'job should increment success'
128
128
  end
129
+
130
+ def test_lock_timeout_accepts_job_args
131
+ # setup our time values.
132
+ now = Time.now.to_i
133
+ one_hour_ahead = now + 3600
134
+ twelve_hours_ahead = (now + (3600 * 12))
135
+
136
+ # 1 hour ahead.
137
+ assert VariableTimeoutJob.acquire_lock!(1) >= one_hour_ahead, 'lock should be 1 hour ahead'
138
+ VariableTimeoutJob.release_lock!
139
+
140
+ # 12 hours ahead.
141
+ assert VariableTimeoutJob.acquire_lock!(12) >= twelve_hours_ahead, 'lock should be 12 hours ahead'
142
+ VariableTimeoutJob.release_lock!
143
+ end
144
+
145
+ def test_refresh_lock!
146
+ # grab the lock.
147
+ RefreshLockJob.acquire_lock!
148
+ sleep 2
149
+
150
+ # grab the initial lock timeout then refresh the lock.
151
+ initial_lock = Resque.redis.get(RefreshLockJob.redis_lock_key).to_i
152
+ RefreshLockJob.refresh_lock!
153
+
154
+ # lock should now be at least 1 second more then the initial lock.
155
+ latest_lock = Resque.redis.get(RefreshLockJob.redis_lock_key).to_i
156
+ diff = latest_lock - initial_lock
157
+ assert diff >= 1, 'diff between initial lock and refreshed lock should be at least 1 second'
158
+ end
129
159
  end
data/test/test_jobs.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # Slow successful job, does not use timeout algorithm.
1
2
  class SlowJob
2
3
  extend Resque::Plugins::LockTimeout
3
4
  @queue = :test
@@ -12,6 +13,7 @@ class SlowJob
12
13
  end
13
14
  end
14
15
 
16
+ # Fast successful job, does not use timeout algorithm.
15
17
  class FastJob
16
18
  extend Resque::Plugins::LockTimeout
17
19
  @queue = :test
@@ -25,6 +27,7 @@ class FastJob
25
27
  end
26
28
  end
27
29
 
30
+ # Job that fails quickly, does not use timeout algorithm.
28
31
  class FailingFastJob
29
32
  extend Resque::Plugins::LockTimeout
30
33
  @queue = :test
@@ -35,6 +38,7 @@ class FailingFastJob
35
38
  end
36
39
  end
37
40
 
41
+ # Job that enables the timeout algorithm.
38
42
  class SlowWithTimeoutJob
39
43
  extend Resque::Plugins::LockTimeout
40
44
  @queue = :test
@@ -46,6 +50,7 @@ class SlowWithTimeoutJob
46
50
  end
47
51
  end
48
52
 
53
+ # Job that releases its lock AFTER its expired.
49
54
  class ExpireBeforeReleaseJob
50
55
  extend Resque::Plugins::LockTimeout
51
56
  @queue = :test
@@ -61,6 +66,7 @@ class ExpireBeforeReleaseJob
61
66
  end
62
67
  end
63
68
 
69
+ # Job that uses a spesific redis connection just for storing locks.
64
70
  class SpecificRedisJob
65
71
  extend Resque::Plugins::LockTimeout
66
72
  @queue = :test
@@ -81,4 +87,29 @@ class SpecificRedisJob
81
87
  $success += 1
82
88
  sleep 0.2
83
89
  end
90
+ end
91
+
92
+ # Job that uses a different lock timeout value depending on job args.
93
+ class VariableTimeoutJob
94
+ extend Resque::Plugins::LockTimeout
95
+ @queue = :test
96
+
97
+ def self.identifier(*args)
98
+ nil
99
+ end
100
+
101
+ def self.lock_timeout(extra_timeout)
102
+ 3600 * extra_timeout
103
+ end
104
+
105
+ def self.perform
106
+ $success += 1
107
+ end
108
+ end
109
+
110
+ # Job to simulate a long running job that refreshes its hold on the lock.
111
+ class RefreshLockJob
112
+ extend Resque::Plugins::LockTimeout
113
+ @queue = :test
114
+ @lock_timeout = 60
84
115
  end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: resque-lock-timeout
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.3.0
5
+ version: 0.3.1
6
6
  platform: ruby
7
7
  authors:
8
8
  - Luke Antins