resque-lock-retry 0.0.1 → 0.0.2
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/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
|