Skip to content

Commit

Permalink
chore: make eager connection failure hard failure (#355)
Browse files Browse the repository at this point in the history
* chore: make eager connection failure hard failure

* chore: fix lint errors
  • Loading branch information
pratik151192 authored Mar 19, 2024
1 parent 630ab32 commit 660519a
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 18 deletions.
39 changes: 22 additions & 17 deletions momento-sdk/src/main/java/momento/sdk/ScsDataGrpcStubsManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import io.grpc.ManagedChannel;
import io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
Expand All @@ -23,6 +24,7 @@
import javax.annotation.Nonnull;
import momento.sdk.auth.CredentialProvider;
import momento.sdk.config.Configuration;
import momento.sdk.exceptions.ConnectionFailedException;
import momento.sdk.internal.GrpcChannelOptions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -110,32 +112,38 @@ public void connect(final long timeoutSeconds) {
final ConnectivityState currentState = channel.getState(true /* tryToConnect */);
if (ConnectivityState.READY.equals(currentState)) {
LOGGER.debug("Connected to Momento's server! Happy Caching!");
return;
continue;
}

// this future is our signalling mechanism to exit after the eager connection is successfully
// established or fails
final CompletableFuture<Void> connectionFuture = new CompletableFuture<>();
eagerlyConnect(currentState, connectionFuture, channel);
eagerlyConnect(
currentState, connectionFuture, channel, Instant.now().plusSeconds(timeoutSeconds));

try {
connectionFuture.get(timeoutSeconds, TimeUnit.SECONDS);
} catch (TimeoutException e) {
connectionFuture.cancel(true);
LOGGER.debug("Failed to connect within the allotted time of {} seconds.", 1);
throw new ConnectionFailedException(
"Failed to connect within the allotted time of " + timeoutSeconds + " seconds.", e);
} catch (InterruptedException | ExecutionException e) {
connectionFuture.cancel(true);
LOGGER.debug("Error while waiting for eager connection to establish.", e);
throw new ConnectionFailedException(
"Error while waiting for eager connection to establish.", e);
}
}
}

private static void eagerlyConnect(
final ConnectivityState lastObservedState,
final CompletableFuture<Void> connectionFuture,
final ManagedChannel channel) {
final ManagedChannel channel,
final Instant timeout) {

// the callback is triggerd only when a state change happens
if (Instant.now().toEpochMilli() > timeout.toEpochMilli()) {
connectionFuture.completeExceptionally(
new ConnectionFailedException("Connection failed: Deadline exceeded"));
return;
}
channel.notifyWhenStateChanged(
lastObservedState,
() -> {
Expand All @@ -144,25 +152,22 @@ private static void eagerlyConnect(
case READY:
LOGGER.debug("Connected to Momento's server! Happy Caching!");
connectionFuture.complete(null);
break;
return;
case IDLE:
LOGGER.debug("State is idle; waiting to transition to CONNECTING");
// we will recursively call this atmost twice (IDLE -> CONNECTING and CONNECTING ->
// READY) in a happy case.
// we deliberately give up connecting eagerly if it fails or has intermittent issues
// to not
// blow up the call stack on frequent state changes.
eagerlyConnect(currentState, connectionFuture, channel);
eagerlyConnect(currentState, connectionFuture, channel, timeout);
break;
case CONNECTING:
LOGGER.debug("State transitioned to CONNECTING; waiting to get READY");
eagerlyConnect(currentState, connectionFuture, channel);
eagerlyConnect(currentState, connectionFuture, channel, timeout);
break;
default:
LOGGER.debug(
"Unexpected state encountered {}. Contact Momento if this persists.",
currentState.name());
connectionFuture.complete(null);
connectionFuture.completeExceptionally(
new ConnectionFailedException(
"Connection failed due to unexpected state: " + currentState));
break;
}
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package momento.sdk.exceptions;

public class ConnectionFailedException extends MomentoServiceException {

/**
* Constructs a ConnectionFailedException with a message.
*
* @param message the message/cause for exception.
*/
public ConnectionFailedException(final String message) {
super(MomentoErrorCode.CONNECTION, message);
}

/**
* Constructs a ConnectionFailedException with a message and error details.
*
* @param message the message/cause for exception.
* @param cause the error details.
*/
public ConnectionFailedException(final String message, final Throwable cause) {
super(MomentoErrorCode.CONNECTION, message, cause);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
* errors on a failure response.
*/
public enum MomentoErrorCode {
/** The client was unable to connect to the server. */
CONNECTION,

/** An invalid argument was passed to Momento client. */
INVALID_ARGUMENT_ERROR,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,17 @@ public MomentoServiceException(MomentoErrorCode errorCode, String message) {
super(errorCode, message);
}

/**
* Constructs a MomentoServiceException with an error code, a detail message, and error details.
*
* @param errorCode the error code, or {@link MomentoErrorCode#UNKNOWN} if none exists.
* @param message the detail message.
* @param cause the exception cause/details
*/
public MomentoServiceException(MomentoErrorCode errorCode, String message, Throwable cause) {
super(errorCode, message, cause);
}

/**
* Constructs a MomentoServiceException with an error code, a detail message, and error details.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public class UnknownException extends MomentoServiceException {
* @param message the detail message.
*/
public UnknownException(String message) {
super(MomentoErrorCode.UNKNOWN, message, null);
super(MomentoErrorCode.UNKNOWN, message);
}

/**
Expand Down

0 comments on commit 660519a

Please sign in to comment.