class HTTP::Retriable::Performer
@api private
Request performing watchdog.
def calculate_delay(iteration, response)
-
(Numeric)-
Other tags:
- Api: - private
Parameters:
-
response(HTTP::Response, nil) -- -
iteration(Integer) --
def calculate_delay(iteration, response) @delay_calculator.call(iteration, response) end
def finish_attempt(client, err)
-
(void)-
Other tags:
- Api: - private
def finish_attempt(client, err) client.close raise err end
def initialize(tries: 5, delay: nil, exceptions: RETRIABLE_ERRORS, retry_statuses: nil,
-
(HTTP::Retriable::Performer)-
Other tags:
- Api: - private
Parameters:
-
should_retry(#call, nil) -- custom retry predicate -
max_delay(#to_f) -- maximum delay between retries -
on_retry(#call) -- callback invoked on each retry -
retry_statuses(Array<#to_i>, nil) -- status codes to retry -
exceptions(Array) -- exception classes to retry -
delay(#call, #to_i, nil) -- delay between retries -
tries(#to_i) -- maximum number of attempts
def initialize(tries: 5, delay: nil, exceptions: RETRIABLE_ERRORS, retry_statuses: nil, on_retry: ->(*_args) {}, max_delay: Float::MAX, should_retry: nil) @exception_classes = exceptions @retry_statuses = retry_statuses @tries = tries.to_i @on_retry = on_retry @should_retry_proc = should_retry @delay_calculator = DelayCalculator.new(delay: delay, max_delay: max_delay) end
def out_of_retries_error(request, response, exception)
-
(HTTP::OutOfRetriesError)-
Other tags:
- Api: - private
Parameters:
-
exception(Exception, nil) -- -
response(HTTP::Response, nil) -- -
request(HTTP::Request) --
def out_of_retries_error(request, response, exception) message = format("%s <%s> failed", String(request.verb).upcase, request.uri) message += " with #{response.status}" if response message += ":#{exception}" if exception OutOfRetriesError.new(message).tap do |ex| ex.cause = exception ex.response = response end end
def perform(client, req, &block)
- Api: - private
Returns:
-
(HTTP::Response)-
Other tags:
- See: #initialize -
def perform(client, req, &block) 1.upto(Float::INFINITY) do |attempt| # infinite loop with index err, res = try_request(&block) if retry_request?(req, err, res, attempt) retry_attempt(client, req, err, res, attempt) elsif err finish_attempt(client, err) elsif res return res end end end
def retry_attempt(client, req, err, res, attempt)
-
(void)-
Other tags:
- Api: - private
def retry_attempt(client, req, err, res, attempt) # Some servers support Keep-Alive on any response. Thus we should # flush response before retry, to avoid state error (when socket # has pending response data and we try to write new request). # Alternatively, as we don't need response body here at all, we # are going to close client, effectively closing underlying socket # and resetting client's state. wait_for_retry_or_raise(req, err, res, attempt) ensure client.close end
def retry_exception?(err)
-
(Boolean)-
Other tags:
- Api: - private
def retry_exception?(err) @exception_classes.any? { |e| err.is_a?(e) } end
def retry_request?(req, err, res, attempt)
-
(Boolean)-
Other tags:
- Api: - private
def retry_request?(req, err, res, attempt) if @should_retry_proc @should_retry_proc.call(req, err, res, attempt) elsif err retry_exception?(err) else retry_response?(res) end end
def retry_response?(res)
-
(Boolean)-
Other tags:
- Api: - private
def retry_response?(res) return false unless @retry_statuses response_status = Integer(res.status) retry_matchers = [@retry_statuses].flatten retry_matchers.any? do |matcher| case matcher when Range then matcher.cover?(response_status) when Numeric then matcher == response_status else matcher.call(response_status) end end end
def try_request
-
(Array)-
Other tags:
- Api: - private
def try_request err, res = nil begin res = yield rescue Exception => e err = e end [err, res] end
def wait_for_retry_or_raise(req, err, res, attempt)
-
(void)-
Other tags:
- Api: - private
def wait_for_retry_or_raise(req, err, res, attempt) if attempt < @tries @on_retry.call(req, err, res) sleep(calculate_delay(attempt, res)) else res&.flush raise out_of_retries_error(req, res, err) end end