retry_upto 1.0
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/Changelog.md +5 -0
- data/Gemfile +3 -0
- data/LICENSE +21 -0
- data/README.md +51 -0
- data/RakeFile +11 -0
- data/lib/retry_upto.rb +70 -0
- data/test/retry_upto_test.rb +92 -0
- data/test/test_helper.rb +4 -0
- metadata +125 -0
data/Changelog.md
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) 2011 Raul Murciano, Glenn Gillen, Pedro Belo,
|
2
|
+
Jaime Iniesta, Lleïr Borras and Aitor García Rey.
|
3
|
+
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
a copy of this software and associated documentation files (the
|
6
|
+
"Software"), to deal in the Software without restriction, including
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# retry_upto: retry with steroids
|
2
|
+
|
3
|
+
## Usage
|
4
|
+
|
5
|
+
Basic usage
|
6
|
+
|
7
|
+
- retries up to 5 times catching any exception, doesn't wait between attempts:
|
8
|
+
|
9
|
+
retry_upto(5) do ... end
|
10
|
+
|
11
|
+
Waiting time between attempts
|
12
|
+
|
13
|
+
- retries up to 5 times, waits 2 seconds between attempts:
|
14
|
+
|
15
|
+
retry_upto(5, :interval => 2) do ... end
|
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
|
+
Retrying only when certain Exceptions get raised
|
35
|
+
|
36
|
+
- retries up to 5 times only after a ZeroDivisionError, raising any other Exception:
|
37
|
+
|
38
|
+
retry_upto(5, :rescue => ZeroDivisionError) do ... end
|
39
|
+
|
40
|
+
All the options described above can be combined together.
|
41
|
+
|
42
|
+
## License
|
43
|
+
|
44
|
+
See the LICENSE file included in the distribution.
|
45
|
+
|
46
|
+
## Authors
|
47
|
+
|
48
|
+
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.
|
49
|
+
|
50
|
+
Yes, so many brain cells and so few lines of code. Great, isn't it?
|
51
|
+
|
data/RakeFile
ADDED
data/lib/retry_upto.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
# retry with steroids
|
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.
|
43
|
+
|
44
|
+
def retry_upto(max_retries = 1, options = {})
|
45
|
+
yield
|
46
|
+
rescue (options[:rescue] || Exception)
|
47
|
+
raise if (max_retries -= 1) == 0
|
48
|
+
sleep(options[:interval] || 0)
|
49
|
+
if options[:growth].respond_to?('*')
|
50
|
+
options[:interval] = options[:interval] * options[:growth]
|
51
|
+
elsif options[:growth].respond_to?(:call)
|
52
|
+
options[:interval] = options[:growth].call(options[:interval])
|
53
|
+
end
|
54
|
+
retry
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
|
59
|
+
# Extends enumerator to allow usage like:
|
60
|
+
#
|
61
|
+
# 5.times.retry do
|
62
|
+
# ...
|
63
|
+
# end
|
64
|
+
#
|
65
|
+
|
66
|
+
class Enumerator
|
67
|
+
def retry(options = {}, &blk)
|
68
|
+
retry_upto(self.count, options, &blk)
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require './test/test_helper'
|
2
|
+
|
3
|
+
class Retry_uptoTest < MiniTest::Unit::TestCase
|
4
|
+
|
5
|
+
class FooError < Exception; end
|
6
|
+
|
7
|
+
# raises ZeroDivisionError in the two first hits
|
8
|
+
class Target
|
9
|
+
attr_accessor :hits
|
10
|
+
def initialize; @hits = 0; end
|
11
|
+
|
12
|
+
def hit!
|
13
|
+
@hits += 1
|
14
|
+
raise FooError if @hits < 3
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def setup
|
19
|
+
@target = Target.new
|
20
|
+
end
|
21
|
+
|
22
|
+
# number of attempts
|
23
|
+
|
24
|
+
def test_retries_one_time_by_default_without_capturing_the_exception
|
25
|
+
assert_raises(FooError) do
|
26
|
+
retry_upto{ @target.hit! }
|
27
|
+
end
|
28
|
+
assert_equal 1, @target.hits
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_retries_the_desired_number_of_attempts
|
32
|
+
retry_upto(3){ @target.hit! }
|
33
|
+
assert_equal 3, @target.hits
|
34
|
+
end
|
35
|
+
|
36
|
+
# interval between attempts
|
37
|
+
|
38
|
+
def test_there_is_no_interval_between_attempts_by_default
|
39
|
+
self.expects(:sleep).times(2).with(0).returns(nil)
|
40
|
+
retry_upto(3){ @target.hit! }
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_interval_between_attempts_can_be_customized
|
44
|
+
self.expects(:sleep).times(2).with(5).returns(nil)
|
45
|
+
retry_upto(3, :interval => 5){ @target.hit! }
|
46
|
+
end
|
47
|
+
|
48
|
+
# interval growth between attempts
|
49
|
+
|
50
|
+
def test_inverval_can_be_multiplied_by_an_integer_growth
|
51
|
+
self.expects(:sleep).times(1).with(5)
|
52
|
+
self.expects(:sleep).times(1).with(15)
|
53
|
+
retry_upto(3, :interval => 5, :growth => 3){ @target.hit! }
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_grow_for_inverval_between_attempts_can_be_defined_with_a_lambda
|
57
|
+
self.expects(:sleep).times(1).with(5)
|
58
|
+
self.expects(:sleep).times(1).with(7)
|
59
|
+
retry_upto(3, :interval => 5, :growth => lambda{ |t| t + 2 }){ @target.hit! }
|
60
|
+
end
|
61
|
+
|
62
|
+
# exceptions
|
63
|
+
|
64
|
+
def test_by_default_any_exception_gets_captured_if_there_are_attempts_left
|
65
|
+
retry_upto(3){ @target.hit! }
|
66
|
+
assert true # if we reach this no exception was raised out of retry_upto
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_the_last_attempt_does_not_capture_the_exception
|
70
|
+
assert_raises(FooError) do
|
71
|
+
retry_upto(2){ @target.hit! }
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_a_specified_exception_will_be_captured_between_attempts
|
76
|
+
retry_upto(3, :rescue => FooError){ @target.hit! }
|
77
|
+
assert true # if we reach this no exception was raised out of retry_upto
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_the_last_attempt_does_not_capture_the_specified_exception
|
81
|
+
assert_raises(FooError) do
|
82
|
+
retry_upto(2, :rescue => FooError){ @target.hit! }
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_a_exception_different_from_the_specified_one_will_not_be_captured_between_attempts
|
87
|
+
assert_raises(FooError) do
|
88
|
+
retry_upto(3, :rescue => ZeroDivisionError){ @target.hit! }
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: retry_upto
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 15
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
version: "1.0"
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Raul Murciano
|
13
|
+
- Glenn Gillen
|
14
|
+
- Pedro Belo
|
15
|
+
- Jaime Iniesta
|
16
|
+
- "Lle\xC3\xAFr Borras"
|
17
|
+
- "Aitor Garc\xC3\xADa Rey"
|
18
|
+
autorequire:
|
19
|
+
bindir: bin
|
20
|
+
cert_chain: []
|
21
|
+
|
22
|
+
date: 2011-10-07 00:00:00 -07:00
|
23
|
+
default_executable:
|
24
|
+
dependencies:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: minitest
|
27
|
+
prerelease: false
|
28
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ">"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
hash: 3
|
34
|
+
segments:
|
35
|
+
- 2
|
36
|
+
- 0
|
37
|
+
version: "2.0"
|
38
|
+
type: :development
|
39
|
+
version_requirements: *id001
|
40
|
+
- !ruby/object:Gem::Dependency
|
41
|
+
name: mocha
|
42
|
+
prerelease: false
|
43
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
44
|
+
none: false
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
hash: 55
|
49
|
+
segments:
|
50
|
+
- 0
|
51
|
+
- 10
|
52
|
+
- 0
|
53
|
+
version: 0.10.0
|
54
|
+
type: :development
|
55
|
+
version_requirements: *id002
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: rake
|
58
|
+
prerelease: false
|
59
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
60
|
+
none: false
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
hash: 63
|
65
|
+
segments:
|
66
|
+
- 0
|
67
|
+
- 9
|
68
|
+
- 2
|
69
|
+
version: 0.9.2
|
70
|
+
type: :development
|
71
|
+
version_requirements: *id003
|
72
|
+
description: adds some useful options to retry code blocks
|
73
|
+
email:
|
74
|
+
- raul@murciano.net
|
75
|
+
executables: []
|
76
|
+
|
77
|
+
extensions: []
|
78
|
+
|
79
|
+
extra_rdoc_files: []
|
80
|
+
|
81
|
+
files:
|
82
|
+
- lib/retry_upto.rb
|
83
|
+
- test/retry_upto_test.rb
|
84
|
+
- test/test_helper.rb
|
85
|
+
- Changelog.md
|
86
|
+
- Gemfile
|
87
|
+
- LICENSE
|
88
|
+
- RakeFile
|
89
|
+
- README.md
|
90
|
+
has_rdoc: true
|
91
|
+
homepage: http://github.com/raul/retry_upto
|
92
|
+
licenses: []
|
93
|
+
|
94
|
+
post_install_message:
|
95
|
+
rdoc_options: []
|
96
|
+
|
97
|
+
require_paths:
|
98
|
+
- lib
|
99
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
100
|
+
none: false
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
hash: 3
|
105
|
+
segments:
|
106
|
+
- 0
|
107
|
+
version: "0"
|
108
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
109
|
+
none: false
|
110
|
+
requirements:
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
hash: 3
|
114
|
+
segments:
|
115
|
+
- 0
|
116
|
+
version: "0"
|
117
|
+
requirements: []
|
118
|
+
|
119
|
+
rubyforge_project: retry_upto
|
120
|
+
rubygems_version: 1.5.2
|
121
|
+
signing_key:
|
122
|
+
specification_version: 3
|
123
|
+
summary: retry with steroids
|
124
|
+
test_files: []
|
125
|
+
|