Skip to content

Commit 2cd1c91

Browse files
committed
addressed comments
1 parent 863132c commit 2cd1c91

3 files changed

Lines changed: 36 additions & 42 deletions

File tree

src/main/java/io/cdap/plugin/gcp/common/GCPUtils.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ public class GCPUtils {
9191
public static final int BQ_DEFAULT_READ_TIMEOUT_SECONDS = 120;
9292
public static final String DATASTORE_SUPPORTED_DOC_URL = "https://cloud.google.com/datastore/docs/concepts/errors";
9393
public static final String BIG_TABLE_SUPPORTED_DOC_URL = "https://cloud.google.com/bigtable/docs/status-codes";
94+
public static final String GCE_METADATA_SERVER_ERROR_SUPPORTED_DOC_URL =
95+
"https://cloud.google.com/compute/docs/troubleshooting/troubleshoot-metadata-server";
9496

9597
/**
9698
* Load a service account from the local file system.

src/main/java/io/cdap/plugin/gcp/common/ServerErrorException.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,10 @@ public class ServerErrorException extends RuntimeException {
3131
*
3232
* @param statusCode the HTTP status code (should be in the 5xx range)
3333
* @param message the detail message explaining the error
34+
* @param cause the original cause of the error
3435
*/
35-
public ServerErrorException(int statusCode, String message) {
36-
super("Server error [" + statusCode + "]: " + message);
36+
public ServerErrorException(int statusCode, String message, Throwable cause) {
37+
super("Server error [" + statusCode + "]: " + message, cause);
3738
this.statusCode = statusCode;
3839
}
3940

src/main/java/io/cdap/plugin/gcp/gcs/ServiceAccountAccessTokenProvider.java

Lines changed: 31 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,10 @@
2222
import com.google.cloud.hadoop.util.AccessTokenProvider;
2323
import com.google.cloud.hadoop.util.CredentialFactory;
2424
import dev.failsafe.Failsafe;
25+
import dev.failsafe.FailsafeException;
2526
import dev.failsafe.RetryPolicy;
26-
import io.cdap.cdap.api.exception.ErrorCategory;
27-
import io.cdap.cdap.api.exception.ErrorCategory.ErrorCategoryEnum;
2827
import io.cdap.cdap.api.exception.ErrorType;
29-
import io.cdap.cdap.api.exception.ErrorUtils;
30-
import io.cdap.plugin.gcp.bigquery.source.BigQuerySourceConfig;
31-
import io.cdap.plugin.gcp.bigquery.util.BigQueryConstants;
28+
import io.cdap.plugin.gcp.common.GCPErrorDetailsProviderUtil;
3229
import io.cdap.plugin.gcp.common.GCPUtils;
3330
import io.cdap.plugin.gcp.common.ServerErrorException;
3431
import org.apache.hadoop.conf.Configuration;
@@ -40,6 +37,7 @@
4037
import java.time.Duration;
4138
import java.time.Instant;
4239
import java.util.Date;
40+
import java.util.regex.Pattern;
4341
import java.util.stream.Collectors;
4442
import java.util.stream.Stream;
4543

@@ -52,68 +50,61 @@ public class ServiceAccountAccessTokenProvider implements AccessTokenProvider {
5250
private Configuration conf;
5351
private GoogleCredentials credentials;
5452
private static final Gson GSON = new Gson();
55-
private static final Logger logger = LoggerFactory.getLogger(ServiceAccountAccessTokenProvider.class);
53+
private static final Logger LOG = LoggerFactory.getLogger(ServiceAccountAccessTokenProvider.class);
5654
public static final int DEFAULT_INITIAL_RETRY_DURATION_SECONDS = 5;
5755
public static final int DEFAULT_MAX_RETRY_COUNT = 5;
5856
public static final int DEFAULT_MAX_RETRY_DURATION_SECONDS = 80;
59-
57+
private static final RetryPolicy<Object> RETRY_POLICY = createRetryPolicy();
58+
private static final Pattern SERVER_ERROR_PATTERN = Pattern.compile("Unexpected Error code 5\\d{2} trying to get " +
59+
"security access token from Compute Engine metadata for the default service account.*");
6060

6161
@Override
6262
public AccessToken getAccessToken() {
63-
int initialRetryDuration = DEFAULT_INITIAL_RETRY_DURATION_SECONDS;
64-
int maxRetryCount = DEFAULT_MAX_RETRY_COUNT;
65-
int maxRetryDuration = DEFAULT_MAX_RETRY_DURATION_SECONDS;
66-
logger.debug(
67-
"Initializing RetryPolicy with the following configuration: MaxRetryCount: {}, InitialRetryDuration: {}s, " +
68-
"MaxRetryDuration: {}s", maxRetryCount, initialRetryDuration, maxRetryDuration);
6963
try {
70-
return Failsafe.with(getRetryPolicy(initialRetryDuration, maxRetryDuration, maxRetryCount))
71-
.get(() -> {
72-
com.google.auth.oauth2.AccessToken token = safeGetAccessToken();
64+
return Failsafe.with(RETRY_POLICY).get(() -> {
65+
com.google.auth.oauth2.AccessToken token = retrieveAccessToken();
7366
if (token == null || token.getExpirationTime().before(Date.from(Instant.now()))) {
7467
refresh();
75-
token = safeGetAccessToken();
68+
token = retrieveAccessToken();
7669
}
7770
return new AccessToken(token.getTokenValue(), token.getExpirationTime().getTime());
7871
});
79-
} catch (Exception e) {
80-
throw ErrorUtils.getProgramFailureException(
81-
new ErrorCategory(ErrorCategoryEnum.PLUGIN),
82-
"Unable to get service account access token after retries.",
83-
e.getMessage(),
84-
ErrorType.UNKNOWN,
85-
true,
86-
e
72+
} catch (FailsafeException e) {
73+
Throwable t = e.getCause() != null ? e.getCause() : e;
74+
ErrorType errorType = (t instanceof ServerErrorException) ? ErrorType.SYSTEM : ErrorType.UNKNOWN;
75+
throw GCPErrorDetailsProviderUtil.getHttpResponseExceptionDetailsFromChain(
76+
e, "Unable to get service account access token after retries.", errorType, true,
77+
GCPUtils.GCE_METADATA_SERVER_ERROR_SUPPORTED_DOC_URL
8778
);
8879
}
8980
}
9081

91-
92-
private RetryPolicy<Object> getRetryPolicy(int initialRetryDuration, int maxRetryDuration,
93-
int maxRetryCount) {
82+
private static RetryPolicy<Object> createRetryPolicy() {
9483
return RetryPolicy.builder()
9584
.handle(ServerErrorException.class)
96-
.withBackoff(Duration.ofSeconds(initialRetryDuration), Duration.ofSeconds(maxRetryDuration))
97-
.withMaxRetries(maxRetryCount)
98-
.onRetry(event -> logger.debug("Retry attempt {} due to {}", event.getAttemptCount(), event.getLastException().
85+
.withBackoff(Duration.ofSeconds(DEFAULT_INITIAL_RETRY_DURATION_SECONDS),
86+
Duration.ofSeconds(DEFAULT_MAX_RETRY_DURATION_SECONDS))
87+
.withMaxRetries(DEFAULT_MAX_RETRY_COUNT)
88+
.onRetry(event -> LOG.debug("Retry attempt {} due to {}", event.getAttemptCount(), event.getLastException().
9989
getMessage()))
100-
.onSuccess(event -> logger.debug("Access Token Fetched Successfully."))
101-
.onRetriesExceeded(event -> logger.error("Retry limit reached for Service account."))
90+
.onSuccess(event -> LOG.debug("Access Token Fetched Successfully."))
91+
.onRetriesExceeded(
92+
event -> LOG.error("Unable to get service account access token after {} retries.", event.getAttemptCount() - 1))
10293
.build();
10394
}
10495

10596
private boolean isServerError(IOException e) {
10697
String msg = e.getMessage();
107-
return msg != null && msg.matches("^5\\d{2}$"); // crude check for 5xx codes
98+
return msg != null && SERVER_ERROR_PATTERN.matcher(msg).matches();
10899
}
109100

110-
private com.google.auth.oauth2.AccessToken safeGetAccessToken() throws IOException {
101+
private com.google.auth.oauth2.AccessToken retrieveAccessToken() throws IOException {
111102
try {
112103
return getCredentials().getAccessToken();
113104
} catch (IOException e) {
114105
if (isServerError(e)) {
115106
throw new ServerErrorException(HttpStatus.SC_SERVICE_UNAVAILABLE, "Server error while fetching access token: "
116-
+ e.getMessage());
107+
+ e.getMessage(), e);
117108
}
118109
throw e;
119110
}
@@ -126,11 +117,11 @@ public void refresh() throws IOException {
126117
} catch (IOException e) {
127118
if (isServerError(e)) {
128119
throw new ServerErrorException(HttpStatus.SC_SERVICE_UNAVAILABLE, "Server error during refresh: " +
129-
e.getMessage());
120+
e.getMessage(), e);
130121
}
131-
throw ErrorUtils.getProgramFailureException(new ErrorCategory(ErrorCategoryEnum.PLUGIN),
132-
"Unable to refresh service account access token.", e.getMessage(),
133-
ErrorType.UNKNOWN, true, e);
122+
throw GCPErrorDetailsProviderUtil.getHttpResponseExceptionDetailsFromChain(
123+
e, "Unable to refresh service account access token.", ErrorType.UNKNOWN, true,
124+
GCPUtils.GCE_METADATA_SERVER_ERROR_SUPPORTED_DOC_URL);
134125
}
135126
}
136127

0 commit comments

Comments
 (0)