Permalink
Browse files

v1.2: enhanced :interval parameter, :growth is now deprecated

  • Loading branch information...
1 parent b29ff90 commit cf50b7c02b61bba2b234e5db4fcc52a9d5214a36 @raul committed Oct 10, 2011
Showing with 32 additions and 46 deletions.
  1. +16 −20 README.md
  2. +9 −10 lib/retry_upto.rb
  3. +1 −1 retry_upto.gemspec
  4. +6 −15 test/retry_upto_test.rb
View
@@ -1,12 +1,18 @@
# retry_upto: retry with steroids
If you need to use `retry` in ruby, you probably want to retry some code only a **maximum number of times**,
-and sometimes **wait a bit** between the attempts to avoid external resources hiccups or usage limits.
+and sometimes **wait an interval of time** between the attempts to avoid external resources hiccups or usage limits.
Therefore **Your Important Code** ends surrounded by counters, conditions and calls to `sleep`.
This gem deals elegantly with this common scenario:
+ retry_upto(5) do
+ # Your Important Code
+ end
+
+Under Ruby 1.9 it also allows:
+
5.times.retry do
# Your Important Code
end
@@ -21,28 +27,18 @@ Retries up to 5 times catching any exception, doesn't wait between attempts:
retry_upto(5)
-### Waiting time between attempts
+### Time intervals between attempts
-Retries up to 5 times, waits 2 seconds between attempts:
+For fixed intervals, an `:interval` parameter can be passed indicating the time in seconds.
+The following example will sleep two seconds between attempts:
retry_upto(5, :interval => 2)
-### Varying waiting time between attempts
-
-Retries up to 5 times, waits 1 second after the first attempt and increases
-the time between the following attempts (2, 4, 8, ...):
-
- retry_upto(5, :interval => 1, :growth => 2)
-
-Retries up to 5 times, waits 1 second after the first attempt and decreases
-the time between the following attempts (0.5, 0.25, 0.125, ...):
-
- retry_upto(5, :interval => 1, :growth => 0.5)
-
-Retries up to 5 times, waits 1 second after the first attempt and increases
-randomly the time between the following attempts:
+For customized intervals, the `:interval` parameter can be a lambda, which will be applied
+to the number of each attempt. For instance, the following code will sleep 3 seconds after
+the first attempt, 6 after the second, 9 after the third...
- retry_upto(5, :interval => 1, :growth => lambda{ |x| x + rand(3) } )
+ retry_upto(5, :interval => lambda{ |attempt| attempt * 3 })
### Retrying only when certain Exceptions get raised
@@ -62,7 +58,7 @@ In ruby 1.9, the `Enumerator` class gets enhanced to use `retry_upto` this way:
5.times.retry
-And yes, this accepts the same options:
+This syntax accepts the same options:
5.times.retry(:interval => 10)
@@ -72,7 +68,7 @@ See the LICENSE file included in the distribution.
## Authors
-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.
+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.
Yes, so many brain cells and so few lines of code. Great, isn't it?
View
@@ -1,20 +1,19 @@
# See README.md for usage explanations
-def retry_upto(max_retries = 1, options = {})
+def retry_upto(max_retries = 1, opts = {})
yield
-rescue *(options[:rescue] || Exception)
- raise if (max_retries -= 1) == 0
- sleep(options[:interval] || 0)
- if options[:growth].respond_to?('*')
- options[:interval] = options[:interval] * options[:growth]
- elsif options[:growth].respond_to?(:call)
- options[:interval] = options[:growth].call(options[:interval])
+rescue *(opts[:rescue] || Exception)
+ attempt = attempt ? attempt+1 : 1
+ raise if (attempt == max_retries)
+ if interval = opts[:interval]
+ secs = interval.respond_to?(:call) ? interval.call(attempt) : interval
+ sleep(secs)
end
retry
end
class Enumerator
- def retry(options = {}, &blk)
- retry_upto(self.count, options, &blk)
+ def retry(opts = {}, &blk)
+ retry_upto(self.count, opts, &blk)
end
end
View
@@ -3,7 +3,7 @@ require File.expand_path("./lib/retry_upto")
Gem::Specification.new do |s|
s.name = "retry_upto"
- s.version = "1.1"
+ s.version = "1.2"
s.authors = ["Raul Murciano", "Glenn Gillen", "Pedro Belo", "Jaime Iniesta", "Lleïr Borras", "Aitor García Rey"]
s.email = ["raul@murciano.net"]
s.homepage = "http://github.com/raul/retry_upto"
View
@@ -1,6 +1,6 @@
require './test/test_helper'
-class Retry_uptoTest < MiniTest::Unit::TestCase
+class RetryUptoTest < MiniTest::Unit::TestCase
class FooError < Exception; end
class BarError < Exception; end
@@ -46,7 +46,7 @@ def test_retries_the_desired_number_of_attempts
# interval between attempts
def test_there_is_no_interval_between_attempts_by_default
- self.expects(:sleep).times(3).with(0).returns(nil)
+ self.expects(:sleep).never
retry_upto(4){ @target.foo! }
end
@@ -55,20 +55,11 @@ def test_interval_between_attempts_can_be_customized
retry_upto(4, :interval => 5){ @target.foo! }
end
- # interval growth between attempts
-
- def test_inverval_can_be_multiplied_by_an_integer_growth
- self.expects(:sleep).times(1).with(5)
- self.expects(:sleep).times(1).with(15)
- self.expects(:sleep).times(1).with(45)
- retry_upto(4, :interval => 5, :growth => 3){ @target.foo! }
- end
-
- def test_grow_for_inverval_between_attempts_can_be_defined_with_a_lambda
- self.expects(:sleep).times(1).with(5)
- self.expects(:sleep).times(1).with(7)
+ def test_different_intervals_can_be_defined_with_a_lambda
+ self.expects(:sleep).times(1).with(3)
+ self.expects(:sleep).times(1).with(6)
self.expects(:sleep).times(1).with(9)
- retry_upto(4, :interval => 5, :growth => lambda{ |t| t + 2 }){ @target.foo! }
+ retry_upto(4, :interval => lambda{ |attempt| attempt * 3 }){ @target.foo! }
end
# exceptions

0 comments on commit cf50b7c

Please sign in to comment.