-
Notifications
You must be signed in to change notification settings - Fork 119
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
fix: Retry when attempting to get the auth token #1301
Conversation
1ab7c33
to
42096ea
Compare
apiFetcher.getInstanceData( | ||
instanceName, downscopedCredentials, AuthType.IAM, executor, keyPair); | ||
} else { | ||
throw new RuntimeException( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We probably still need to throw an exception when no credentials have been provided.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that case is covered on line 104. There is no way to create a CloudSQLInstance with authType == IAM leaving this.iamAuthnCredentials with an empty value. Optional.of(null) will throw an exception.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes. In that case, let's update the exception message above to match what we have here (which is more useful, I think).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
* @param credentials the credentials to refresh | ||
* @throws IOException when the credentials.refresh() has failed 3 times | ||
*/ | ||
private void refreshWithRetry(OAuth2Credentials credentials) throws IOException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we be adding a test for this? Something like a CredentialRefresher maybe?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea. I'll add one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test added. I refactored the retry logic into its own implementation of Callable called RetryingCallable so that it could be tested.
Side note: does this issue fix all the Auto IAM AuthN flaky tests? |
Yes, this fixes all the flakey tests. |
throw new RuntimeException( | ||
String.format( | ||
"[%s] Unable to connect via automatic IAM authentication: " | ||
+ "Not supporting credentials of type %s", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be "Unsupported credentials of type ..."? "Not supporting" sounds odd.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed.
* | ||
* @param <T> the result type of the Callable. | ||
*/ | ||
public class RetryingCallable<T> implements Callable<T> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be public?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't need to be public. Fixed.
@Override | ||
public T call() throws Exception { | ||
|
||
for (int i = retryCount - 1; i >= 0; i--) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why the count down instead of the usual count up?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like that i
is the number of tries remaining. It makes line 73 easier to understand. I'm renanming i
to retriesLeft
throw e; | ||
} catch (Exception e) { | ||
throw new RuntimeException( | ||
"Unexpected exception while attempting to refresh oauth credentials", e); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/oauth/OAuth2/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed.
* @param sleepDuration the duration wait after a failed attempt. | ||
*/ | ||
public RetryingCallable(Callable<T> call, int retryCount, Duration sleepDuration) { | ||
if (retryCount <= 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shall we test all these error conditions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's put some tests around all this behavior. Should be simple to test.
public class RetryingCallableTest { | ||
@Test | ||
public void testNoRetryRequired() throws Exception { | ||
RetryingCallable<Integer> r = new RetryingCallable<>(() -> 1, 5, Duration.ofSeconds(1)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to wait a full second in test between retries?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed to 100ms.
public class RetryingCallable<T> implements Callable<T> { | ||
|
||
/** The callable that should be retried. */ | ||
private final Callable<T> call; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Let's just match the class name generally. So this would be callable
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed.
return new FailToConnectRequest(); | ||
} | ||
|
||
private class FailToConnectRequest extends LowLevelHttpRequest { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be static.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
@Override | ||
public LowLevelHttpResponse execute() throws IOException { | ||
try { | ||
Thread.sleep(10000); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we're just going to throw a Socket timeout exception, shall we just skip the sleep here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
This PR adds a retry for fetching the OAuth2 token which is used exclusively in Auto IAM AuthN. Why do you think it will fix the integration tests that aren't using Auto IAM AuthN? |
d7fbf95
to
0890b55
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. I'd like to see us add tests for the various error conditions in RetryingCallable's constructor before merging this.
Added tests for RetryingCallable constructor illegal arguments. |
Simplifies the logic when attempting to get the first token for a connection with IAM AuthN enabled. Also, adds logic
to retry the token request 3 times if it initially fails.
Fixes #1288
Fixes #1127