@@ -118,6 +118,7 @@ def initialize(options={})
118
118
self . key = options [ :key ]
119
119
self . user_ip = options [ :user_ip ]
120
120
self . retries = options . fetch ( :retries ) { 0 }
121
+ self . expired_auth_retry = options . fetch ( :expired_auth_retry ) { true }
121
122
@discovery_uris = { }
122
123
@discovery_documents = { }
123
124
@discovered_apis = { }
@@ -255,6 +256,13 @@ def authorization=(new_authorization)
255
256
# Number of retries
256
257
attr_accessor :retries
257
258
259
+ ##
260
+ # Whether or not an expired auth token should be re-acquired
261
+ # (and the operation retried) regardless of retries setting
262
+ # @return [Boolean]
263
+ # Auto retry on auth expiry
264
+ attr_accessor :expired_auth_retry
265
+
258
266
##
259
267
# Returns the URI for the directory document.
260
268
#
@@ -613,28 +621,40 @@ def execute!(*params)
613
621
request . authorization = options [ :authorization ] || self . authorization unless options [ :authenticated ] == false
614
622
615
623
tries = 1 + ( options [ :retries ] || self . retries )
624
+ attempt = 0
616
625
617
626
Retriable . retriable :tries => tries ,
618
627
:on => [ TransmissionError ] ,
619
- :on_retry => client_error_handler ( request . authorization ) ,
628
+ :on_retry => client_error_handler ,
620
629
:interval => lambda { |attempts | ( 2 ** attempts ) + rand } do
621
- result = request . send ( connection , true )
622
-
623
- case result . status
624
- when 200 ...300
625
- result
626
- when 301 , 302 , 303 , 307
627
- request = generate_request ( request . to_hash . merge ( {
628
- :uri => result . headers [ 'location' ] ,
629
- :api_method => nil
630
- } ) )
631
- raise RedirectError . new ( result . headers [ 'location' ] , result )
632
- when 400 ...500
633
- raise ClientError . new ( result . error_message || "A client error has occurred" , result )
634
- when 500 ...600
635
- raise ServerError . new ( result . error_message || "A server error has occurred" , result )
636
- else
637
- raise TransmissionError . new ( result . error_message || "A transmission error has occurred" , result )
630
+ attempt += 1
631
+
632
+ # This 2nd level retriable only catches auth errors, and supports 1 retry, which allows
633
+ # auth to be re-attempted without having to retry all sorts of other failures like
634
+ # NotFound, etc
635
+ Retriable . retriable :tries => ( ( expired_auth_retry || tries > 1 ) && attempt == 1 ) ? 2 : 1 ,
636
+ :on => [ AuthorizationError ] ,
637
+ :on_retry => authorization_error_handler ( request . authorization ) do
638
+ result = request . send ( connection , true )
639
+
640
+ case result . status
641
+ when 200 ...300
642
+ result
643
+ when 301 , 302 , 303 , 307
644
+ request = generate_request ( request . to_hash . merge ( {
645
+ :uri => result . headers [ 'location' ] ,
646
+ :api_method => nil
647
+ } ) )
648
+ raise RedirectError . new ( result . headers [ 'location' ] , result )
649
+ when 401
650
+ raise AuthorizationError . new ( result . error_message || 'Invalid/Expired Authentication' , result )
651
+ when 400 , 402 ...500
652
+ raise ClientError . new ( result . error_message || "A client error has occurred" , result )
653
+ when 500 ...600
654
+ raise ServerError . new ( result . error_message || "A server error has occurred" , result )
655
+ else
656
+ raise TransmissionError . new ( result . error_message || "A transmission error has occurred" , result )
657
+ end
638
658
end
639
659
end
640
660
end
@@ -682,18 +702,17 @@ def resolve_uri(template, mapping={})
682
702
683
703
684
704
##
685
- # Returns on proc for special processing of retries as not all client errors
686
- # are recoverable. Only 401s should be retried and only if the credentials
687
- # are refreshable
705
+ # Returns on proc for special processing of retries for authorization errors
706
+ # Only 401s should be retried and only if the credentials are refreshable
688
707
#
689
708
# @param [#fetch_access_token!] authorization
690
709
# OAuth 2 credentials
691
- # @return [Proc]
692
- def client_error_handler ( authorization )
710
+ # @return [Proc]
711
+ def authorization_error_handler ( authorization )
693
712
can_refresh = authorization . respond_to? ( :refresh_token ) && auto_refresh_token
694
713
Proc . new do |exception , tries |
695
- next unless exception . kind_of? ( ClientError )
696
- if exception . result . status == 401 && can_refresh && tries == 1
714
+ next unless exception . kind_of? ( AuthorizationError )
715
+ if can_refresh
697
716
begin
698
717
logger . debug ( "Attempting refresh of access token & retry of request" )
699
718
authorization . fetch_access_token!
@@ -705,6 +724,17 @@ def client_error_handler(authorization)
705
724
end
706
725
end
707
726
727
+ ##
728
+ # Returns on proc for special processing of retries as not all client errors
729
+ # are recoverable. Only 401s should be retried (via authorization_error_handler)
730
+ #
731
+ # @return [Proc]
732
+ def client_error_handler
733
+ Proc . new do |exception , tries |
734
+ raise exception if exception . kind_of? ( ClientError )
735
+ end
736
+ end
737
+
708
738
end
709
739
710
740
end
0 commit comments