retry_upto 1.0 → 1.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/README.md +42 -19
- data/lib/retry_upto.rb +2 -52
- data/test/retry_upto_test.rb +35 -19
- metadata +44 -78
data/README.md
CHANGED
@@ -1,44 +1,67 @@
|
|
1
1
|
# retry_upto: retry with steroids
|
2
2
|
|
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 a bit** between the attempts to avoid external resources hiccups or usage limits.
|
5
|
+
|
6
|
+
Therefore **Your Important Code** ends surrounded by counters, conditions and calls to `sleep`.
|
7
|
+
|
8
|
+
This gem deals elegantly with this common scenario:
|
9
|
+
|
10
|
+
5.times.retry do
|
11
|
+
# Your Important Code
|
12
|
+
end
|
13
|
+
|
14
|
+
Keep reading to see all the options available.
|
15
|
+
|
3
16
|
## Usage
|
4
17
|
|
5
|
-
Basic usage
|
18
|
+
### Basic usage
|
6
19
|
|
7
|
-
|
20
|
+
Retries up to 5 times catching any exception, doesn't wait between attempts:
|
8
21
|
|
9
|
-
retry_upto(5)
|
22
|
+
retry_upto(5)
|
10
23
|
|
11
|
-
Waiting time between attempts
|
24
|
+
### Waiting time between attempts
|
12
25
|
|
13
|
-
|
26
|
+
Retries up to 5 times, waits 2 seconds between attempts:
|
14
27
|
|
15
|
-
|
28
|
+
retry_upto(5, :interval => 2)
|
16
29
|
|
17
|
-
Varying waiting time between attempts
|
30
|
+
### Varying waiting time between attempts
|
18
31
|
|
19
|
-
|
20
|
-
|
32
|
+
Retries up to 5 times, waits 1 second after the first attempt and increases
|
33
|
+
the time between the following attempts (2, 4, 8, ...):
|
21
34
|
|
22
|
-
retry_upto(5, :interval => 1, :growth => 2)
|
35
|
+
retry_upto(5, :interval => 1, :growth => 2)
|
23
36
|
|
24
|
-
|
25
|
-
|
37
|
+
Retries up to 5 times, waits 1 second after the first attempt and decreases
|
38
|
+
the time between the following attempts (0.5, 0.25, 0.125, ...):
|
26
39
|
|
27
|
-
retry_upto(5, :interval => 1, :growth => 0.5)
|
40
|
+
retry_upto(5, :interval => 1, :growth => 0.5)
|
28
41
|
|
29
|
-
|
30
|
-
|
42
|
+
Retries up to 5 times, waits 1 second after the first attempt and increases
|
43
|
+
randomly the time between the following attempts:
|
31
44
|
|
32
|
-
retry_upto(5, :interval => 1, :growth => lambda{ |x| x + rand(3) } )
|
45
|
+
retry_upto(5, :interval => 1, :growth => lambda{ |x| x + rand(3) } )
|
33
46
|
|
34
|
-
Retrying only when certain Exceptions get raised
|
47
|
+
### Retrying only when certain Exceptions get raised
|
35
48
|
|
36
|
-
|
49
|
+
Retries up to 5 times only after a ZeroDivisionError, raising any other Exception:
|
37
50
|
|
38
|
-
retry_upto(5, :rescue => ZeroDivisionError)
|
51
|
+
retry_upto(5, :rescue => ZeroDivisionError)
|
39
52
|
|
40
53
|
All the options described above can be combined together.
|
41
54
|
|
55
|
+
### More sugar!
|
56
|
+
|
57
|
+
In ruby 1.9, the `Enumerator` class gets enhanced to use `retry_upto` this way:
|
58
|
+
|
59
|
+
5.times.retry
|
60
|
+
|
61
|
+
And yes, this accepts the same options:
|
62
|
+
|
63
|
+
5.times.retry(:interval => 10)
|
64
|
+
|
42
65
|
## License
|
43
66
|
|
44
67
|
See the LICENSE file included in the distribution.
|
data/lib/retry_upto.rb
CHANGED
@@ -1,49 +1,8 @@
|
|
1
|
-
#
|
2
|
-
#
|
3
|
-
# Basic usage:
|
4
|
-
#
|
5
|
-
# - retries up to 5 times catching any exception, doesn't wait between attempts
|
6
|
-
#
|
7
|
-
# retry_upto(5) do ... end
|
8
|
-
#
|
9
|
-
#
|
10
|
-
# Waiting time between attempts:
|
11
|
-
#
|
12
|
-
# - retries up to 5 times, waits 2 seconds between attempts
|
13
|
-
#
|
14
|
-
# retry_upto(5, :interval => 2) do ... end
|
15
|
-
#
|
16
|
-
#
|
17
|
-
# Varying waiting time between attempts:
|
18
|
-
#
|
19
|
-
# - retries up to 5 times, waits 1 second after the first attempt and increases
|
20
|
-
# the time between the following attempts (2, 4, 8, ...)
|
21
|
-
#
|
22
|
-
# retry_upto(5, :interval => 1, :growth => 2) do ... end
|
23
|
-
#
|
24
|
-
# - retries up to 5 times, waits 1 second after the first attempt and decreases
|
25
|
-
# the time between the following attempts (0.5, 0.25, 0.125, ...)
|
26
|
-
#
|
27
|
-
# retry_upto(5, :interval => 1, :growth => 0.5) do ... end
|
28
|
-
#
|
29
|
-
# - retries up to 5 times, waits 1 second after the first attempt and increases
|
30
|
-
# randomly the time between the following attempts
|
31
|
-
#
|
32
|
-
# retry_upto(5, :interval => 1, :growth => lambda{ |x| x + rand(3) } ) do ... end
|
33
|
-
#
|
34
|
-
#
|
35
|
-
# Retrying only when certain Exceptions get raised:
|
36
|
-
#
|
37
|
-
# - retries up to 5 times only after a ZeroDivisionError, raising any other Exception
|
38
|
-
#
|
39
|
-
# retry_upto(5, :rescue => ZeroDivisionError) do ... end
|
40
|
-
#
|
41
|
-
#
|
42
|
-
# All the described options can be combined together.
|
1
|
+
# See README.md for usage explanations
|
43
2
|
|
44
3
|
def retry_upto(max_retries = 1, options = {})
|
45
4
|
yield
|
46
|
-
rescue (options[:rescue] || Exception)
|
5
|
+
rescue *(options[:rescue] || Exception)
|
47
6
|
raise if (max_retries -= 1) == 0
|
48
7
|
sleep(options[:interval] || 0)
|
49
8
|
if options[:growth].respond_to?('*')
|
@@ -54,15 +13,6 @@ rescue (options[:rescue] || Exception)
|
|
54
13
|
retry
|
55
14
|
end
|
56
15
|
|
57
|
-
|
58
|
-
|
59
|
-
# Extends enumerator to allow usage like:
|
60
|
-
#
|
61
|
-
# 5.times.retry do
|
62
|
-
# ...
|
63
|
-
# end
|
64
|
-
#
|
65
|
-
|
66
16
|
class Enumerator
|
67
17
|
def retry(options = {}, &blk)
|
68
18
|
retry_upto(self.count, options, &blk)
|
data/test/retry_upto_test.rb
CHANGED
@@ -3,15 +3,25 @@ require './test/test_helper'
|
|
3
3
|
class Retry_uptoTest < MiniTest::Unit::TestCase
|
4
4
|
|
5
5
|
class FooError < Exception; end
|
6
|
+
class BarError < Exception; end
|
6
7
|
|
7
|
-
# raises ZeroDivisionError in the two first hits
|
8
8
|
class Target
|
9
|
-
attr_accessor :
|
10
|
-
def initialize
|
9
|
+
attr_accessor :foos, :bars
|
10
|
+
def initialize
|
11
|
+
@foos = 0
|
12
|
+
@bars = 0
|
13
|
+
end
|
14
|
+
|
15
|
+
# raises FooError only in the two first calls
|
16
|
+
def foo!
|
17
|
+
@foos += 1
|
18
|
+
raise FooError if @foos < 3
|
19
|
+
end
|
11
20
|
|
12
|
-
|
13
|
-
|
14
|
-
|
21
|
+
# raises BarError only in the two first calls
|
22
|
+
def bar!
|
23
|
+
@bars += 1
|
24
|
+
raise BarError if @bars < 3
|
15
25
|
end
|
16
26
|
end
|
17
27
|
|
@@ -23,26 +33,26 @@ class Retry_uptoTest < MiniTest::Unit::TestCase
|
|
23
33
|
|
24
34
|
def test_retries_one_time_by_default_without_capturing_the_exception
|
25
35
|
assert_raises(FooError) do
|
26
|
-
retry_upto{ @target.
|
36
|
+
retry_upto{ @target.foo! }
|
27
37
|
end
|
28
|
-
assert_equal 1, @target.
|
38
|
+
assert_equal 1, @target.foos
|
29
39
|
end
|
30
40
|
|
31
41
|
def test_retries_the_desired_number_of_attempts
|
32
|
-
retry_upto(3){ @target.
|
33
|
-
assert_equal 3, @target.
|
42
|
+
retry_upto(3){ @target.foo! }
|
43
|
+
assert_equal 3, @target.foos
|
34
44
|
end
|
35
45
|
|
36
46
|
# interval between attempts
|
37
47
|
|
38
48
|
def test_there_is_no_interval_between_attempts_by_default
|
39
49
|
self.expects(:sleep).times(2).with(0).returns(nil)
|
40
|
-
retry_upto(3){ @target.
|
50
|
+
retry_upto(3){ @target.foo! }
|
41
51
|
end
|
42
52
|
|
43
53
|
def test_interval_between_attempts_can_be_customized
|
44
54
|
self.expects(:sleep).times(2).with(5).returns(nil)
|
45
|
-
retry_upto(3, :interval => 5){ @target.
|
55
|
+
retry_upto(3, :interval => 5){ @target.foo! }
|
46
56
|
end
|
47
57
|
|
48
58
|
# interval growth between attempts
|
@@ -50,42 +60,48 @@ class Retry_uptoTest < MiniTest::Unit::TestCase
|
|
50
60
|
def test_inverval_can_be_multiplied_by_an_integer_growth
|
51
61
|
self.expects(:sleep).times(1).with(5)
|
52
62
|
self.expects(:sleep).times(1).with(15)
|
53
|
-
retry_upto(3, :interval => 5, :growth => 3){ @target.
|
63
|
+
retry_upto(3, :interval => 5, :growth => 3){ @target.foo! }
|
54
64
|
end
|
55
65
|
|
56
66
|
def test_grow_for_inverval_between_attempts_can_be_defined_with_a_lambda
|
57
67
|
self.expects(:sleep).times(1).with(5)
|
58
68
|
self.expects(:sleep).times(1).with(7)
|
59
|
-
retry_upto(3, :interval => 5, :growth => lambda{ |t| t + 2 }){ @target.
|
69
|
+
retry_upto(3, :interval => 5, :growth => lambda{ |t| t + 2 }){ @target.foo! }
|
60
70
|
end
|
61
71
|
|
62
72
|
# exceptions
|
63
73
|
|
64
74
|
def test_by_default_any_exception_gets_captured_if_there_are_attempts_left
|
65
|
-
retry_upto(3){ @target.
|
75
|
+
retry_upto(3){ @target.foo! }
|
66
76
|
assert true # if we reach this no exception was raised out of retry_upto
|
67
77
|
end
|
68
78
|
|
69
79
|
def test_the_last_attempt_does_not_capture_the_exception
|
70
80
|
assert_raises(FooError) do
|
71
|
-
retry_upto(2){ @target.
|
81
|
+
retry_upto(2){ @target.foo! }
|
72
82
|
end
|
73
83
|
end
|
74
84
|
|
75
85
|
def test_a_specified_exception_will_be_captured_between_attempts
|
76
|
-
retry_upto(3, :rescue => FooError){ @target.
|
86
|
+
retry_upto(3, :rescue => FooError){ @target.foo! }
|
87
|
+
assert true # if we reach this no exception was raised out of retry_upto
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_several_specified_exceptions_will_be_captured_between_attempts
|
91
|
+
retry_upto(3, :rescue => [FooError, BarError]){ @target.foo! }
|
92
|
+
retry_upto(3, :rescue => [FooError, BarError]){ @target.bar! }
|
77
93
|
assert true # if we reach this no exception was raised out of retry_upto
|
78
94
|
end
|
79
95
|
|
80
96
|
def test_the_last_attempt_does_not_capture_the_specified_exception
|
81
97
|
assert_raises(FooError) do
|
82
|
-
retry_upto(2, :rescue => FooError){ @target.
|
98
|
+
retry_upto(2, :rescue => FooError){ @target.foo! }
|
83
99
|
end
|
84
100
|
end
|
85
101
|
|
86
102
|
def test_a_exception_different_from_the_specified_one_will_not_be_captured_between_attempts
|
87
103
|
assert_raises(FooError) do
|
88
|
-
retry_upto(3, :rescue => ZeroDivisionError){ @target.
|
104
|
+
retry_upto(3, :rescue => ZeroDivisionError){ @target.foo! }
|
89
105
|
end
|
90
106
|
end
|
91
107
|
|
metadata
CHANGED
@@ -1,84 +1,61 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: retry_upto
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '1.1'
|
5
5
|
prerelease:
|
6
|
-
segments:
|
7
|
-
- 1
|
8
|
-
- 0
|
9
|
-
version: "1.0"
|
10
6
|
platform: ruby
|
11
|
-
authors:
|
7
|
+
authors:
|
12
8
|
- Raul Murciano
|
13
9
|
- Glenn Gillen
|
14
10
|
- Pedro Belo
|
15
11
|
- Jaime Iniesta
|
16
|
-
-
|
17
|
-
-
|
12
|
+
- Lleïr Borras
|
13
|
+
- Aitor García Rey
|
18
14
|
autorequire:
|
19
15
|
bindir: bin
|
20
16
|
cert_chain: []
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
dependencies:
|
25
|
-
- !ruby/object:Gem::Dependency
|
17
|
+
date: 2011-10-08 00:00:00.000000000Z
|
18
|
+
dependencies:
|
19
|
+
- !ruby/object:Gem::Dependency
|
26
20
|
name: minitest
|
27
|
-
|
28
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
21
|
+
requirement: &2153033700 !ruby/object:Gem::Requirement
|
29
22
|
none: false
|
30
|
-
requirements:
|
31
|
-
- -
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
|
34
|
-
segments:
|
35
|
-
- 2
|
36
|
-
- 0
|
37
|
-
version: "2.0"
|
23
|
+
requirements:
|
24
|
+
- - ! '>'
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.0'
|
38
27
|
type: :development
|
39
|
-
version_requirements: *id001
|
40
|
-
- !ruby/object:Gem::Dependency
|
41
|
-
name: mocha
|
42
28
|
prerelease: false
|
43
|
-
|
29
|
+
version_requirements: *2153033700
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: mocha
|
32
|
+
requirement: &2153033220 !ruby/object:Gem::Requirement
|
44
33
|
none: false
|
45
|
-
requirements:
|
46
|
-
- -
|
47
|
-
- !ruby/object:Gem::Version
|
48
|
-
hash: 55
|
49
|
-
segments:
|
50
|
-
- 0
|
51
|
-
- 10
|
52
|
-
- 0
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
53
37
|
version: 0.10.0
|
54
38
|
type: :development
|
55
|
-
version_requirements: *id002
|
56
|
-
- !ruby/object:Gem::Dependency
|
57
|
-
name: rake
|
58
39
|
prerelease: false
|
59
|
-
|
40
|
+
version_requirements: *2153033220
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: &2153032760 !ruby/object:Gem::Requirement
|
60
44
|
none: false
|
61
|
-
requirements:
|
62
|
-
- -
|
63
|
-
- !ruby/object:Gem::Version
|
64
|
-
hash: 63
|
65
|
-
segments:
|
66
|
-
- 0
|
67
|
-
- 9
|
68
|
-
- 2
|
45
|
+
requirements:
|
46
|
+
- - ! '>='
|
47
|
+
- !ruby/object:Gem::Version
|
69
48
|
version: 0.9.2
|
70
49
|
type: :development
|
71
|
-
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: *2153032760
|
72
52
|
description: adds some useful options to retry code blocks
|
73
|
-
email:
|
53
|
+
email:
|
74
54
|
- raul@murciano.net
|
75
55
|
executables: []
|
76
|
-
|
77
56
|
extensions: []
|
78
|
-
|
79
57
|
extra_rdoc_files: []
|
80
|
-
|
81
|
-
files:
|
58
|
+
files:
|
82
59
|
- lib/retry_upto.rb
|
83
60
|
- test/retry_upto_test.rb
|
84
61
|
- test/test_helper.rb
|
@@ -87,39 +64,28 @@ files:
|
|
87
64
|
- LICENSE
|
88
65
|
- RakeFile
|
89
66
|
- README.md
|
90
|
-
has_rdoc: true
|
91
67
|
homepage: http://github.com/raul/retry_upto
|
92
68
|
licenses: []
|
93
|
-
|
94
69
|
post_install_message:
|
95
70
|
rdoc_options: []
|
96
|
-
|
97
|
-
require_paths:
|
71
|
+
require_paths:
|
98
72
|
- lib
|
99
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
73
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
100
74
|
none: false
|
101
|
-
requirements:
|
102
|
-
- -
|
103
|
-
- !ruby/object:Gem::Version
|
104
|
-
|
105
|
-
|
106
|
-
- 0
|
107
|
-
version: "0"
|
108
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
75
|
+
requirements:
|
76
|
+
- - ! '>='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
109
80
|
none: false
|
110
|
-
requirements:
|
111
|
-
- -
|
112
|
-
- !ruby/object:Gem::Version
|
113
|
-
|
114
|
-
segments:
|
115
|
-
- 0
|
116
|
-
version: "0"
|
81
|
+
requirements:
|
82
|
+
- - ! '>='
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
117
85
|
requirements: []
|
118
|
-
|
119
86
|
rubyforge_project: retry_upto
|
120
|
-
rubygems_version: 1.
|
87
|
+
rubygems_version: 1.8.10
|
121
88
|
signing_key:
|
122
89
|
specification_version: 3
|
123
90
|
summary: retry with steroids
|
124
91
|
test_files: []
|
125
|
-
|