Created
September 17, 2014 04:16
-
-
Save mikehale/388bbc47dbb8e2c23a0f to your computer and use it in GitHub Desktop.
Excon middleware to exponentially backoff when throttled by AWS APIs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'fog' | |
class BackoffWhenThrottled < Excon::Middleware::Base | |
def error_call(datum) | |
datum[:throttle] ||= {} | |
datum[:throttle][:max_retries] ||= 0 | |
datum[:throttle][:max_delay] ||= 30 | |
datum[:throttle][:retry_count] = 0 | |
if throttled?(datum) | |
(datum[:throttle][:max_retries] == 0 || | |
datum[:throttle][:retry_count] < datum[:throttle][:max_retries]) | |
sleep_time = [(2 ** datum[:throttle][:retry_count] + rand(0.0)) * 0.1, datum[:throttle][:max_retries]].max.round(2) | |
puts "backing off for #{sleep_time}..." | |
sleep sleep_time | |
datum[:throttle][:retry_count] -= 1 | |
connection = datum.delete(:connection) | |
datum.reject! { |key, _| !Excon::VALID_REQUEST_KEYS.include?(key) } | |
connection.request(datum) | |
else | |
@stack.error_call(datum) | |
end | |
end | |
def throttled?(datum) | |
datum[:error].kind_of?(Excon::Errors::BadRequest) && | |
["Throttling", "Rate exceeded"] == extract_error_details(datum[:error].response.body) | |
end | |
def extract_error_details(body) | |
error_code = error_message = nil | |
begin | |
doc = Nokogiri::XML(body) | |
error_code = doc.css("Error Code").text | |
error_message = doc.css("Error Message").text | |
rescue | |
end | |
[error_code, error_message] | |
end | |
end | |
Excon.defaults[:middlewares] << BackoffWhenThrottled |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment