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 +4 -4
- data/History.txt +4 -0
- data/VERSION +1 -1
- data/lib/stripe.rb +61 -21
- data/lib/stripe/version.rb +1 -1
- data/test/stripe/api_resource_test.rb +32 -27
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d883d1c0eb0486e3c51e5076178c4351ca70ee68
|
4
|
+
data.tar.gz: a992c6c4e854019538a0406dbca5382c8f99d77e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: caf72f6851481ed302b8d06d450b55cf72c260104e549c099f52bb7477ec0ec28777648f4d3e4edae0f1c96cfec8123248a645cb316325cefec4f04cab74fab8
|
7
|
+
data.tar.gz: 165a6679fea615754af43de70e04c5d33a225ad1e938222e7c13767736bcdd9955162b22f266044f20818758ec3bcae0bb366c1c641b3fe1a388ed441315264b
|
data/History.txt
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.46.0
|
data/lib/stripe.rb
CHANGED
@@ -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
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
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
|
|
data/lib/stripe/version.rb
CHANGED
@@ -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¤cy=usd').
|
694
|
+
@mock.expects(:post).times(3).with('https://api.stripe.com/v1/charges', nil, 'amount=50¤cy=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¤cy=usd').
|
707
|
+
@mock.expects(:post).times(2).with('https://api.stripe.com/v1/charges', nil, 'amount=50¤cy=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¤cy=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¤cy=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 "
|
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
|