Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: update retries and implement Retryable #750

Merged
merged 39 commits into from
Feb 7, 2022
Merged
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
70b01b7
feat: update retries and implement Retryable
TimurSadykov Sep 28, 2021
b9bbc1f
fix: retry logic fix
TimurSadykov Sep 29, 2021
11c9ffa
feat: add RetryStrategy setting to GoogleCredential and ServiceAccoun…
TimurSadykov Oct 7, 2021
2791b9a
fix: refactor retryable interface
TimurSadykov Nov 7, 2021
fd7a446
Merge remote-tracking branch 'origin/main' into stim-common-retry
TimurSadykov Nov 15, 2021
190d191
fix: javadocs
TimurSadykov Nov 15, 2021
8c0991c
🦉 Updates from OwlBot
gcf-owl-bot[bot] Nov 15, 2021
d863ce8
fix: remove RetryStrategy
TimurSadykov Nov 16, 2021
c6ef5c5
fix: change set definition to java 8 compatible
TimurSadykov Nov 16, 2021
e92c65b
🦉 Updates from OwlBot
gcf-owl-bot[bot] Nov 16, 2021
f8d6842
feat: tests for new retries
TimurSadykov Nov 17, 2021
7b4e490
🦉 Updates from OwlBot
gcf-owl-bot[bot] Nov 17, 2021
5aef1f7
fix: update method name
TimurSadykov Nov 21, 2021
fc7bcb4
fix: temporary poms
TimurSadykov Nov 21, 2021
67cfaab
🦉 Updates from OwlBot
gcf-owl-bot[bot] Nov 21, 2021
5bd45cf
fix: refactor to move response handling into the specific credential …
TimurSadykov Jan 7, 2022
7e7f437
🦉 Updates from OwlBot
gcf-owl-bot[bot] Jan 7, 2022
22b2ce5
fix: update dependencies with release builds
TimurSadykov Jan 7, 2022
e11b257
fix: http-client dependency fix
TimurSadykov Jan 7, 2022
626cb41
fix: http-client dependency fix
TimurSadykov Jan 7, 2022
e1910c2
remove unused dependency
TimurSadykov Jan 10, 2022
eef2030
feat: additional factory method
TimurSadykov Jan 11, 2022
d7bef21
feat: flag to disable default retries and tests
TimurSadykov Jan 12, 2022
577bfef
🦉 Updates from OwlBot
gcf-owl-bot[bot] Jan 12, 2022
d88bc10
fix: merge conflict
TimurSadykov Jan 13, 2022
c22fb51
fix: (WIF) remove erroneous check for the subject token field name fo…
lsirac Jan 10, 2022
fe7a059
chore(deps): update dependency org.apache.maven.plugins:maven-compile…
renovate-bot Jan 12, 2022
fff63de
chore(deps): update dependency org.apache.maven.plugins:maven-checkst…
renovate-bot Jan 12, 2022
52aacd6
🦉 Updates from OwlBot
gcf-owl-bot[bot] Jan 13, 2022
c14a620
Merge remote-tracking branch 'origin/main' into stim-common-retry
TimurSadykov Jan 13, 2022
afb3a50
fix: nit remove extra ;
TimurSadykov Jan 14, 2022
10a0c0c
merge latest
TimurSadykov Feb 1, 2022
1adab2c
feat: generate retryable exceptions for UserCredentials
TimurSadykov Feb 2, 2022
b533e65
🦉 Updates from OwlBot
gcf-owl-bot[bot] Feb 2, 2022
7404928
Merge branch 'main' into stim-common-retry
arithmetic1728 Feb 2, 2022
4363aba
fix: remove public from exception constructors, leverage builder in S…
TimurSadykov Feb 4, 2022
d309720
🦉 Updates from OwlBot
gcf-owl-bot[bot] Feb 4, 2022
23d38a5
fix: update ServiceAccountCredentials docs
TimurSadykov Feb 7, 2022
d85aee4
🦉 Updates from OwlBot
gcf-owl-bot[bot] Feb 7, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ target/

# Intellij
*.iml
*.factorypath
.idea/

# VS Code
Expand Down
4 changes: 3 additions & 1 deletion credentials/java/com/google/auth/Credentials.java
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,9 @@ protected final void blockingGetToCallback(URI uri, RequestMetadataCallback call
*
* @param uri URI of the entry point for the request.
* @return The request metadata used for populating headers or other context.
* @throws IOException if there was an error getting up-to-date access.
* @throws IOException if there was an error getting up-to-date access. The exception should
* implement {@link Retryable} and {@code isRetryable()} will return true if the operation may
* be retried.
*/
public abstract Map<String, List<String>> getRequestMetadata(URI uri) throws IOException;

Expand Down
49 changes: 49 additions & 0 deletions credentials/java/com/google/auth/Retryable.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright 2022 Google LLC
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Google LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package com.google.auth;

// an interface to identify retryable errors
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/** Retryable is an interface to identify retryable errors. */

public interface Retryable {
TimurSadykov marked this conversation as resolved.
Show resolved Hide resolved
/**
* A flag indicating whether the error is retryable
*
* @return true if related error is retryable, false otherwise
*/
boolean isRetryable();

/**
* Gets a number of performed retries for related HttpRequest
*
* @return a number of performed retries
*/
int getRetryCount();
}
157 changes: 157 additions & 0 deletions oauth2_http/java/com/google/auth/oauth2/GoogleAuthException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/*
* Copyright 2022 Google LLC
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Google LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package com.google.auth.oauth2;

import com.google.api.client.http.HttpResponseException;
import com.google.auth.Retryable;
import java.io.IOException;

/**
* Base class for the standard Auth error response. It extends a default exception while keeping
* Json response format
*/
class GoogleAuthException extends IOException implements Retryable {

private final boolean isRetryable;
private final int retryCount;

/**
* Constructor with all parameters
*
* @param isRetryable A retry status for the related HTTP request
* @param retryCount A number of retries performed for the related HTTP request
* @param message The detail message (which is saved for later retrieval by the {@link
* #getMessage()} method)
* @param cause The cause (which is saved for later retrieval by the {@link #getCause()} method).
* (A null value is permitted, and indicates that the cause is nonexistent or unknown.)
*/
GoogleAuthException(boolean isRetryable, int retryCount, String message, Throwable cause) {
super(message, cause);
this.isRetryable = isRetryable;
this.retryCount = retryCount;
}

/**
* Constructor with message defaulted to the cause
*
* @param isRetryable A retry status for the related HTTP request
* @param retryCount A number of retries performed for the related HTTP request
* @param cause The cause (which is saved for later retrieval by the {@link #getCause()} method).
* (A null value is permitted, and indicates that the cause is nonexistent or unknown.) If the
* cause has retry information, it is going to be skipped in favor of the {@code retryCount}
* parameter
*/
GoogleAuthException(boolean isRetryable, int retryCount, Throwable cause) {
super(cause);
this.isRetryable = isRetryable;
this.retryCount = retryCount;
}

/**
* Constructor without explicit retry count.
*
* @param isRetryable A retry status for the related HTTP request
* @param cause The cause (which is saved for later retrieval by the {@link #getCause()} method).
* (A null value is permitted, and indicates that the cause is nonexistent or unknown.)
*/
GoogleAuthException(boolean isRetryable, Throwable cause) {
super(cause);
this.isRetryable = isRetryable;
this.retryCount = 0;
}

/**
* Constructor without retry info
*
* @param cause The cause (which is saved for later retrieval by the {@link #getCause()} method).
* (A null value is permitted, and indicates that the cause is nonexistent or unknown.)
*/
GoogleAuthException(Throwable cause) {
this(false, cause);
}

/** A default Constructor */
GoogleAuthException() {
super();
this.isRetryable = false;
this.retryCount = 0;
}

/**
* Creates an instance of the exception based on {@link HttpResponseException} and a custom error
* message.
*
* @see #createWithTokenEndpointResponseException(HttpResponseException, String)
* @param responseException an instance of {@link HttpResponseException}
* @param message The detail message (which is saved for later retrieval by the {@link
* #getMessage()} method)
* @return new instance of {@link GoogleAuthException}
*/
static GoogleAuthException createWithTokenEndpointResponseException(
HttpResponseException responseException, String message) {
int responseStatus = responseException.getStatusCode();
boolean isRetryable =
OAuth2Utils.TOKEN_ENDPOINT_RETRYABLE_STATUS_CODES.contains(responseStatus);
int retryCount = responseException.getAttemptCount() - 1;

if (message == null) {
return new GoogleAuthException(isRetryable, retryCount, responseException);
} else {
return new GoogleAuthException(isRetryable, retryCount, message, responseException);
}
}

/**
* Creates an instance of the exception based on {@link HttpResponseException} returned by Google
* token endpoint. It uses response status code information to populate the {@code #isRetryable}
* property and a number of performed attempts to populate the {@code #retryCount} property
*
* @param responseException an instance of {@link HttpResponseException}
* @return new instance of {@link GoogleAuthException}
*/
static GoogleAuthException createWithTokenEndpointResponseException(
HttpResponseException responseException) {
return GoogleAuthException.createWithTokenEndpointResponseException(responseException, null);
}

/** Returns true if the error is retryable, false otherwise */
@Override
public boolean isRetryable() {
return isRetryable;
}

/** Returns number of reties performed for the related HTTP request */
@Override
public int getRetryCount() {
return retryCount;
}
}
24 changes: 17 additions & 7 deletions oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java
Original file line number Diff line number Diff line change
Expand Up @@ -243,8 +243,8 @@ public boolean createScopedRequired() {
}

/**
* If the credentials support scopes, creates a copy of the the identity with the specified
* scopes; otherwise, returns the same instance.
* If the credentials support scopes, creates a copy of the identity with the specified scopes;
* otherwise, returns the same instance.
*
* @param scopes Collection of scopes to request.
* @return GoogleCredentials with requested scopes.
Expand All @@ -254,9 +254,8 @@ public GoogleCredentials createScoped(Collection<String> scopes) {
}

/**
* If the credentials support scopes, creates a copy of the the identity with the specified scopes
* and default scopes; otherwise, returns the same instance. This is mainly used by client
* libraries.
* If the credentials support scopes, creates a copy of the identity with the specified scopes and
* default scopes; otherwise, returns the same instance. This is mainly used by client libraries.
*
* @param scopes Collection of scopes to request.
* @param defaultScopes Collection of default scopes to request.
Expand All @@ -268,8 +267,8 @@ public GoogleCredentials createScoped(
}

/**
* If the credentials support scopes, creates a copy of the the identity with the specified
* scopes; otherwise, returns the same instance.
* If the credentials support scopes, creates a copy of the identity with the specified scopes;
* otherwise, returns the same instance.
*
* @param scopes Collection of scopes to request.
* @return GoogleCredentials with requested scopes.
Expand All @@ -278,6 +277,17 @@ public GoogleCredentials createScoped(String... scopes) {
return createScoped(ImmutableList.copyOf(scopes));
}

/**
* If the credentials support automatic retries, creates a copy of the identity with the provided
* retry strategy
*
* @param defaultRetriesEnabled a flag enabling or disabling default retries
* @return GoogleCredentials with the new default retries configuration.
*/
public GoogleCredentials createWithCustomRetryStrategy(boolean defaultRetriesEnabled) {
TimurSadykov marked this conversation as resolved.
Show resolved Hide resolved
return this;
}

/**
* If the credentials support domain-wide delegation, creates a copy of the identity so that it
* impersonates the specified user; otherwise, returns the same instance.
Expand Down
8 changes: 8 additions & 0 deletions oauth2_http/java/com/google/auth/oauth2/OAuth2Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,11 @@
import java.math.BigDecimal;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/** Internal utilities for the com.google.auth.oauth2 namespace. */
class OAuth2Utils {
Expand All @@ -74,6 +77,11 @@ class OAuth2Utils {

static final String BEARER_PREFIX = AuthHttpConstants.BEARER + " ";

// Includes expected server errors from Google token endpoint
// Other 5xx codes are either not used or retries are unlikely to succeed
public static final Set<Integer> TOKEN_ENDPOINT_RETRYABLE_STATUS_CODES =
new HashSet<>(Arrays.asList(500, 503, 408, 429));

static class DefaultHttpTransportFactory implements HttpTransportFactory {

public HttpTransport create() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,13 @@

import static com.google.common.base.Preconditions.checkNotNull;

import java.io.IOException;
import javax.annotation.Nullable;

/**
* Encapsulates the standard OAuth error response. See
* https://tools.ietf.org/html/rfc6749#section-5.2.
*/
class OAuthException extends IOException {
class OAuthException extends GoogleAuthException {

private final String errorCode;
@Nullable private final String errorDescription;
Expand Down
Loading