Sha256: 4fb112f0bf6806ed51eeb98d9ef516c22909a43bd92d0c76e98bfc05faf12aa5

Contents?: true

Size: 1.41 KB

Versions: 7

Compression:

Stored size: 1.41 KB

Contents

require 'thread'

module Airrecord
  class FaradayRateLimiter < Faraday::Middleware
    class << self
      attr_accessor :requests
    end

    def initialize(app, requests_per_second: nil, sleeper: nil)
      super(app)
      @rps = requests_per_second
      @sleeper = sleeper || ->(seconds) { sleep(seconds) }
      @mutex = Mutex.new
      clear
    end

    def call(env)
      @mutex.synchronize do
        wait if too_many_requests_in_last_second?
        @app.call(env).on_complete do |_response_env|
          requests << Process.clock_gettime(Process::CLOCK_MONOTONIC)
          requests.shift if requests.size > @rps
        end
      end
    end

    def clear
      self.class.requests = []
    end

    private

    def requests
      self.class.requests
    end

    def too_many_requests_in_last_second?
      return false unless @rps
      return false unless requests.size >= @rps
      window_span < 1.0
    end

    def wait
      # Time to wait until making the next request to stay within limits.
      # [1.1, 1.2, 1.3, 1.4, 1.5] => 1 - 0.4 => 0.6
      wait_time = 1.0 - window_span
      @sleeper.call(wait_time)
    end

    # [1.1, 1.2, 1.3, 1.4, 1.5] => 1.5 - 1.1 => 0.4
    def window_span
      requests.last - requests.first
    end
  end
end

Faraday::Request.register_middleware(
  # Avoid polluting the global middleware namespace with a prefix.
  :airrecord_rate_limiter => Airrecord::FaradayRateLimiter
)

Version data entries

7 entries across 7 versions & 1 rubygems

Version Path
airrecord-1.0.6 lib/airrecord/faraday_rate_limiter.rb
airrecord-1.0.5 lib/airrecord/faraday_rate_limiter.rb
airrecord-1.0.4 lib/airrecord/faraday_rate_limiter.rb
airrecord-1.0.3 lib/airrecord/faraday_rate_limiter.rb
airrecord-1.0.2 lib/airrecord/faraday_rate_limiter.rb
airrecord-1.0.1 lib/airrecord/faraday_rate_limiter.rb
airrecord-1.0.0 lib/airrecord/faraday_rate_limiter.rb