retry_upto 1.1 → 1.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.md +20 -20
- data/lib/retry_upto.rb +9 -10
- data/test/retry_upto_test.rb +23 -30
- metadata +8 -8
data/README.md
CHANGED
@@ -1,12 +1,18 @@
|
|
1
1
|
# retry_upto: retry with steroids
|
2
2
|
|
3
3
|
If you need to use `retry` in ruby, you probably want to retry some code only a **maximum number of times**,
|
4
|
-
and sometimes **wait
|
4
|
+
and sometimes **wait an interval of time** between the attempts to avoid external resources hiccups or usage limits.
|
5
5
|
|
6
6
|
Therefore **Your Important Code** ends surrounded by counters, conditions and calls to `sleep`.
|
7
7
|
|
8
8
|
This gem deals elegantly with this common scenario:
|
9
9
|
|
10
|
+
retry_upto(5) do
|
11
|
+
# Your Important Code
|
12
|
+
end
|
13
|
+
|
14
|
+
Under Ruby 1.9 it also allows:
|
15
|
+
|
10
16
|
5.times.retry do
|
11
17
|
# Your Important Code
|
12
18
|
end
|
@@ -21,28 +27,18 @@ Retries up to 5 times catching any exception, doesn't wait between attempts:
|
|
21
27
|
|
22
28
|
retry_upto(5)
|
23
29
|
|
24
|
-
###
|
30
|
+
### Time intervals between attempts
|
25
31
|
|
26
|
-
|
32
|
+
For fixed intervals, an `:interval` parameter can be passed indicating the time in seconds.
|
33
|
+
The following example will sleep two seconds between attempts:
|
27
34
|
|
28
35
|
retry_upto(5, :interval => 2)
|
29
36
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
the time between the following attempts (2, 4, 8, ...):
|
34
|
-
|
35
|
-
retry_upto(5, :interval => 1, :growth => 2)
|
37
|
+
For customized intervals, the `:interval` parameter can be a lambda, which will be applied
|
38
|
+
to the number of each attempt. For instance, the following code will sleep 3 seconds after
|
39
|
+
the first attempt, 6 after the second, 9 after the third...
|
36
40
|
|
37
|
-
|
38
|
-
the time between the following attempts (0.5, 0.25, 0.125, ...):
|
39
|
-
|
40
|
-
retry_upto(5, :interval => 1, :growth => 0.5)
|
41
|
-
|
42
|
-
Retries up to 5 times, waits 1 second after the first attempt and increases
|
43
|
-
randomly the time between the following attempts:
|
44
|
-
|
45
|
-
retry_upto(5, :interval => 1, :growth => lambda{ |x| x + rand(3) } )
|
41
|
+
retry_upto(5, :interval => lambda{ |attempt| attempt * 3 })
|
46
42
|
|
47
43
|
### Retrying only when certain Exceptions get raised
|
48
44
|
|
@@ -50,6 +46,10 @@ Retries up to 5 times only after a ZeroDivisionError, raising any other Exceptio
|
|
50
46
|
|
51
47
|
retry_upto(5, :rescue => ZeroDivisionError)
|
52
48
|
|
49
|
+
Retries up to 5 times only after a ZeroDivisionError or a NameError, raising any other Exception:
|
50
|
+
|
51
|
+
retry_upto(5, :rescue => [ZeroDivisionError, NameError])
|
52
|
+
|
53
53
|
All the options described above can be combined together.
|
54
54
|
|
55
55
|
### More sugar!
|
@@ -58,7 +58,7 @@ In ruby 1.9, the `Enumerator` class gets enhanced to use `retry_upto` this way:
|
|
58
58
|
|
59
59
|
5.times.retry
|
60
60
|
|
61
|
-
|
61
|
+
This syntax accepts the same options:
|
62
62
|
|
63
63
|
5.times.retry(:interval => 10)
|
64
64
|
|
@@ -68,7 +68,7 @@ See the LICENSE file included in the distribution.
|
|
68
68
|
|
69
69
|
## Authors
|
70
70
|
|
71
|
-
This gem was born from gists by Raul Murciano, Glenn Gillen, Pedro Belo, Jaime Iniesta, Lleïr Borras and ideas taken from Aitor García Rey.
|
71
|
+
This gem was born from gists by Raul Murciano, Glenn Gillen, Pedro Belo, Jaime Iniesta, Lleïr Borras and ideas taken from Aitor García Rey and Jim Remsik.
|
72
72
|
|
73
73
|
Yes, so many brain cells and so few lines of code. Great, isn't it?
|
74
74
|
|
data/lib/retry_upto.rb
CHANGED
@@ -1,20 +1,19 @@
|
|
1
1
|
# See README.md for usage explanations
|
2
2
|
|
3
|
-
def retry_upto(max_retries = 1,
|
3
|
+
def retry_upto(max_retries = 1, opts = {})
|
4
4
|
yield
|
5
|
-
rescue *(
|
6
|
-
|
7
|
-
|
8
|
-
if
|
9
|
-
|
10
|
-
|
11
|
-
options[:interval] = options[:growth].call(options[:interval])
|
5
|
+
rescue *(opts[:rescue] || Exception)
|
6
|
+
attempt = attempt ? attempt+1 : 1
|
7
|
+
raise if (attempt == max_retries)
|
8
|
+
if interval = opts[:interval]
|
9
|
+
secs = interval.respond_to?(:call) ? interval.call(attempt) : interval
|
10
|
+
sleep(secs)
|
12
11
|
end
|
13
12
|
retry
|
14
13
|
end
|
15
14
|
|
16
15
|
class Enumerator
|
17
|
-
def retry(
|
18
|
-
retry_upto(self.count,
|
16
|
+
def retry(opts = {}, &blk)
|
17
|
+
retry_upto(self.count, opts, &blk)
|
19
18
|
end
|
20
19
|
end
|
data/test/retry_upto_test.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require './test/test_helper'
|
2
2
|
|
3
|
-
class
|
3
|
+
class RetryUptoTest < MiniTest::Unit::TestCase
|
4
4
|
|
5
5
|
class FooError < Exception; end
|
6
6
|
class BarError < Exception; end
|
@@ -12,16 +12,16 @@ class Retry_uptoTest < MiniTest::Unit::TestCase
|
|
12
12
|
@bars = 0
|
13
13
|
end
|
14
14
|
|
15
|
-
# raises FooError only in the
|
15
|
+
# raises FooError only in the 3 first calls
|
16
16
|
def foo!
|
17
17
|
@foos += 1
|
18
|
-
raise FooError if @foos <
|
18
|
+
raise FooError if @foos < 4
|
19
19
|
end
|
20
20
|
|
21
|
-
# raises BarError only in the
|
21
|
+
# raises BarError only in the 3 first calls
|
22
22
|
def bar!
|
23
23
|
@bars += 1
|
24
|
-
raise BarError if @bars <
|
24
|
+
raise BarError if @bars < 4
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
@@ -39,69 +39,62 @@ class Retry_uptoTest < MiniTest::Unit::TestCase
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def test_retries_the_desired_number_of_attempts
|
42
|
-
retry_upto(
|
43
|
-
assert_equal
|
42
|
+
retry_upto(4){ @target.foo! }
|
43
|
+
assert_equal 4, @target.foos
|
44
44
|
end
|
45
45
|
|
46
46
|
# interval between attempts
|
47
47
|
|
48
48
|
def test_there_is_no_interval_between_attempts_by_default
|
49
|
-
self.expects(:sleep).
|
50
|
-
retry_upto(
|
49
|
+
self.expects(:sleep).never
|
50
|
+
retry_upto(4){ @target.foo! }
|
51
51
|
end
|
52
52
|
|
53
53
|
def test_interval_between_attempts_can_be_customized
|
54
|
-
self.expects(:sleep).times(
|
55
|
-
retry_upto(
|
54
|
+
self.expects(:sleep).times(3).with(5).returns(nil)
|
55
|
+
retry_upto(4, :interval => 5){ @target.foo! }
|
56
56
|
end
|
57
57
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
self.expects(:sleep).times(1).with(
|
62
|
-
|
63
|
-
retry_upto(3, :interval => 5, :growth => 3){ @target.foo! }
|
64
|
-
end
|
65
|
-
|
66
|
-
def test_grow_for_inverval_between_attempts_can_be_defined_with_a_lambda
|
67
|
-
self.expects(:sleep).times(1).with(5)
|
68
|
-
self.expects(:sleep).times(1).with(7)
|
69
|
-
retry_upto(3, :interval => 5, :growth => lambda{ |t| t + 2 }){ @target.foo! }
|
58
|
+
def test_different_intervals_can_be_defined_with_a_lambda
|
59
|
+
self.expects(:sleep).times(1).with(3)
|
60
|
+
self.expects(:sleep).times(1).with(6)
|
61
|
+
self.expects(:sleep).times(1).with(9)
|
62
|
+
retry_upto(4, :interval => lambda{ |attempt| attempt * 3 }){ @target.foo! }
|
70
63
|
end
|
71
64
|
|
72
65
|
# exceptions
|
73
66
|
|
74
67
|
def test_by_default_any_exception_gets_captured_if_there_are_attempts_left
|
75
|
-
retry_upto(
|
68
|
+
retry_upto(4){ @target.foo! }
|
76
69
|
assert true # if we reach this no exception was raised out of retry_upto
|
77
70
|
end
|
78
71
|
|
79
72
|
def test_the_last_attempt_does_not_capture_the_exception
|
80
73
|
assert_raises(FooError) do
|
81
|
-
retry_upto(
|
74
|
+
retry_upto(3){ @target.foo! }
|
82
75
|
end
|
83
76
|
end
|
84
77
|
|
85
78
|
def test_a_specified_exception_will_be_captured_between_attempts
|
86
|
-
retry_upto(
|
79
|
+
retry_upto(4, :rescue => FooError){ @target.foo! }
|
87
80
|
assert true # if we reach this no exception was raised out of retry_upto
|
88
81
|
end
|
89
82
|
|
90
83
|
def test_several_specified_exceptions_will_be_captured_between_attempts
|
91
|
-
retry_upto(
|
92
|
-
retry_upto(
|
84
|
+
retry_upto(4, :rescue => [FooError, BarError]){ @target.foo! }
|
85
|
+
retry_upto(4, :rescue => [FooError, BarError]){ @target.bar! }
|
93
86
|
assert true # if we reach this no exception was raised out of retry_upto
|
94
87
|
end
|
95
88
|
|
96
89
|
def test_the_last_attempt_does_not_capture_the_specified_exception
|
97
90
|
assert_raises(FooError) do
|
98
|
-
retry_upto(
|
91
|
+
retry_upto(3, :rescue => FooError){ @target.foo! }
|
99
92
|
end
|
100
93
|
end
|
101
94
|
|
102
95
|
def test_a_exception_different_from_the_specified_one_will_not_be_captured_between_attempts
|
103
96
|
assert_raises(FooError) do
|
104
|
-
retry_upto(
|
97
|
+
retry_upto(4, :rescue => ZeroDivisionError){ @target.foo! }
|
105
98
|
end
|
106
99
|
end
|
107
100
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: retry_upto
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '1.
|
4
|
+
version: '1.2'
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -14,11 +14,11 @@ authors:
|
|
14
14
|
autorequire:
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
|
-
date: 2011-10-
|
17
|
+
date: 2011-10-10 00:00:00.000000000Z
|
18
18
|
dependencies:
|
19
19
|
- !ruby/object:Gem::Dependency
|
20
20
|
name: minitest
|
21
|
-
requirement: &
|
21
|
+
requirement: &2153491260 !ruby/object:Gem::Requirement
|
22
22
|
none: false
|
23
23
|
requirements:
|
24
24
|
- - ! '>'
|
@@ -26,10 +26,10 @@ dependencies:
|
|
26
26
|
version: '2.0'
|
27
27
|
type: :development
|
28
28
|
prerelease: false
|
29
|
-
version_requirements: *
|
29
|
+
version_requirements: *2153491260
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
name: mocha
|
32
|
-
requirement: &
|
32
|
+
requirement: &2153490760 !ruby/object:Gem::Requirement
|
33
33
|
none: false
|
34
34
|
requirements:
|
35
35
|
- - ! '>='
|
@@ -37,10 +37,10 @@ dependencies:
|
|
37
37
|
version: 0.10.0
|
38
38
|
type: :development
|
39
39
|
prerelease: false
|
40
|
-
version_requirements: *
|
40
|
+
version_requirements: *2153490760
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rake
|
43
|
-
requirement: &
|
43
|
+
requirement: &2153490260 !ruby/object:Gem::Requirement
|
44
44
|
none: false
|
45
45
|
requirements:
|
46
46
|
- - ! '>='
|
@@ -48,7 +48,7 @@ dependencies:
|
|
48
48
|
version: 0.9.2
|
49
49
|
type: :development
|
50
50
|
prerelease: false
|
51
|
-
version_requirements: *
|
51
|
+
version_requirements: *2153490260
|
52
52
|
description: adds some useful options to retry code blocks
|
53
53
|
email:
|
54
54
|
- raul@murciano.net
|