Skip to content

Commit 3675514

Browse files
authored
fix: add retries for auth service errors which are tagged Retryable (#2026)
1 parent 260b6e5 commit 3675514

File tree

2 files changed

+52
-0
lines changed

2 files changed

+52
-0
lines changed

google-cloud-storage/src/main/java/com/google/cloud/storage/DefaultStorageRetryStrategy.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import com.fasterxml.jackson.core.io.JsonEOFException;
2020
import com.google.api.client.http.HttpResponseException;
21+
import com.google.auth.Retryable;
2122
import com.google.cloud.BaseServiceException;
2223
import com.google.cloud.ExceptionHandler;
2324
import com.google.cloud.ExceptionHandler.Interceptor;
@@ -84,6 +85,9 @@ public RetryResult beforeEval(Exception exception) {
8485
} else if (exception instanceof HttpResponseException) {
8586
int code = ((HttpResponseException) exception).getStatusCode();
8687
return shouldRetryCodeReason(code, null);
88+
} else if (exception instanceof Retryable) {
89+
Retryable retryable = (Retryable) exception;
90+
return (idempotent && retryable.isRetryable()) ? RetryResult.RETRY : RetryResult.NO_RETRY;
8791
} else if (exception instanceof IOException) {
8892
IOException ioException = (IOException) exception;
8993
return shouldRetryIOException(ioException);

google-cloud-storage/src/test/java/com/google/cloud/storage/DefaultRetryHandlingBehaviorTest.java

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import com.google.api.client.http.HttpHeaders;
2828
import com.google.api.client.http.HttpResponseException;
2929
import com.google.api.gax.retrying.ResultRetryAlgorithm;
30+
import com.google.auth.Retryable;
3031
import com.google.common.collect.ImmutableList;
3132
import com.google.common.collect.ImmutableSet;
3233
import com.google.common.collect.Sets;
@@ -339,6 +340,8 @@ enum ThrowableCategory {
339340
STORAGE_EXCEPTION_0_GSON_MALFORMED_EXCEPTION(
340341
new StorageException(0, "parse error", C.GSON_MALFORMED_EXCEPTION)),
341342
IO_EXCEPTION(new IOException("no retry")),
343+
AUTH_RETRYABLE_TRUE(new RetryableException(true)),
344+
AUTH_RETRYABLE_FALSE(new RetryableException(false)),
342345
;
343346

344347
private final Throwable throwable;
@@ -1042,7 +1045,52 @@ private static ImmutableList<Case> getAllCases() {
10421045
ThrowableCategory.STORAGE_EXCEPTION_0_GSON_MALFORMED_EXCEPTION,
10431046
HandlerCategory.NONIDEMPOTENT,
10441047
ExpectRetry.NO,
1048+
Behavior.SAME),
1049+
new Case(
1050+
ThrowableCategory.AUTH_RETRYABLE_TRUE,
1051+
HandlerCategory.IDEMPOTENT,
1052+
ExpectRetry.YES,
1053+
Behavior.DEFAULT_MORE_PERMISSIBLE),
1054+
new Case(
1055+
ThrowableCategory.AUTH_RETRYABLE_TRUE,
1056+
HandlerCategory.NONIDEMPOTENT,
1057+
ExpectRetry.NO,
1058+
Behavior.SAME),
1059+
new Case(
1060+
ThrowableCategory.AUTH_RETRYABLE_FALSE,
1061+
HandlerCategory.IDEMPOTENT,
1062+
ExpectRetry.NO,
1063+
Behavior.SAME),
1064+
new Case(
1065+
ThrowableCategory.AUTH_RETRYABLE_FALSE,
1066+
HandlerCategory.NONIDEMPOTENT,
1067+
ExpectRetry.NO,
10451068
Behavior.SAME))
10461069
.build();
10471070
}
1071+
1072+
/**
1073+
* The auth library provides the interface {@link Retryable} to annotate an exception as
1074+
* retryable. Add a definition here. Explicitly extend IOException to ensure our handling of this
1075+
* type is sooner than IOExceptions
1076+
*/
1077+
private static final class RetryableException extends IOException implements Retryable {
1078+
1079+
private final boolean isRetryable;
1080+
1081+
private RetryableException(boolean isRetryable) {
1082+
super(String.format("RetryableException{isRetryable=%s}", isRetryable));
1083+
this.isRetryable = isRetryable;
1084+
}
1085+
1086+
@Override
1087+
public boolean isRetryable() {
1088+
return isRetryable;
1089+
}
1090+
1091+
@Override
1092+
public int getRetryCount() {
1093+
return 0;
1094+
}
1095+
}
10481096
}

0 commit comments

Comments
 (0)