module Scrivito class CmsRestApi module RateLimit class << self def retry_on_rate_limit(request_timer, &block) internal_retry(block, request_timer, 0) end private def internal_retry(request_proc, request_timer, retry_count) response = request_proc.call if failed_because_of_rate_limit?(response) time_to_sleep = calculate_time_to_sleep(response['Retry-After'].to_f, retry_count) if request_timer.cover?(Time.now + time_to_sleep.seconds) Warning.warn("Rate limit exceeded. Will retry after #{time_to_sleep} seconds.") sleep time_to_sleep internal_retry(request_proc, request_timer, retry_count + 1) else raise Scrivito::RateLimitExceeded.new('rate limit exceeded', 429) end else response end end def calculate_time_to_sleep(retry_after, retry_count) backoff_wait_time = 2 ** retry_count * 0.5 [backoff_wait_time, retry_after].max end def failed_because_of_rate_limit?(response) response.code == '429' end end end end end