Created
July 8, 2016 01:38
-
-
Save mikeyhew/79dfd1189f14811425dad97e7f6545ca to your computer and use it in GitHub Desktop.
Custom ShopifyAPI connection class with 429-retrial and throttling
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
class ApiConnection < ShopifyAPI::Connection | |
cattr_accessor :logger | |
self.logger = Logger.new(STDOUT) # for now | |
class_attribute :leak_rate | |
self.leak_rate = 2 # 2 per second | |
class_attribute :call_limit_header | |
self.call_limit_header = 'X-Shopify-Shop-Api-Call-Limit' | |
class_attribute :min_call_buffer | |
self.min_call_buffer = 2 | |
def handle_response(response) | |
super.tap do | |
num_calls, limit = response.header[call_limit_header].split('/').map(&:to_i) | |
if limit - num_calls < min_call_buffer | |
self.wait_until = Time.now + ((num_calls + min_call_buffer - limit).to_f/leak_rate).seconds | |
end | |
logger.debug("API Calls used: #{num_calls}/#{limit}") | |
end | |
end | |
def request(*) | |
if wait_until | |
sleep_time = wait_until - Time.now | |
if sleep_time > 0 | |
logger.debug "waiting #{sleep_time} seconds to allow bucket to drain" | |
sleep(sleep_time) | |
end | |
end | |
with_retrial do | |
super | |
end | |
end | |
private | |
attr_accessor :wait_until | |
def with_retrial | |
num_retries = 5 | |
min_wait = 2 | |
retries_left = num_retries | |
loop do | |
begin | |
return yield | |
rescue ActiveResource::ClientError => e | |
if e.response.code.to_i == 429 && retries_left > 0 | |
retries_left -= 1 | |
wait_time = e.response['Retry-After'.freeze].to_i | |
wait_time = min_wait if wait_time < min_wait | |
logger.info "Got a 429, will retry in #{wait_time} seconds" | |
sleep(wait_time) | |
next | |
else | |
raise | |
end | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment