Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Retry block change #3

Merged
merged 4 commits into from
Jan 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .rubocop_todo.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
# on 2021-12-31 12:13:51 UTC using RuboCop version 1.21.0.
# on 2022-01-04 18:53:25 UTC using RuboCop version 1.23.0.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
Expand All @@ -15,12 +15,12 @@ Lint/AmbiguousBlockAssociation:
# Offense count: 1
# Configuration parameters: IgnoredMethods, CountRepeatedAttributes.
Metrics/AbcSize:
Max: 23
Max: 26

# Offense count: 2
# Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods.
Metrics/MethodLength:
Max: 20
Max: 26

# Offense count: 12
# Configuration parameters: Prefixes.
Expand Down Expand Up @@ -49,11 +49,11 @@ RSpec/InstanceVariable:
RSpec/MultipleExpectations:
Max: 3

# Offense count: 7
# Offense count: 9
# Configuration parameters: AllowSubject.
RSpec/MultipleMemoizedHelpers:
Max: 9

# Offense count: 1
# Offense count: 3
RSpec/NestedGroups:
Max: 4
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# Changelog

## v2.0

### Changed

* retry_block now takes keyword arguments instead of positional (backwards incompatible)
* retry_block `retry_count` arg now counts up from 0, instead of old `retries_remaining`

### Added

* retry_block has additional `will_retry_in` argument with upcoming delay before retry in seconds.

## v1.0

Initial release.
Expand Down
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,15 +127,19 @@ retry_options = {

### Call a block on every retry

You can specify a block through the `retry_block` option that will be called before every retry.
There are many different applications for this feature, spacing from instrumentation to monitoring.
Request environment, middleware options, current number of retries and the exception is passed to the block as parameters.
You can specify a proc object through the `retry_block` option that will be called before every
retry, before There are many different applications for this feature, spacing from instrumentation to monitoring.


The block is passed keyword arguments with contextual information: Request environment, middleware options, current number of retries, exception, and amount of time we will wait before retrying. (retry_block is called before the wait time happens)


For example, you might want to keep track of the response statuses:

```ruby
response_statuses = []
retry_options = {
retry_block: -> (env, options, retries, exc) { response_statuses << env.status }
retry_block: -> (env:, options:, retries_remaining:, exception:, will_retry_in:) { response_statuses << env.status }
}
```

Expand Down
20 changes: 17 additions & 3 deletions lib/faraday/retry/middleware.rb
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,16 @@ def retry_statuses
# if the exception produced is non-recoverable or if the
# the HTTP method called is not idempotent.
# @option options [Block] :retry_block block that is executed before
# every retry. Request environment, middleware options, current number
# of retries and the exception is passed to the block as parameters.
# every retry. The block will be yielded keyword arguments:
# * env [Faraday::Env]: Request environment
# * options [Faraday::Options]: middleware options
# * retry_count [Integer]: how many retries have already occured (starts at 0)
# * exception [Exception]: exception that triggered the retry,
# will be the synthetic `Faraday::RetriableResponse` if the
# retry was triggered by something other than an exception.
# * will_retry_in [Float]: retry_block is called *before* the retry
# delay, actual retry will happen in will_retry_in number of
# seconds.
# @option options [Array] :retry_statuses Array of Integer HTTP status
# codes or a single Integer value that determines whether to raise
# a Faraday::RetriableResponse exception based on the HTTP status code
Expand Down Expand Up @@ -145,7 +153,13 @@ def call(env)
retries -= 1
rewind_files(request_body)
if (sleep_amount = calculate_sleep_amount(retries + 1, env))
@options.retry_block.call(env, @options, retries, e)
@options.retry_block.call(
env: env,
options: @options,
retry_count: @options.max - (retries + 1),
exception: e,
will_retry_in: sleep_amount
)
sleep sleep_amount
retry
end
Expand Down
16 changes: 14 additions & 2 deletions spec/faraday/retry/middleware_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,25 @@
end

context 'and retry_block is set' do
let(:options) { [{ retry_block: ->(env, options, retries, exc) { retry_block_calls << [env, options, retries, exc] } }] }
let(:options) { [{ retry_block: ->(**kwargs) { retry_block_calls << kwargs } }] }
let(:retry_block_calls) { [] }
let(:retry_block_times_called) { retry_block_calls.size }

it 'calls retry block for each retry' do
expect(retry_block_times_called).to eq(2)
end

describe 'with arguments to retry_block' do
it { expect(retry_block_calls.first[:exception]).to be_kind_of(Errno::ETIMEDOUT) }
it { expect(retry_block_calls.first[:options]).to be_kind_of(Faraday::Options) }
it { expect(retry_block_calls.first[:env]).to be_kind_of(Faraday::Env) }
it { expect(retry_block_calls.first[:retry_count]).to be_kind_of(Integer) }
it { expect(retry_block_calls.first[:retry_count]).to eq 0 }
end

describe 'arguments to retry_block on second call' do
it { expect(retry_block_calls[1][:retry_count]).to eq 1 }
end
end
end

Expand Down Expand Up @@ -263,7 +275,7 @@
context 'and retry_block is set' do
let(:options) do
[{
retry_block: ->(env, options, retries, exc) { retry_block_calls << [env, options, retries, exc] },
retry_block: ->(**kwargs) { retry_block_calls << kwargs },
max: 2,
max_interval: 5,
retry_statuses: 504
Expand Down