Permalink
Browse files

improve Retry middleware, change to only handle timeouts

Also supercharge it with :max, :interval, and :exceptions options.

Closes #158
  • Loading branch information...
1 parent 98ba913 commit e8c98c4323f04a1a40e9f409e6a6d6c2c7df88de @mislav mislav committed May 28, 2012
Showing with 69 additions and 17 deletions.
  1. +0 −2 lib/faraday/adapter/rack.rb
  2. +20 −3 lib/faraday/request/retry.rb
  3. +49 −12 test/middleware/retry_test.rb
@@ -1,5 +1,3 @@
-require 'timeout'
-
module Faraday
class Adapter
# Sends requests to a Rack app.
@@ -1,17 +1,34 @@
module Faraday
class Request::Retry < Faraday::Middleware
- def initialize(app, retries = 2)
- @retries = retries
+ def initialize(app, options = {})
super(app)
+ @retries, options = options, {} if options.is_a? Integer
+ @retries ||= options.fetch(:max, 2).to_i
+ @sleep = options.fetch(:interval, 0).to_f
+ to_handle = options.fetch(:exceptions) {
+ [Errno::ETIMEDOUT, 'Timeout::Error', Error::TimeoutError]
+ }
+ @errmatch = ExceptionMatcher.new Array(to_handle)
+ end
+
+ class ExceptionMatcher < Struct.new(:exceptions)
+ def ===(error)
+ exceptions.any? do |ex|
+ if ex.is_a? Module then error.is_a? ex
+ else error.class.to_s == ex.to_s
+ end
+ end
+ end
end
def call(env)
retries = @retries
begin
@app.call(env)
- rescue StandardError, Timeout::Error
+ rescue @errmatch
if retries > 0
retries -= 1
+ sleep @sleep if @sleep > 0
retry
end
raise
@@ -3,23 +3,60 @@
module Middleware
class RetryTest < Faraday::TestCase
def setup
- @stubs = Faraday::Adapter::Test::Stubs.new
- @conn = Faraday.new do |b|
- b.request :retry, 2
- b.adapter :test, @stubs
+ @times_called = 0
+ end
+
+ def conn(*retry_args)
+ Faraday.new do |b|
+ b.request :retry, *retry_args
+ b.adapter :test do |stub|
+ stub.post('/unstable') {
+ @times_called += 1
+ @explode.call @times_called
+ }
+ end
end
end
- def test_retries
- times_called = 0
+ def test_unhandled_error
+ @explode = lambda {|n| raise "boom!" }
+ assert_raise(RuntimeError) { conn.post("/unstable") }
+ assert_equal 1, @times_called
+ end
+
+ def test_handled_error
+ @explode = lambda {|n| raise Errno::ETIMEDOUT }
+ assert_raise(Errno::ETIMEDOUT) { conn.post("/unstable") }
+ assert_equal 3, @times_called
+ end
- @stubs.post("/echo") do
- times_called += 1
- raise "Error occurred"
- end
+ def test_legacy_max_retries
+ @explode = lambda {|n| raise Errno::ETIMEDOUT }
+ assert_raise(Errno::ETIMEDOUT) { conn(1).post("/unstable") }
+ assert_equal 2, @times_called
+ end
+
+ def test_new_max_retries
+ @explode = lambda {|n| raise Errno::ETIMEDOUT }
+ assert_raise(Errno::ETIMEDOUT) { conn(:max => 3).post("/unstable") }
+ assert_equal 4, @times_called
+ end
+
+ def test_interval
+ @explode = lambda {|n| raise Errno::ETIMEDOUT }
+ started = Time.now
+ assert_raise(Errno::ETIMEDOUT) {
+ conn(:max => 2, :interval => 0.1).post("/unstable")
+ }
+ assert_in_delta 0.2, Time.now - started, 0.02
+ end
- @conn.post("/echo") rescue nil
- assert_equal times_called, 3
+ def test_custom_exceptions
+ @explode = lambda {|n| raise "boom!" }
+ assert_raise(RuntimeError) {
+ conn(:exceptions => StandardError).post("/unstable")
+ }
+ assert_equal 3, @times_called
end
end
end

0 comments on commit e8c98c4

Please sign in to comment.