From 2bed0748ab1ed3e0941d5fb22733f775d757fff6 Mon Sep 17 00:00:00 2001 From: Doug Henderson Date: Thu, 13 Mar 2014 11:20:08 -0700 Subject: [PATCH] Add auto retry logic for auth expiry separate from normal failure retry --- README.md | 2 ++ lib/google/api_client.rb | 43 ++++++++++++++++++++------------- lib/google/api_client/errors.rb | 5 ++++ 3 files changed, 33 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index f39694953..1c71e2d09 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,8 @@ in the credentials. Detailed instructions on how to enable delegation for your d The API client can automatically retry requests for recoverable errors. To enable retries, set the `client.retries` property to the number of additional attempts. To avoid flooding servers, retries invovle a 1 second delay that increases on each subsequent retry. +In the case of authentication token expiry, the API client will attempt to refresh the token and retry the failed operation - this +is a specific exception to the retry rules. The default value for retries is 0, but will be enabled by default in future releases. diff --git a/lib/google/api_client.rb b/lib/google/api_client.rb index c79c71b58..c5648081c 100644 --- a/lib/google/api_client.rb +++ b/lib/google/api_client.rb @@ -596,25 +596,34 @@ module Google Retriable.retriable :tries => tries, :on => [TransmissionError], - :on_retry => client_error_handler(request.authorization), :interval => lambda {|attempts| (2 ** attempts) + rand} do - result = request.send(connection, true) + # This 2nd level retriable only catches auth errors, and supports 1 retry, which allows + # auth to be re-attempted without having to retry all sorts of other failures like + # NotFound, etc + Retriable.retriable :tries => 2, + :on => [AuthorizationError], + :on_retry => client_error_handler(request.authorization), + :interval => lambda {|attempts| (2 ** attempts) + rand} do + result = request.send(connection, true) - case result.status - when 200...300 - result - when 301, 302, 303, 307 - request = generate_request(request.to_hash.merge({ - :uri => result.headers['location'], - :api_method => nil - })) - raise RedirectError.new(result.headers['location'], result) - when 400...500 - raise ClientError.new(result.error_message || "A client error has occurred", result) - when 500...600 - raise ServerError.new(result.error_message || "A server error has occurred", result) - else - raise TransmissionError.new(result.error_message || "A transmission error has occurred", result) + case result.status + when 200...300 + result + when 301, 302, 303, 307 + request = generate_request(request.to_hash.merge({ + :uri => result.headers['location'], + :api_method => nil + })) + raise RedirectError.new(result.headers['location'], result) + when 401 + raise AuthorizationError.new(result.error_message || 'Invalid/Expired Authentication', result) + when 400, 402...500 + raise ClientError.new(result.error_message || "A client error has occurred", result) + when 500...600 + raise ServerError.new(result.error_message || "A server error has occurred", result) + else + raise TransmissionError.new(result.error_message || "A transmission error has occurred", result) + end end end end diff --git a/lib/google/api_client/errors.rb b/lib/google/api_client/errors.rb index f12ad6daa..9644c692a 100644 --- a/lib/google/api_client/errors.rb +++ b/lib/google/api_client/errors.rb @@ -43,6 +43,11 @@ module Google class ClientError < TransmissionError end + ## + # A 401 HTTP error occurred. + class AuthorizationError < ClientError + end + ## # A 5xx class HTTP error occurred. class ServerError < TransmissionError