diff --git a/lib/stripe/stripe_client.rb b/lib/stripe/stripe_client.rb index f981089ab..a373f395c 100644 --- a/lib/stripe/stripe_client.rb +++ b/lib/stripe/stripe_client.rb @@ -88,6 +88,16 @@ def self.should_retry?(error, method:, num_retries:) # 409 Conflict return true if error.http_status == 409 + # 429 Too Many Requests + # + # There are a few different problems that can lead to a 429. The most + # common is rate limiting, on which we *don't* want to retry because + # that'd likely contribute to more contention problems. However, some + # 429s are lock timeouts, which is when a request conflicted with + # another request or an internal process on some particular object. + # These 429s are safe to retry. + return true if error.http_status == 429 && error.code == "lock_timeout" + # 500 Internal Server Error # # We only bother retrying these for non-POST requests. POSTs end up diff --git a/test/stripe/stripe_client_test.rb b/test/stripe/stripe_client_test.rb index 2d8fba808..3f22242f4 100644 --- a/test/stripe/stripe_client_test.rb +++ b/test/stripe/stripe_client_test.rb @@ -122,6 +122,12 @@ class StripeClientTest < Test::Unit::TestCase method: :post, num_retries: 0) end + should "retry on a 429 Too Many Requests when lock timeout" do + assert StripeClient.should_retry?(Stripe::StripeError.new(http_status: 429, + code: "lock_timeout"), + method: :post, num_retries: 0) + end + should "retry on a 500 Internal Server Error when non-POST" do assert StripeClient.should_retry?(Stripe::StripeError.new(http_status: 500), method: :get, num_retries: 0) @@ -142,6 +148,12 @@ class StripeClientTest < Test::Unit::TestCase method: :post, num_retries: 0) end + should "not retry on a 429 Too Many Requests when not lock timeout" do + refute StripeClient.should_retry?(Stripe::StripeError.new(http_status: 429, + code: "rate_limited"), + method: :post, num_retries: 0) + end + should "not retry on a 500 Internal Server Error when POST" do refute StripeClient.should_retry?(Stripe::StripeError.new(http_status: 500), method: :post, num_retries: 0)