stripe 1.45.0 → 1.46.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5ed148072cc048ea24b62fc7a64645d8714eec90
4
- data.tar.gz: 2f478d4c522c9cff1cf502328289233f0b71c8b2
3
+ metadata.gz: d883d1c0eb0486e3c51e5076178c4351ca70ee68
4
+ data.tar.gz: a992c6c4e854019538a0406dbca5382c8f99d77e
5
5
  SHA512:
6
- metadata.gz: 4035922aa5bd4d02bf82ea89c52c645cf761ebbedea8ca165b81a6a379af363b9a027911313d447c7db9e846e633774780a0e838b9771c3aaf0fa132992028e2
7
- data.tar.gz: ee89f0e1140edeead9e86733d3467468dcdf94551b35878ae438e0acd7dd70ec3a68ca66e3acf5e29d23d194f8cd59bb4641e5d0e6c2eb8efd6ebbe8dc991f1e
6
+ metadata.gz: caf72f6851481ed302b8d06d450b55cf72c260104e549c099f52bb7477ec0ec28777648f4d3e4edae0f1c96cfec8123248a645cb316325cefec4f04cab74fab8
7
+ data.tar.gz: 165a6679fea615754af43de70e04c5d33a225ad1e938222e7c13767736bcdd9955162b22f266044f20818758ec3bcae0bb366c1c641b3fe1a388ed441315264b
@@ -1,3 +1,7 @@
1
+ === 1.46.0 2016-07-07
2
+
3
+ * Allow retry when a 409 conflict is encountered
4
+
1
5
  === 1.45.0 2016-07-07
2
6
 
3
7
  * Do not send subresources when updating except when explicitly told to do so (see #433)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.45.0
1
+ 1.46.0
@@ -68,6 +68,23 @@ require 'stripe/errors/rate_limit_error'
68
68
  module Stripe
69
69
  DEFAULT_CA_BUNDLE_PATH = File.dirname(__FILE__) + '/data/ca-certificates.crt'
70
70
 
71
+ # HTTP status exceptions which we'd like to retry. Most HTTP status
72
+ # exceptions are from a Stripe API server response, so we generally _don't_
73
+ # retry because doing so would have the same result as the original request.
74
+ RETRY_HTTP_EXCEPTIONS = [
75
+ # A server may respond with a 409 to indicate that there is a concurrent
76
+ # request executing with the same idempotency key. In the case that a
77
+ # request failed due to a connection problem and the client has retried too
78
+ # early, but the server is still executing the old request, we would like
79
+ # the client to continue retrying until getting a "real" response status
80
+ # back.
81
+ RestClient::Conflict,
82
+
83
+ # Retry on timeout-related problems. This shouldn't be lumped in with HTTP
84
+ # exceptions, but with RestClient it is.
85
+ RestClient::RequestTimeout,
86
+ ].freeze
87
+
71
88
  @api_base = 'https://api.stripe.com'
72
89
  @connect_base = 'https://connect.stripe.com'
73
90
  @uploads_base = 'https://uploads.stripe.com'
@@ -194,24 +211,45 @@ module Stripe
194
211
  def self.execute_request_with_rescues(request_opts, api_base_url, retry_count = 0)
195
212
  begin
196
213
  response = execute_request(request_opts)
197
- rescue SocketError => e
198
- response = handle_restclient_error(e, request_opts, retry_count, api_base_url)
199
- rescue NoMethodError => e
200
- # Work around RestClient bug
201
- if e.message =~ /\WRequestFailed\W/
202
- e = APIConnectionError.new('Unexpected HTTP response code')
214
+
215
+ # We rescue all exceptions from a request so that we have an easy spot to
216
+ # implement our retry logic across the board. We'll re-raise if it's a type
217
+ # of exception that we didn't expect to handle.
218
+ rescue => e
219
+ if should_retry?(e, retry_count)
220
+ retry_count = retry_count + 1
221
+ sleep sleep_time(retry_count)
222
+ retry
223
+ end
224
+
225
+ case e
226
+ when SocketError
227
+ response = handle_restclient_error(e, request_opts, retry_count, api_base_url)
228
+
229
+ when NoMethodError
230
+ # Work around RestClient bug
231
+ if e.message =~ /\WRequestFailed\W/
232
+ e = APIConnectionError.new('Unexpected HTTP response code')
233
+ response = handle_restclient_error(e, request_opts, retry_count, api_base_url)
234
+ else
235
+ raise
236
+ end
237
+
238
+ when RestClient::ExceptionWithResponse
239
+ if e.response
240
+ handle_api_error(e.response)
241
+ else
242
+ response = handle_restclient_error(e, request_opts, retry_count, api_base_url)
243
+ end
244
+
245
+ when RestClient::Exception, Errno::ECONNREFUSED, OpenSSL::SSL::SSLError
203
246
  response = handle_restclient_error(e, request_opts, retry_count, api_base_url)
247
+
248
+ # Only handle errors when we know we can do so, and re-raise otherwise.
249
+ # This should be pretty infrequent.
204
250
  else
205
251
  raise
206
252
  end
207
- rescue RestClient::ExceptionWithResponse => e
208
- if e.response
209
- handle_api_error(e.response)
210
- else
211
- response = handle_restclient_error(e, request_opts, retry_count, api_base_url)
212
- end
213
- rescue RestClient::Exception, Errno::ECONNREFUSED, OpenSSL::SSL::SSLError => e
214
- response = handle_restclient_error(e, request_opts, retry_count, api_base_url)
215
253
  end
216
254
 
217
255
  response
@@ -367,13 +405,6 @@ module Stripe
367
405
 
368
406
  def self.handle_restclient_error(e, request_opts, retry_count, api_base_url=nil)
369
407
 
370
- if should_retry?(e, retry_count)
371
- retry_count = retry_count + 1
372
- sleep sleep_time(retry_count)
373
- response = execute_request_with_rescues(request_opts, api_base_url, retry_count)
374
- return response
375
- end
376
-
377
408
  api_base_url = @api_base unless api_base_url
378
409
  connection_message = "Please check your internet connection and try again. " \
379
410
  "If this problem persists, you should check Stripe's service status at " \
@@ -419,7 +450,16 @@ module Stripe
419
450
 
420
451
  def self.should_retry?(e, retry_count)
421
452
  return false if retry_count >= self.max_network_retries
453
+
454
+ # Certificate validation problem: do not retry.
422
455
  return false if e.is_a?(RestClient::SSLCertificateNotVerified)
456
+
457
+ # Generally don't retry when we got a successful response back from the
458
+ # Stripe API server, but with some exceptions (for more details, see notes
459
+ # on RETRY_HTTP_EXCEPTIONS).
460
+ return false if e.is_a?(RestClient::ExceptionWithResponse) &&
461
+ !RETRY_HTTP_EXCEPTIONS.any? { |klass| e.is_a?(klass) }
462
+
423
463
  return true
424
464
  end
425
465
 
@@ -1,3 +1,3 @@
1
1
  module Stripe
2
- VERSION = '1.45.0'
2
+ VERSION = '1.46.0'
3
3
  end
@@ -685,14 +685,14 @@ module Stripe
685
685
  end
686
686
 
687
687
  context "with retries" do
688
-
689
688
  setup do
690
689
  Stripe.stubs(:max_network_retries).returns(2)
691
690
  end
692
691
 
693
692
  should 'retry failed network requests if specified and raise if error persists' do
694
693
  Stripe.expects(:sleep_time).at_least_once.returns(0)
695
- @mock.expects(:post).times(3).with('https://api.stripe.com/v1/charges', nil, 'amount=50&currency=usd').raises(Errno::ECONNREFUSED.new)
694
+ @mock.expects(:post).times(3).with('https://api.stripe.com/v1/charges', nil, 'amount=50&currency=usd').
695
+ raises(Errno::ECONNREFUSED.new)
696
696
 
697
697
  err = assert_raises Stripe::APIConnectionError do
698
698
  Stripe::Charge.create(:amount => 50, :currency => 'usd', :card => { :number => nil })
@@ -704,34 +704,15 @@ module Stripe
704
704
  Stripe.expects(:sleep_time).at_least_once.returns(0)
705
705
  response = make_response({"id" => "myid"})
706
706
  err = Errno::ECONNREFUSED.new
707
- @mock.expects(:post).times(2).with('https://api.stripe.com/v1/charges', nil, 'amount=50&currency=usd').raises(err).then.returns(response)
707
+ @mock.expects(:post).times(2).with('https://api.stripe.com/v1/charges', nil, 'amount=50&currency=usd').
708
+ raises(Errno::ECONNREFUSED.new).
709
+ then.
710
+ returns(response)
708
711
 
709
712
  result = Stripe::Charge.create(:amount => 50, :currency => 'usd', :card => { :number => nil })
710
713
  assert_equal "myid", result.id
711
714
  end
712
715
 
713
- # We retry the request if we receive SSL errors, since these can be caused
714
- # by transient network issues, in addition to compatibility issues between
715
- # the client and server.
716
- should 'retry failed network requests if they fail with OpenSSL::SSL::SSLError' do
717
- Stripe.expects(:sleep_time).at_least_once.returns(0)
718
- @mock.expects(:post).times(3).with('https://api.stripe.com/v1/charges', nil, 'amount=50&currency=usd').raises(OpenSSL::SSL::SSLError.new('message'))
719
-
720
- err = assert_raises Stripe::APIConnectionError do
721
- Stripe::Charge.create(:amount => 50, :currency => 'usd', :card => { :number => nil })
722
- end
723
- assert_match(/Request was retried 2 times/, err.message)
724
- end
725
-
726
- should 'not retry a SSLCertificateNotVerified error' do
727
- @mock.expects(:post).times(1).with('https://api.stripe.com/v1/charges', nil, 'amount=50&currency=usd').raises(RestClient::SSLCertificateNotVerified.new('message'))
728
-
729
- err = assert_raises Stripe::APIConnectionError do
730
- Stripe::Charge.create(:amount => 50, :currency => 'usd', :card => { :number => nil })
731
- end
732
- assert_no_match(/retried/, err.message)
733
- end
734
-
735
716
  should 'not add an idempotency key to GET requests' do
736
717
  SecureRandom.expects(:uuid).times(0)
737
718
  Stripe.expects(:execute_request).with do |opts|
@@ -770,8 +751,33 @@ module Stripe
770
751
 
771
752
  end
772
753
 
773
- context "sleep_time" do
754
+ context ".should_retry?" do
755
+ setup do
756
+ Stripe.stubs(:max_network_retries).returns(2)
757
+ end
758
+
759
+ should 'retry on a low-level network error' do
760
+ assert Stripe.should_retry?(Errno::ECONNREFUSED.new, 0)
761
+ end
762
+
763
+ should 'retry on timeout' do
764
+ assert Stripe.should_retry?(RestClient::RequestTimeout.new, 0)
765
+ end
774
766
 
767
+ should 'retry on a conflict' do
768
+ assert Stripe.should_retry?(RestClient::Conflict.new, 0)
769
+ end
770
+
771
+ should 'not retry at maximum count' do
772
+ refute Stripe.should_retry?(RuntimeError.new, Stripe.max_network_retries)
773
+ end
774
+
775
+ should 'not retry on a certificate validation error' do
776
+ refute Stripe.should_retry?(RestClient::SSLCertificateNotVerified.new('message'), 0)
777
+ end
778
+ end
779
+
780
+ context ".sleep_time" do
775
781
  should "should grow exponentially" do
776
782
  Stripe.stubs(:rand).returns(1)
777
783
  Stripe.stubs(:max_network_retry_delay).returns(999)
@@ -808,7 +814,6 @@ module Stripe
808
814
  assert_equal(base_value * 4, Stripe.sleep_time(3))
809
815
  assert_equal(base_value * 8, Stripe.sleep_time(4))
810
816
  end
811
-
812
817
  end
813
818
  end
814
819
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stripe
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.45.0
4
+ version: 1.46.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stripe