Skip to content

Commit

Permalink
Implement header_parser_block option
Browse files Browse the repository at this point in the history
  • Loading branch information
zavan authored and iMacTia committed Jun 1, 2023
1 parent 3b0c052 commit 5905eb1
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 9 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,13 +111,14 @@ retry_options = {
}
```

If you are working with an API which does not comply with the Rate Limit RFC you can specify custom headers to be used for retry and reset.
If you are working with an API which does not comply with the Rate Limit RFC you can specify custom headers to be used for retry and reset, as well as a block to parse the headers:

```ruby
retry_options = {
retry_statuses: [429],
rate_limit_retry_header: 'x-rate-limit-retry-after',
rate_limit_reset_header: 'x-rate-limit-reset'
rate_limit_reset_header: 'x-rate-limit-reset',
header_parser_block: ->(value) { Time.at(value.to_i).utc - Time.now.utc }
}
```

Expand Down
22 changes: 15 additions & 7 deletions lib/faraday/retry/middleware.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class Options < Faraday::Options.new(:max, :interval, :max_interval,
:backoff_factor, :exceptions,
:methods, :retry_if, :retry_block,
:retry_statuses, :rate_limit_retry_header,
:rate_limit_reset_header)
:rate_limit_reset_header, :header_parser_block)

DEFAULT_CHECK = ->(_env, _exception) { false }

Expand Down Expand Up @@ -120,6 +120,10 @@ def retry_statuses
# codes or a single Integer value that determines whether to raise
# a Faraday::RetriableResponse exception based on the HTTP status code
# of an HTTP response.
# @option options [Block] :header_parser_block block that will receive
# the the value of the retry header and should return the number of
# seconds to wait before retrying the request. This is useful if the
# value of the header is not a number of seconds or a RFC 2822 formatted date.
def initialize(app, options = nil)
super(app)
@options = Options.from(options)
Expand Down Expand Up @@ -244,12 +248,16 @@ def parse_retry_header(env, header)

retry_after_value = env[:response_headers][header]

# Try to parse date from the header value
begin
datetime = DateTime.rfc2822(retry_after_value)
datetime.to_time - Time.now.utc
rescue ArgumentError
retry_after_value.to_f
if @options.header_parser_block
@options.header_parser_block.call(retry_after_value)
else
# Try to parse date from the header value
begin
datetime = DateTime.rfc2822(retry_after_value)
datetime.to_time - Time.now.utc
rescue ArgumentError
retry_after_value.to_f
end
end
end
end
Expand Down
7 changes: 7 additions & 0 deletions spec/faraday/retry/middleware_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,13 @@
it { expect(elapsed).to be > 1 }
end

context 'when custom header_parser_block is set' do
let(:headers) { { 'Retry-After' => '0.1', 'RateLimit-Reset' => (Time.now.utc + 2).to_i.to_s } }
let(:options) { [{ max: 1, interval: 0.1, retry_statuses: 504, header_parser_block: ->(value) { Time.at(value.to_i).utc - Time.now.utc } }] }

it { expect(elapsed).to be > 1 }
end

context 'when retry_after is bigger than max_interval' do
let(:headers) { { 'Retry-After' => (Time.now.utc + 20).strftime('%a, %d %b %Y %H:%M:%S GMT') } }
let(:options) { [{ max: 2, interval: 0.1, max_interval: 5, retry_statuses: 504 }] }
Expand Down

3 comments on commit 5905eb1

@panozzaj
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wanted to say thanks for this! I wrote a custom middleware to fix a case where the API did not conform to the spec, and this seems like a great alternative that is well-documented!

@iMacTia
Copy link
Member

@iMacTia iMacTia commented on 5905eb1 Jun 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shout out to @zavan for the contribution ❤️

@zavan
Copy link
Contributor Author

@zavan zavan commented on 5905eb1 Jun 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@panozzaj @iMacTia Good to know it's useful for other people too 😄

Please sign in to comment.