module Scrivito class CmsRestApi module RateLimit class << self def retry_on_rate_limit(try_until, &block) internal_retry(block, try_until, 0) end private def internal_retry(request_proc, try_until, 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 (Time.now + time_to_sleep.seconds) <= try_until sleep time_to_sleep internal_retry(request_proc, try_until, 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