diff --git a/gcloud-java-core/src/main/java/com/google/gcloud/BaseServiceException.java b/gcloud-java-core/src/main/java/com/google/gcloud/BaseServiceException.java index 4e0d03e0073a..db322128b845 100644 --- a/gcloud-java-core/src/main/java/com/google/gcloud/BaseServiceException.java +++ b/gcloud-java-core/src/main/java/com/google/gcloud/BaseServiceException.java @@ -48,10 +48,16 @@ protected static final class Error implements Serializable { private final Integer code; private final String reason; + private final boolean rejected; public Error(Integer code, String reason) { + this(code, reason, false); + } + + public Error(Integer code, String reason, boolean rejected) { this.code = code; this.reason = reason; + this.rejected = rejected; } /** @@ -61,6 +67,14 @@ public Integer code() { return code; } + /** + * Returns true if the error indicates that the API call was certainly not accepted by the + * server. + */ + public boolean rejected() { + return rejected; + } + /** * Returns the reason that caused the exception. */ @@ -68,10 +82,11 @@ public String reason() { return reason; } - boolean isRetryable(Set retryableErrors) { + boolean isRetryable(boolean idempotent, Set retryableErrors) { for (Error retryableError : retryableErrors) { - if ((retryableError.code() == null || retryableError.code().equals(this.code())) - && (retryableError.reason() == null || retryableError.reason().equals(this.reason()))) { + boolean match = (retryableError.code() == null || retryableError.code().equals(this.code())) + && (retryableError.reason() == null || retryableError.reason().equals(this.reason())); + if (match && idempotent || match && retryableError.rejected()) { return true; } } @@ -111,7 +126,7 @@ public BaseServiceException(IOException exception, boolean idempotent) { } } this.code = code; - this.retryable = idempotent && isRetryable(exception); + this.retryable = isRetryable(idempotent, exception); this.reason = reason; this.idempotent = idempotent; this.location = location; @@ -123,7 +138,7 @@ public BaseServiceException(GoogleJsonError error, boolean idempotent) { this.code = error.getCode(); this.reason = reason(error); this.idempotent = idempotent; - this.retryable = idempotent && isRetryable(error); + this.retryable = isRetryable(idempotent, error); this.location = null; this.debugInfo = null; } @@ -138,7 +153,7 @@ public BaseServiceException(int code, String message, String reason, boolean ide this.code = code; this.reason = reason; this.idempotent = idempotent; - this.retryable = idempotent && new Error(code, reason).isRetryable(retryableErrors()); + this.retryable = new Error(code, reason).isRetryable(idempotent, retryableErrors()); this.location = null; this.debugInfo = null; } @@ -147,15 +162,15 @@ protected Set retryableErrors() { return Collections.emptySet(); } - protected boolean isRetryable(GoogleJsonError error) { - return error != null && error(error).isRetryable(retryableErrors()); + protected boolean isRetryable(boolean idempotent, GoogleJsonError error) { + return error != null && error(error).isRetryable(idempotent, retryableErrors()); } - protected boolean isRetryable(IOException exception) { + protected boolean isRetryable(boolean idempotent, IOException exception) { if (exception instanceof GoogleJsonResponseException) { - return isRetryable(((GoogleJsonResponseException) exception).getDetails()); + return isRetryable(idempotent, (((GoogleJsonResponseException) exception).getDetails())); } - return exception instanceof SocketTimeoutException; + return idempotent && exception instanceof SocketTimeoutException; } /** @@ -187,8 +202,8 @@ public boolean idempotent() { } /** - * Returns the service location where the error causing the exception occurred. Returns - * {@code null} if not set. + * Returns the service location where the error causing the exception occurred. Returns {@code + * null} if not set. */ public String location() { return location; @@ -224,7 +239,7 @@ public int hashCode() { } protected static String reason(GoogleJsonError error) { - if (error.getErrors() != null && !error.getErrors().isEmpty()) { + if (error.getErrors() != null && !error.getErrors().isEmpty()) { return error.getErrors().get(0).getReason(); } return null; diff --git a/gcloud-java-dns/src/main/java/com/google/gcloud/dns/DnsException.java b/gcloud-java-dns/src/main/java/com/google/gcloud/dns/DnsException.java index 169e56f58b7b..e385b362cdae 100644 --- a/gcloud-java-dns/src/main/java/com/google/gcloud/dns/DnsException.java +++ b/gcloud-java-dns/src/main/java/com/google/gcloud/dns/DnsException.java @@ -31,12 +31,12 @@ public class DnsException extends BaseServiceException { // see: https://cloud.google.com/dns/troubleshooting private static final Set RETRYABLE_ERRORS = ImmutableSet.of( - new Error(429, null), - new Error(500, null), - new Error(502, null), - new Error(503, null), - new Error(null, "userRateLimitExceeded"), - new Error(null, "rateLimitExceeded")); + new Error(429, null, true), + new Error(500, null, false), + new Error(502, null, false), + new Error(503, null, false), + new Error(null, "userRateLimitExceeded", true), + new Error(null, "rateLimitExceeded", true)); private static final long serialVersionUID = 490302380416260252L; public DnsException(IOException exception, boolean idempotent) {