mirror of
https://github.com/lostisland/faraday.git
synced 2025-11-22 00:08:56 -05:00
improve Retry middleware, change to only handle timeouts
Also supercharge it with :max, :interval, and :exceptions options. Closes #158
This commit is contained in:
parent
98ba9137f6
commit
e8c98c4323
@ -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 @@ require File.expand_path(File.join(File.dirname(__FILE__), "..", "helper"))
|
||||
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
|
||||
|
||||
@stubs.post("/echo") do
|
||||
times_called += 1
|
||||
raise "Error occurred"
|
||||
end
|
||||
def test_handled_error
|
||||
@explode = lambda {|n| raise Errno::ETIMEDOUT }
|
||||
assert_raise(Errno::ETIMEDOUT) { conn.post("/unstable") }
|
||||
assert_equal 3, @times_called
|
||||
end
|
||||
|
||||
@conn.post("/echo") rescue nil
|
||||
assert_equal times_called, 3
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user