resque-lock-retry 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +39 -10
- data/Rakefile +1 -6
- data/VERSION +1 -1
- data/lib/resque/plugins/retried.rb +12 -6
- data/resque-lock-retry.gemspec +2 -2
- data/test/combined_test.rb +1 -1
- data/test/locked_test.rb +1 -1
- data/test/retried_test.rb +27 -1
- data/test/retried_test_with_scheduler.rb +13 -1
- data/test/retry_on_fail_test.rb +1 -1
- data/test/retry_on_lock_test.rb +1 -1
- data/test/test_helper.rb +18 -0
- metadata +3 -3
data/README.markdown
CHANGED
@@ -8,11 +8,15 @@ Resque-lock-retry is an extension to
|
|
8
8
|
only one job runs at a time. In the case of locking conflicts, the job may be
|
9
9
|
ignored or retried.
|
10
10
|
|
11
|
+
This plugin works best in combination with
|
12
|
+
[resque-scheduler](http://github.com/bvandenbos/resque-scheduler), but it
|
13
|
+
isn't required.
|
14
|
+
|
11
15
|
Locked jobs
|
12
16
|
------------
|
13
17
|
|
14
18
|
If you want only one instance of your job running at a time, extend
|
15
|
-
Resque::Plugins::Locked
|
19
|
+
`Resque::Plugins::Locked`.
|
16
20
|
|
17
21
|
For example:
|
18
22
|
|
@@ -23,8 +27,8 @@ For example:
|
|
23
27
|
end
|
24
28
|
end
|
25
29
|
|
26
|
-
While other UpdateNetworkGraph jobs will be placed on the queue, the Locked
|
27
|
-
class will check Redis to see if any others are executing with the same
|
30
|
+
While other UpdateNetworkGraph jobs will be placed on the queue, the `Locked`
|
31
|
+
class will check `Redis` to see if any others are executing with the same
|
28
32
|
arguments before beginning. If another is executing the job will be aborted.
|
29
33
|
|
30
34
|
If you want to define the key yourself you can override the `lock` class
|
@@ -41,9 +45,9 @@ method in your subclass, e.g.
|
|
41
45
|
end
|
42
46
|
end
|
43
47
|
|
44
|
-
The above modification will ensure only one job of class UpdateNetworkGraph
|
45
|
-
running at a time, regardless of the repo_id
|
46
|
-
combination of its class name and arguments.
|
48
|
+
The above modification will ensure only one job of class `UpdateNetworkGraph`
|
49
|
+
is running at a time, regardless of the `repo_id`. Normally a job is locked
|
50
|
+
using a combination of its class name and arguments.
|
47
51
|
|
48
52
|
Retried jobs
|
49
53
|
------------
|
@@ -51,7 +55,7 @@ Retried jobs
|
|
51
55
|
### Locks
|
52
56
|
|
53
57
|
Normally, locked jobs simply abort when a lock is encountered. If you'd like
|
54
|
-
the job to try again when the lock is lifted, extend RetryOnLock
|
58
|
+
the job to try again when the lock is lifted, extend `RetryOnLock`.
|
55
59
|
|
56
60
|
For example:
|
57
61
|
|
@@ -67,7 +71,7 @@ a short delay.
|
|
67
71
|
|
68
72
|
### Failures
|
69
73
|
|
70
|
-
If you'd like to retry jobs when certain exceptions happen, use RetryOnFail
|
74
|
+
If you'd like to retry jobs when certain exceptions happen, use `RetryOnFail`.
|
71
75
|
Then, define the types of exceptions that are ok to retry on.
|
72
76
|
|
73
77
|
For example:
|
@@ -82,8 +86,33 @@ For example:
|
|
82
86
|
end
|
83
87
|
end
|
84
88
|
|
85
|
-
Now, if a NetworkError (or subclass) exception is thrown while performing
|
86
|
-
job, it will be required after a short delay.
|
89
|
+
Now, if a `NetworkError` (or subclass) exception is thrown while performing
|
90
|
+
the job, it will be required after a short delay.
|
91
|
+
|
92
|
+
### Retry strategies
|
93
|
+
|
94
|
+
Retrying comes in two flavors:
|
95
|
+
|
96
|
+
1. [resque-scheduler](http://github.com/bvandenbos/resque-scheduler) If
|
97
|
+
Resque responds to `enqueue_in`, the job will be scheduled to perform again in
|
98
|
+
the 5 seconds.
|
99
|
+
|
100
|
+
2. `sleep` If Resque does not respond to `enqueue_in`, then we simply sleep
|
101
|
+
for 1 second before enqueing the job. This method is NOT recommended because
|
102
|
+
it will block your worker.
|
103
|
+
|
104
|
+
To change how long to wait until the job is retried, just override
|
105
|
+
`seconds_until_retry`
|
106
|
+
|
107
|
+
class UpdateNetworkGraph
|
108
|
+
extend Resque::Plugins::RetryOnLock
|
109
|
+
def self.perform(repo_id)
|
110
|
+
heavy_lifting
|
111
|
+
end
|
112
|
+
def self.seconds_until_retry
|
113
|
+
100
|
114
|
+
end
|
115
|
+
end
|
87
116
|
|
88
117
|
### Bonus
|
89
118
|
|
data/Rakefile
CHANGED
@@ -2,15 +2,10 @@ require 'rake/testtask'
|
|
2
2
|
|
3
3
|
task :default => :test
|
4
4
|
|
5
|
-
def command?(command)
|
6
|
-
system("type #{command} > /dev/null")
|
7
|
-
end
|
8
|
-
|
9
5
|
desc "Run the test suite"
|
10
6
|
task :test do
|
11
|
-
rg = command?(:rg)
|
12
7
|
Dir['test/**/*_test.rb'].each do |f|
|
13
|
-
|
8
|
+
ruby(f)
|
14
9
|
end
|
15
10
|
end
|
16
11
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.2
|
@@ -5,12 +5,12 @@ module Resque
|
|
5
5
|
# Override in your subclass to control how long to wait before
|
6
6
|
# performing this job again. Retrying comes in two flavors:
|
7
7
|
#
|
8
|
-
# 1. ResqueScheduler
|
9
|
-
# If Resque responds to
|
8
|
+
# 1. `ResqueScheduler`
|
9
|
+
# If Resque responds to `enqueue_in`, the job will be scheduled to
|
10
10
|
# perform again in the defined number of seconds.
|
11
11
|
#
|
12
|
-
# 2.
|
13
|
-
# If Resque does not respond to
|
12
|
+
# 2. `sleep`
|
13
|
+
# If Resque does not respond to `enqueue_in`, then we simply sleep
|
14
14
|
# for the defined number of seconds before enqueing the job. This
|
15
15
|
# method is NOT recommended because it will block your worker.
|
16
16
|
#
|
@@ -19,12 +19,18 @@ module Resque
|
|
19
19
|
Resque.respond_to?(:enqueue_in) ? 5 : 1
|
20
20
|
end
|
21
21
|
|
22
|
+
# Modify the arguments used to requeue the job. Use this to do something
|
23
|
+
# other than try the exact same job again.
|
24
|
+
def args_for_try_again(*args)
|
25
|
+
args
|
26
|
+
end
|
27
|
+
|
22
28
|
def try_again(*args)
|
23
29
|
if Resque.respond_to?(:enqueue_in)
|
24
|
-
Resque.enqueue_in(seconds_until_retry || 0, self, *args)
|
30
|
+
Resque.enqueue_in(seconds_until_retry || 0, self, *args_for_try_again(*args))
|
25
31
|
else
|
26
32
|
sleep(seconds_until_retry) if seconds_until_retry
|
27
|
-
Resque.enqueue(self, *args)
|
33
|
+
Resque.enqueue(self, *args_for_try_again(*args))
|
28
34
|
end
|
29
35
|
end
|
30
36
|
|
data/resque-lock-retry.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{resque-lock-retry}
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.2"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Ryan Carver"]
|
12
|
-
s.date = %q{2010-04-
|
12
|
+
s.date = %q{2010-04-09}
|
13
13
|
s.email = %q{ryan@typekit.com}
|
14
14
|
s.extra_rdoc_files = [
|
15
15
|
"README.markdown"
|
data/test/combined_test.rb
CHANGED
data/test/locked_test.rb
CHANGED
data/test/retried_test.rb
CHANGED
@@ -20,7 +20,7 @@ end
|
|
20
20
|
class Resque::RetriedJobWithSleepTest < Test::Unit::TestCase
|
21
21
|
|
22
22
|
def setup
|
23
|
-
Resque.redis.
|
23
|
+
Resque.redis.flushall
|
24
24
|
end
|
25
25
|
|
26
26
|
def test_default_seconds_until_retry
|
@@ -75,4 +75,30 @@ class Resque::RetriedJobWithSleepTest < Test::Unit::TestCase
|
|
75
75
|
assert_equal(0, Resque.redis.llen("queue:testqueue").to_i, "job is NOT enqueued")
|
76
76
|
end
|
77
77
|
|
78
|
+
def test_job_args_are_maintained
|
79
|
+
thread = Thread.new { perform_job RetriedOnFailJob, 1, FooError }
|
80
|
+
assert_equal(0, Resque.redis.llen("queue:testqueue").to_i, "queue is empty")
|
81
|
+
begin
|
82
|
+
thread.join
|
83
|
+
assert(false, "Should have raised an exception")
|
84
|
+
rescue StandardError => e
|
85
|
+
assert_equal(FooError, e.class, e.message)
|
86
|
+
end
|
87
|
+
assert job = Resque.pop(:testqueue)
|
88
|
+
assert_equal [1, "FooError"], job["args"]
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_job_args_can_be_modified
|
92
|
+
thread = Thread.new { perform_job RetriedOnFailWithDifferentArgsJob, 1, FooError }
|
93
|
+
assert_equal(0, Resque.redis.llen("queue:testqueue").to_i, "queue is empty")
|
94
|
+
begin
|
95
|
+
thread.join
|
96
|
+
assert(false, "Should have raised an exception")
|
97
|
+
rescue StandardError => e
|
98
|
+
assert_equal(FooError, e.class, e.message)
|
99
|
+
end
|
100
|
+
assert job = Resque.pop(:testqueue)
|
101
|
+
assert_equal [2, "FooError"], job["args"]
|
102
|
+
end
|
103
|
+
|
78
104
|
end
|
@@ -12,7 +12,7 @@ end
|
|
12
12
|
class Resque::RetriedJobWithResqueSchedulerTest < Test::Unit::TestCase
|
13
13
|
|
14
14
|
def setup
|
15
|
-
Resque.redis.
|
15
|
+
Resque.redis.flushall
|
16
16
|
end
|
17
17
|
|
18
18
|
def test_default_seconds_until_retry
|
@@ -31,4 +31,16 @@ class Resque::RetriedJobWithResqueSchedulerTest < Test::Unit::TestCase
|
|
31
31
|
assert_equal([5, RetriedOnFailJob, 0, FooError], Resque.last_enqueued_in)
|
32
32
|
end
|
33
33
|
|
34
|
+
def test_job_args_can_be_modified
|
35
|
+
thread = Thread.new { perform_job RetriedOnFailWithDifferentArgsJob, 0, FooError }
|
36
|
+
assert_equal(0, Resque.redis.llen("queue:testqueue").to_i, "queue is empty")
|
37
|
+
begin
|
38
|
+
thread.join
|
39
|
+
assert(false, "Should have raised an exception")
|
40
|
+
rescue StandardError => e
|
41
|
+
assert_equal(FooError, e.class, e.message)
|
42
|
+
end
|
43
|
+
assert_equal([5, RetriedOnFailWithDifferentArgsJob, 1, FooError], Resque.last_enqueued_in)
|
44
|
+
end
|
45
|
+
|
34
46
|
end
|
data/test/retry_on_fail_test.rb
CHANGED
data/test/retry_on_lock_test.rb
CHANGED
data/test/test_helper.rb
CHANGED
@@ -127,6 +127,24 @@ class RetriedOnFailJob
|
|
127
127
|
end
|
128
128
|
end
|
129
129
|
|
130
|
+
class RetriedOnFailWithDifferentArgsJob
|
131
|
+
extend ::Resque::Plugins::RetryOnFail
|
132
|
+
@queue = :testqueue
|
133
|
+
def self.perform(sleep_time, ex)
|
134
|
+
sleep sleep_time
|
135
|
+
raise ex
|
136
|
+
end
|
137
|
+
def self.args_for_try_again(sleep_time, ex)
|
138
|
+
[sleep_time + 1, ex]
|
139
|
+
end
|
140
|
+
def self.retried_exceptions
|
141
|
+
[FooError, BarError]
|
142
|
+
end
|
143
|
+
def self.lock(*args)
|
144
|
+
"TestLock"
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
130
148
|
class RetriedOnLockAndFailJob
|
131
149
|
extend ::Resque::Plugins::RetryOnLock
|
132
150
|
extend ::Resque::Plugins::RetryOnFail
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
8
|
+
- 2
|
9
|
+
version: 0.0.2
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Ryan Carver
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-04-
|
17
|
+
date: 2010-04-09 00:00:00 -07:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|