Skip to content

Commit 39c243f

Browse files
authored
Ensure reauthentication attempts aren't blocked after unexpected error (#44)
Motivation A resiliency bug was encountered where the client fails to reauthenticate/recover following an abnormal response from the server to the authenticate RPC request. Modification Ensure the status stored/propagated from a failed authenticate RPC will always be interpreted as authentication-related, so that the existing logic will properly re-attempt authentication in all cases. Result Client properly recovers in rare server failure scenario
1 parent df32ad0 commit 39c243f

1 file changed

Lines changed: 19 additions & 5 deletions

File tree

src/main/java/com/ibm/etcd/client/EtcdClient.java

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -602,7 +602,7 @@ public boolean isClosed() {
602602
};
603603

604604
private Status lastAuthFailStatus;
605-
private long lastAuthFailTime;
605+
private long authFailRetryTime;
606606

607607
protected static boolean reauthRequired(Throwable error) {
608608
Status status = Status.fromThrowable(error);
@@ -616,8 +616,7 @@ protected static boolean reauthRequired(Throwable error) {
616616

617617
// This is only called in a synchronized context
618618
private CallCredentials refreshCredentials(Throwable trigger) {
619-
long lastAuthFailure = System.currentTimeMillis() - lastAuthFailTime;
620-
if (lastAuthFailure < 15_000L) {
619+
if (System.currentTimeMillis() < authFailRetryTime) {
621620
// Rate-limit how often re-auth attempts are made,
622621
// return last auth failure in the meantime
623622
return new CallCredentials() {
@@ -645,9 +644,24 @@ public void applyRequestMetadata(RequestInfo requestInfo,
645644
try {
646645
applier.apply(futureTokenHeader.get());
647646
} catch (ExecutionException | InterruptedException ee) { // (IE won't be thrown)
648-
Status failStatus = Status.fromThrowable(ee.getCause());
647+
Throwable failure = ee.getCause();
648+
Status failStatus;
649+
if (!reauthRequired(failure)) {
650+
// The authenticate RPC failed with an unexpected error (non auth-related)
651+
// Ensure our top-level status remains UNAUTHENTICATED or else higher
652+
// level logic will not recognize that another reauth attempt is required.
653+
failStatus = Status.UNAUTHENTICATED
654+
.withDescription("(Re)authentication RPC failed")
655+
.withCause(failure);
656+
authFailRetryTime = System.currentTimeMillis() + 5_000L;
657+
} else {
658+
failStatus = Status.fromThrowable(failure);
659+
// If this was a real auth failure, postpone further attempts a bit longer
660+
authFailRetryTime = System.currentTimeMillis() + 15_000L;
661+
}
649662
lastAuthFailStatus = failStatus;
650-
lastAuthFailTime = System.currentTimeMillis();
663+
// Augment with the RPC failure that triggered the re-authentication,
664+
// if applicable
651665
if (trigger != null) {
652666
if (failStatus.getCause() != null) {
653667
failStatus.getCause().addSuppressed(trigger);

0 commit comments

Comments
 (0)