diff --git a/lib/stripe/stripe_client.rb b/lib/stripe/stripe_client.rb index e95ef1e22..9c4909593 100644 --- a/lib/stripe/stripe_client.rb +++ b/lib/stripe/stripe_client.rb @@ -92,6 +92,12 @@ def self.should_retry?(error, method:, num_retries:) return true if error.is_a?(SocketError) if error.is_a?(Stripe::StripeError) + # The API may ask us not to retry (e.g. if doing so would be a no-op), + # or advise us to retry (e.g. in cases of lock timeouts). Defer to + # those instructions if given. + return false if error.http_headers["stripe-should-retry"] == "false" + return true if error.http_headers["stripe-should-retry"] == "true" + # 409 Conflict return true if error.http_status == 409 diff --git a/test/stripe/stripe_client_test.rb b/test/stripe/stripe_client_test.rb index 202951648..c029172fa 100644 --- a/test/stripe/stripe_client_test.rb +++ b/test/stripe/stripe_client_test.rb @@ -171,6 +171,28 @@ class StripeClientTest < Test::Unit::TestCase method: :post, num_retries: 0) end + should "retry when the `Stripe-Should-Retry` header is `true`" do + headers = StripeResponse::Headers.new( + "Stripe-Should-Retry" => ["true"], + ) + + # Note we send status 400 here, which would normally not be retried. + assert StripeClient.should_retry?(Stripe::StripeError.new(http_headers: headers, + http_status: 400), + method: :post, num_retries: 0) + end + + should "not retry when the `Stripe-Should-Retry` header is `false`" do + headers = StripeResponse::Headers.new( + "Stripe-Should-Retry" => ["false"], + ) + + # Note we send status 409 here, which would normally be retried. + refute StripeClient.should_retry?(Stripe::StripeError.new(http_headers: headers, + http_status: 409), + method: :post, num_retries: 0) + end + should "retry on a 409 Conflict" do assert StripeClient.should_retry?(Stripe::StripeError.new(http_status: 409), method: :post, num_retries: 0)