Module: HTTPX::Plugins::Retries::InstanceMethods

Defined in:
lib/httpx/plugins/retries.rb,
sig/plugins/retries.rbs

Instance Method Summary collapse

Instance Method Details

#fetch_response(request, selector, options) ⇒ retriesResponse?

Parameters:

  • request (retriesRequest)
  • selector (Selector)
  • options (retriesOptions)

Returns:

  • (retriesResponse, nil)


142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/httpx/plugins/retries.rb', line 142

def fetch_response(request, selector, options)
  response = super

  if response &&
     request.retries.positive? &&
     retryable_request?(request, response, options) &&
     retryable_response?(response, options)
    try_partial_retry(request, response)
    log { "failed to get response, #{request.retries} tries to go..." }
    prepare_to_retry(request, response)

    if (retry_after = when_to_retry(request, response, options)) && retry_after.positive?

      retry_start = Utils.now
      log { "retrying after #{retry_after} secs..." }
      selector.after(retry_after) do
        if (response = request.response)
          response.finish!
          # request has terminated abruptly meanwhile
          request.emit_response(response)
        else
          log { "retrying (elapsed time: #{Utils.elapsed_time(retry_start)})!!" }
          send_request(request, selector, options)
        end
      end

      return
    else
      send_request(request, selector, options)

      # recalling itself, in case an error was triggered by the above, and we can
      # verify retriability again.
      return fetch_response(request, selector, options)
    end
  end
  response
end

#max_retries(n) ⇒ instance

returns a :retries plugin enabled session with n maximum retries per request setting.

Parameters:

  • (int)

Returns:

  • (instance)


136
137
138
# File 'lib/httpx/plugins/retries.rb', line 136

def max_retries(n)
  with(max_retries: n)
end

#prepare_to_retry(request, _response) ⇒ void

This method returns an undefined value.

Parameters:



198
199
200
201
# File 'lib/httpx/plugins/retries.rb', line 198

def prepare_to_retry(request, _response)
  request.retries -= 1 unless request.ping? # do not exhaust retries on connection liveness probes
  request.transition(:idle)
end

#retryable_error?(ex, _) ⇒ Boolean

returns whether the ex exception happend for a retriable request.

Parameters:

  • error (_Exception)
  • options (Options)

Returns:

  • (Boolean)


190
191
192
# File 'lib/httpx/plugins/retries.rb', line 190

def retryable_error?(ex, _)
  RETRYABLE_ERRORS.any? { |klass| ex.is_a?(klass) } && !ex.is_a?(TotalRequestTimeoutError)
end

#retryable_request?(request, _, options) ⇒ Boolean

returns whether request can be retried.

Parameters:

  • request (retriesRequest)
  • response (retriesResponse)
  • options (retriesOptions)

Returns:

  • (Boolean)


181
182
183
# File 'lib/httpx/plugins/retries.rb', line 181

def retryable_request?(request, _, options)
  IDEMPOTENT_METHODS.include?(request.verb) || options.retry_change_requests
end

#retryable_response?(response, options) ⇒ Boolean

Parameters:

  • response (retriesResponse)
  • options (retriesOptions)

Returns:

  • (Boolean)


185
186
187
# File 'lib/httpx/plugins/retries.rb', line 185

def retryable_response?(response, options)
  (response.is_a?(ErrorResponse) && retryable_error?(response.error, options)) || options.retry_on&.call(response)
end

#try_partial_retry(request, response) ⇒ void

This method returns an undefined value.

Attempt to set the request to perform a partial range request. This happens if the peer server accepts byte-range requests, and the last response contains some body payload.

Parameters:

  • request (retriesRequest)
  • response (retriesResponse)


224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'lib/httpx/plugins/retries.rb', line 224

def try_partial_retry(request, response)
  response = response.response if response.is_a?(ErrorResponse)

  return unless response

  unless response.headers.key?("accept-ranges") &&
         response.headers["accept-ranges"] == "bytes" && # there's nothing else supported though...
         (original_body = response.body)
    response.body.close
    return
  end

  request.partial_response = response

  size = original_body.bytesize

  request.headers["range"] = "bytes=#{size}-"
end

#when_to_retry(request, response, options) ⇒ Numeric?

Parameters:

Returns:

  • (Numeric, nil)


203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/httpx/plugins/retries.rb', line 203

def when_to_retry(request, response, options)
  retry_after = options.retry_after

  return unless retry_after

  retry_after = retry_after.call(request, response) if retry_after.respond_to?(:call)

  return unless retry_after

  # apply jitter
  if (jitter = request.options.retry_jitter)
    retry_after = jitter.call(retry_after)
  end
  retry_after
end