File: rate_limiter.rb

package info (click to toggle)
ruby-httpx 1.7.2-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,816 kB
  • sloc: ruby: 12,209; makefile: 4
file content (60 lines) | stat: -rw-r--r-- 1,818 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# frozen_string_literal: true

module HTTPX
  module Plugins
    #
    # This plugin adds support for retrying requests when the request:
    #
    # * is rate limited;
    # * when the server is unavailable (503);
    # * when a 3xx request comes with a "retry-after" value
    #
    # https://gitlab.com/os85/httpx/wikis/Rate-Limiter
    #
    module RateLimiter
      RATE_LIMIT_CODES = [429, 503].freeze

      class << self
        def load_dependencies(klass)
          klass.plugin(:retries, retry_after: method(:retry_after_rate_limit))
        end

        # Servers send the "Retry-After" header field to indicate how long the
        # user agent ought to wait before making a follow-up request.  When
        # sent with a 503 (Service Unavailable) response, Retry-After indicates
        # how long the service is expected to be unavailable to the client.
        # When sent with any 3xx (Redirection) response, Retry-After indicates
        # the minimum time that the user agent is asked to wait before issuing
        # the redirected request.
        #
        def retry_after_rate_limit(_, response)
          return unless response.is_a?(Response)

          retry_after = response.headers["retry-after"]

          return unless retry_after

          Utils.parse_retry_after(retry_after)
        end
      end

      module InstanceMethods
        private

        def retryable_request?(request, response, options)
          super || rate_limit_error?(response)
        end

        def retryable_response?(response, options)
          rate_limit_error?(response) || super
        end

        def rate_limit_error?(response)
          response.is_a?(Response) && RATE_LIMIT_CODES.include?(response.status)
        end
      end
    end

    register_plugin :rate_limiter, RateLimiter
  end
end