faraday-retry 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a1e1671b917edb92ca89a4cebdd676bc6dfbc63956ef5d17a79bb467dd8134b9
4
+ data.tar.gz: b29b41e84db3b281a91fbef905925579d3d9ab003dba97e66c2dc906d1ed0d60
5
+ SHA512:
6
+ metadata.gz: 56bc36544781fe865ba266157f5f07365e69e2efb4aa51fce0e638dec8b19a14e9b1be68f3401e43db7bc76daaf278edcd457fb693f6b314f901c270eb78f3bd
7
+ data.tar.gz: 363570c19fb872444515db4caa4fda1ba3f135510ce0e6d67d32ab8005d73b06270a48ea41b03ac7b707ae63f97f47b92145dbfeb25e28a546691b147328a3ed
data/CHANGELOG.md ADDED
@@ -0,0 +1,6 @@
1
+ # Changelog
2
+
3
+ ## v1.0
4
+
5
+ Initial release.
6
+ This release consists of the same middleware that was previously bundled with Faraday but removed in Faraday v2.0.
data/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2021 Mattia Giuffrida
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,161 @@
1
+ # Faraday Retry
2
+
3
+ [![GitHub Workflow Status](https://img.shields.io/github/workflow/status/lostisland/faraday-retry/CI)](https://github.com/lostisland/faraday-retry/actions?query=branch%3Amain)
4
+ [![Gem](https://img.shields.io/gem/v/faraday-retry.svg?style=flat-square)](https://rubygems.org/gems/faraday-retry)
5
+ [![License](https://img.shields.io/github/license/lostisland/faraday-retry.svg?style=flat-square)](LICENSE.md)
6
+
7
+ The `Retry` middleware automatically retries requests that fail due to intermittent client
8
+ or server errors (such as network hiccups).
9
+ By default, it retries 2 times and handles only timeout exceptions.
10
+ It can be configured with an arbitrary number of retries, a list of exceptions to handle,
11
+ a retry interval, a percentage of randomness to add to the retry interval, and a backoff factor.
12
+ The middleware can also handle the [`Retry-After`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After)
13
+ header automatically when configured with the right status codes (see below for an example).
14
+
15
+ ## Installation
16
+
17
+ Add this line to your application's Gemfile:
18
+
19
+ ```ruby
20
+ gem 'faraday-retry'
21
+ ```
22
+
23
+ And then execute:
24
+
25
+ ```shell
26
+ bundle install
27
+ ```
28
+
29
+ Or install it yourself as:
30
+
31
+ ```shell
32
+ gem install faraday-retry
33
+ ```
34
+
35
+ ## Usage
36
+
37
+ This example will result in a first interval that is random between 0.05 and 0.075
38
+ and a second interval that is random between 0.1 and 0.125.
39
+
40
+ ```ruby
41
+ require 'faraday'
42
+ require 'faraday/retry'
43
+
44
+ retry_options = {
45
+ max: 2,
46
+ interval: 0.05,
47
+ interval_randomness: 0.5,
48
+ backoff_factor: 2
49
+ }
50
+
51
+ conn = Faraday.new(...) do |f|
52
+ f.request :retry, retry_options
53
+ #...
54
+ end
55
+
56
+ conn.get('/')
57
+ ```
58
+
59
+ ### Control when the middleware will retry requests
60
+
61
+ By default, the `Retry` middleware will only retry idempotent methods and the most common network-related exceptions.
62
+ You can change this behaviour by providing the right option when adding the middleware to your connection.
63
+
64
+ #### Specify which methods will be retried
65
+
66
+ You can provide a `methods` option with a list of HTTP methods.
67
+ This will replace the default list of HTTP methods: `delete`, `get`, `head`, `options`, `put`.
68
+
69
+ ```ruby
70
+ retry_options = {
71
+ methods: %i[get post]
72
+ }
73
+ ```
74
+
75
+ #### Specify which exceptions should trigger a retry
76
+
77
+ You can provide an `exceptions` option with a list of exceptions that will replace
78
+ the default list of network-related exceptions: `Errno::ETIMEDOUT`, `Timeout::Error`, `Faraday::TimeoutError`.
79
+ This can be particularly useful when combined with the [RaiseError][raise_error] middleware.
80
+
81
+ ```ruby
82
+ retry_options = {
83
+ exceptions: [Faraday::ResourceNotFound, Faraday::UnauthorizedError]
84
+ }
85
+ ```
86
+
87
+ #### Specify on which response statuses to retry
88
+
89
+ By default the `Retry` middleware will only retry the request if one of the expected exceptions arise.
90
+ However, you can specify a list of HTTP statuses you'd like to be retried. When you do so, the middleware will
91
+ check the response `status` code and will retry the request if included in the list.
92
+
93
+ ```ruby
94
+ retry_options = {
95
+ retry_statuses: [401, 409]
96
+ }
97
+ ```
98
+
99
+ #### Automatically handle the `Retry-After` header
100
+
101
+ Some APIs, like the [Slack API](https://api.slack.com/docs/rate-limits), will inform you when you reach their API limits by replying with a response status code of `429` and a response header of `Retry-After` containing a time in seconds. You should then only retry querying after the amount of time provided by the `Retry-After` header, otherwise you won't get a response.
102
+
103
+ You can automatically handle this and have Faraday pause and retry for the right amount of time by including the `429` status code in the retry statuses list:
104
+
105
+ ```ruby
106
+ retry_options = {
107
+ retry_statuses: [429]
108
+ }
109
+ ```
110
+
111
+ #### Specify a custom retry logic
112
+
113
+ You can also specify a custom retry logic with the `retry_if` option.
114
+ This option accepts a block that will receive the `env` object and the exception raised
115
+ and should decide if the code should retry still the action or not independent of the retry count.
116
+ This would be useful if the exception produced is non-recoverable or if the the HTTP method called is not idempotent.
117
+
118
+ **NOTE:** this option will only be used for methods that are not included in the `methods` option.
119
+ If you want this to apply to all HTTP methods, pass `methods: []` as an additional option.
120
+
121
+ ```ruby
122
+ # Retries the request if response contains { success: false }
123
+ retry_options = {
124
+ retry_if: -> (env, _exc) { env.body[:success] == 'false' }
125
+ }
126
+ ```
127
+
128
+ ### Call a block on every retry
129
+
130
+ You can specify a block through the `retry_block` option that will be called before every retry.
131
+ There are many different applications for this feature, spacing from instrumentation to monitoring.
132
+ Request environment, middleware options, current number of retries and the exception is passed to the block as parameters.
133
+ For example, you might want to keep track of the response statuses:
134
+
135
+ ```ruby
136
+ response_statuses = []
137
+ retry_options = {
138
+ retry_block: -> (env, options, retries, exc) { response_statuses << env.status }
139
+ }
140
+ ```
141
+
142
+ ## Development
143
+
144
+ After checking out the repo, run `bin/setup` to install dependencies.
145
+
146
+ Then, run `bin/test` to run the tests.
147
+
148
+ To install this gem onto your local machine, run `rake build`.
149
+
150
+ To release a new version, make a commit with a message such as "Bumped to 0.0.2" and then run `rake release`.
151
+ See how it works [here](https://bundler.io/guides/creating_gem.html#releasing-the-gem).
152
+
153
+ ## Contributing
154
+
155
+ Bug reports and pull requests are welcome on [GitHub](https://github.com/lostisland/faraday-retry).
156
+
157
+ ## License
158
+
159
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
160
+
161
+ [raise_error]: https://lostisland.github.io/faraday/middleware/raise-error
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Faraday namespace.
4
+ module Faraday
5
+ # Exception used to control the Retry middleware.
6
+ class RetriableResponse < Error
7
+ end
8
+ end
@@ -0,0 +1,229 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Faraday
4
+ module Retry
5
+ # This class provides the main implementation for your middleware.
6
+ # Your middleware can implement any of the following methods:
7
+ # * on_request - called when the request is being prepared
8
+ # * on_complete - called when the response is being processed
9
+ #
10
+ # Optionally, you can also override the following methods from Faraday::Middleware
11
+ # * initialize(app, options = {}) - the initializer method
12
+ # * call(env) - the main middleware invocation method.
13
+ # This already calls on_request and on_complete, so you normally don't need to override it.
14
+ # You may need to in case you need to "wrap" the request or need more control
15
+ # (see "retry" middleware: https://github.com/lostisland/faraday/blob/main/lib/faraday/request/retry.rb#L142).
16
+ # IMPORTANT: Remember to call `@app.call(env)` or `super` to not interrupt the middleware chain!
17
+ class Middleware < Faraday::Middleware
18
+ DEFAULT_EXCEPTIONS = [
19
+ Errno::ETIMEDOUT, 'Timeout::Error',
20
+ Faraday::TimeoutError, Faraday::RetriableResponse
21
+ ].freeze
22
+ IDEMPOTENT_METHODS = %i[delete get head options put].freeze
23
+
24
+ # Options contains the configurable parameters for the Retry middleware.
25
+ class Options < Faraday::Options.new(:max, :interval, :max_interval,
26
+ :interval_randomness,
27
+ :backoff_factor, :exceptions,
28
+ :methods, :retry_if, :retry_block,
29
+ :retry_statuses)
30
+
31
+ DEFAULT_CHECK = ->(_env, _exception) { false }
32
+
33
+ def self.from(value)
34
+ if value.is_a?(Integer)
35
+ new(value)
36
+ else
37
+ super(value)
38
+ end
39
+ end
40
+
41
+ def max
42
+ (self[:max] ||= 2).to_i
43
+ end
44
+
45
+ def interval
46
+ (self[:interval] ||= 0).to_f
47
+ end
48
+
49
+ def max_interval
50
+ (self[:max_interval] ||= Float::MAX).to_f
51
+ end
52
+
53
+ def interval_randomness
54
+ (self[:interval_randomness] ||= 0).to_f
55
+ end
56
+
57
+ def backoff_factor
58
+ (self[:backoff_factor] ||= 1).to_f
59
+ end
60
+
61
+ def exceptions
62
+ Array(self[:exceptions] ||= DEFAULT_EXCEPTIONS)
63
+ end
64
+
65
+ def methods
66
+ Array(self[:methods] ||= IDEMPOTENT_METHODS)
67
+ end
68
+
69
+ def retry_if
70
+ self[:retry_if] ||= DEFAULT_CHECK
71
+ end
72
+
73
+ def retry_block
74
+ self[:retry_block] ||= proc {}
75
+ end
76
+
77
+ def retry_statuses
78
+ Array(self[:retry_statuses] ||= [])
79
+ end
80
+ end
81
+
82
+ # @param app [#call]
83
+ # @param options [Hash]
84
+ # @option options [Integer] :max (2) Maximum number of retries
85
+ # @option options [Integer] :interval (0) Pause in seconds between retries
86
+ # @option options [Integer] :interval_randomness (0) The maximum random
87
+ # interval amount expressed as a float between
88
+ # 0 and 1 to use in addition to the interval.
89
+ # @option options [Integer] :max_interval (Float::MAX) An upper limit
90
+ # for the interval
91
+ # @option options [Integer] :backoff_factor (1) The amount to multiply
92
+ # each successive retry's interval amount by in order to provide backoff
93
+ # @option options [Array] :exceptions ([ Errno::ETIMEDOUT,
94
+ # 'Timeout::Error', Faraday::TimeoutError, Faraday::RetriableResponse])
95
+ # The list of exceptions to handle. Exceptions can be given as
96
+ # Class, Module, or String.
97
+ # @option options [Array] :methods (the idempotent HTTP methods
98
+ # in IDEMPOTENT_METHODS) A list of HTTP methods to retry without
99
+ # calling retry_if. Pass an empty Array to call retry_if
100
+ # for all exceptions.
101
+ # @option options [Block] :retry_if (false) block that will receive
102
+ # the env object and the exception raised
103
+ # and should decide if the code should retry still the action or
104
+ # not independent of the retry count. This would be useful
105
+ # if the exception produced is non-recoverable or if the
106
+ # the HTTP method called is not idempotent.
107
+ # @option options [Block] :retry_block block that is executed before
108
+ # every retry. Request environment, middleware options, current number
109
+ # of retries and the exception is passed to the block as parameters.
110
+ # @option options [Array] :retry_statuses Array of Integer HTTP status
111
+ # codes or a single Integer value that determines whether to raise
112
+ # a Faraday::RetriableResponse exception based on the HTTP status code
113
+ # of an HTTP response.
114
+ def initialize(app, options = nil)
115
+ super(app)
116
+ @options = Options.from(options)
117
+ @errmatch = build_exception_matcher(@options.exceptions)
118
+ end
119
+
120
+ def calculate_sleep_amount(retries, env)
121
+ retry_after = calculate_retry_after(env)
122
+ retry_interval = calculate_retry_interval(retries)
123
+
124
+ return if retry_after && retry_after > @options.max_interval
125
+
126
+ if retry_after && retry_after >= retry_interval
127
+ retry_after
128
+ else
129
+ retry_interval
130
+ end
131
+ end
132
+
133
+ # @param env [Faraday::Env]
134
+ def call(env)
135
+ retries = @options.max
136
+ request_body = env[:body]
137
+ begin
138
+ # after failure env[:body] is set to the response body
139
+ env[:body] = request_body
140
+ @app.call(env).tap do |resp|
141
+ raise Faraday::RetriableResponse.new(nil, resp) if @options.retry_statuses.include?(resp.status)
142
+ end
143
+ rescue @errmatch => e
144
+ if retries.positive? && retry_request?(env, e)
145
+ retries -= 1
146
+ rewind_files(request_body)
147
+ if (sleep_amount = calculate_sleep_amount(retries + 1, env))
148
+ @options.retry_block.call(env, @options, retries, e)
149
+ sleep sleep_amount
150
+ retry
151
+ end
152
+ end
153
+
154
+ raise unless e.is_a?(Faraday::RetriableResponse)
155
+
156
+ e.response
157
+ end
158
+ end
159
+
160
+ # An exception matcher for the rescue clause can usually be any object
161
+ # that responds to `===`, but for Ruby 1.8 it has to be a Class or Module.
162
+ #
163
+ # @param exceptions [Array]
164
+ # @api private
165
+ # @return [Module] an exception matcher
166
+ def build_exception_matcher(exceptions)
167
+ matcher = Module.new
168
+ (
169
+ class << matcher
170
+ self
171
+ end).class_eval do
172
+ define_method(:===) do |error|
173
+ exceptions.any? do |ex|
174
+ if ex.is_a? Module
175
+ error.is_a? ex
176
+ else
177
+ Object.const_defined?(ex.to_s) && error.is_a?(Object.const_get(ex.to_s))
178
+ end
179
+ end
180
+ end
181
+ end
182
+ matcher
183
+ end
184
+
185
+ private
186
+
187
+ def retry_request?(env, exception)
188
+ @options.methods.include?(env[:method]) ||
189
+ @options.retry_if.call(env, exception)
190
+ end
191
+
192
+ def rewind_files(body)
193
+ return unless body.is_a?(Hash)
194
+
195
+ body.each do |_, value|
196
+ value.rewind if value.is_a?(UploadIO)
197
+ end
198
+ end
199
+
200
+ # MDN spec for Retry-After header:
201
+ # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After
202
+ def calculate_retry_after(env)
203
+ response_headers = env[:response_headers]
204
+ return unless response_headers
205
+
206
+ retry_after_value = env[:response_headers]['Retry-After']
207
+
208
+ # Try to parse date from the header value
209
+ begin
210
+ datetime = DateTime.rfc2822(retry_after_value)
211
+ datetime.to_time - Time.now.utc
212
+ rescue ArgumentError
213
+ retry_after_value.to_f
214
+ end
215
+ end
216
+
217
+ def calculate_retry_interval(retries)
218
+ retry_index = @options.max - retries
219
+ current_interval = @options.interval *
220
+ (@options.backoff_factor**retry_index)
221
+ current_interval = [current_interval, @options.max_interval].min
222
+ random_interval = rand * @options.interval_randomness.to_f *
223
+ @options.interval
224
+
225
+ current_interval + random_interval
226
+ end
227
+ end
228
+ end
229
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Faraday
4
+ module Retry
5
+ VERSION = '1.0.0'
6
+ end
7
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'faraday'
4
+ require_relative 'retriable_response'
5
+ require_relative 'retry/middleware'
6
+ require_relative 'retry/version'
7
+
8
+ module Faraday
9
+ # Middleware main module.
10
+ module Retry
11
+ Faraday::Request.register_middleware(retry: Faraday::Retry::Middleware)
12
+ end
13
+ end
metadata ADDED
@@ -0,0 +1,187 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: faraday-retry
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Mattia Giuffrida
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-01-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: faraday
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 2.0.0.alpha.pre.4
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 2.0.0.alpha.pre.4
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '13.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '13.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: simplecov
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.21.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.21.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 1.21.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 1.21.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop-packaging
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 0.5.0
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 0.5.0
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop-performance
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '1.0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '1.0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rubocop-rspec
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '2.0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '2.0'
139
+ description: 'Catches exceptions and retries each request a limited number of times.
140
+
141
+ '
142
+ email:
143
+ - giuffrida.mattia@gmail.com
144
+ executables: []
145
+ extensions: []
146
+ extra_rdoc_files: []
147
+ files:
148
+ - CHANGELOG.md
149
+ - LICENSE.md
150
+ - README.md
151
+ - lib/faraday/retriable_response.rb
152
+ - lib/faraday/retry.rb
153
+ - lib/faraday/retry/middleware.rb
154
+ - lib/faraday/retry/version.rb
155
+ homepage: https://github.com/lostisland/faraday-retry
156
+ licenses:
157
+ - MIT
158
+ metadata:
159
+ bug_tracker_uri: https://github.com/lostisland/faraday-retry/issues
160
+ changelog_uri: https://github.com/lostisland/faraday-retry/blob/v1.0.0/CHANGELOG.md
161
+ documentation_uri: http://www.rubydoc.info/gems/faraday-retry/1.0.0
162
+ homepage_uri: https://github.com/lostisland/faraday-retry
163
+ source_code_uri: https://github.com/lostisland/faraday-retry
164
+ wiki_uri: https://github.com/lostisland/faraday-retry/wiki
165
+ post_install_message:
166
+ rdoc_options: []
167
+ require_paths:
168
+ - lib
169
+ required_ruby_version: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '2.6'
174
+ - - "<"
175
+ - !ruby/object:Gem::Version
176
+ version: '4'
177
+ required_rubygems_version: !ruby/object:Gem::Requirement
178
+ requirements:
179
+ - - ">="
180
+ - !ruby/object:Gem::Version
181
+ version: '0'
182
+ requirements: []
183
+ rubygems_version: 3.1.6
184
+ signing_key:
185
+ specification_version: 4
186
+ summary: Catches exceptions and retries each request a limited number of times
187
+ test_files: []