Skip to content

Commit

Permalink
chore: reject promise if eager connection fails (#1177)
Browse files Browse the repository at this point in the history
* chore: reject promise if eager connection fails
  • Loading branch information
pratik151192 authored Mar 13, 2024
1 parent 3288e19 commit d25c68e
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 30 deletions.
31 changes: 16 additions & 15 deletions packages/client-sdk-nodejs/src/internal/cache-data-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ import _Unbounded = cache_client._Unbounded;
import ECacheResult = cache_client.ECacheResult;
import _ItemGetTypeResponse = cache_client._ItemGetTypeResponse;
import {grpcChannelOptionsFromGrpcConfig} from './grpc/grpc-channel-options';
import {ConnectionError} from '@gomomento/sdk-core/dist/src/errors';

export const CONNECTION_ID_KEY = Symbol('connectionID');

Expand Down Expand Up @@ -218,8 +219,9 @@ export class CacheDataClient implements IDataClient {
const now = new Date();

if (now >= deadline) {
this.logger.error('Unable to connect to Momento: deadline exceeded.');
resolve();
const errorMessage = 'Unable to connect to Momento: deadline exceeded.';
this.logger.error(errorMessage);
reject(new ConnectionError(errorMessage));
return;
}

Expand All @@ -228,14 +230,13 @@ export class CacheDataClient implements IDataClient {
.getChannel()
.watchConnectivityState(currentState, deadline, (error?: Error) => {
if (error) {
this.logger.error(
`Unable to eagerly connect to Momento. Please contact Momento if this persists. currentState: ${currentState}, errorName: ${
error.name
} : errorMessage: ${error.message}, errorStack: ${
error.stack ? error.stack : 'Stack trace undefined'
}`
);
resolve();
const errorMessage = `Unable to eagerly connect to Momento. Please contact Momento if this persists. currentState: ${currentState}, errorName: ${
error.name
} : errorMessage: ${error.message}, errorStack: ${
error.stack ? error.stack : 'Stack trace undefined'
}`;
this.logger.error(errorMessage);
reject(new ConnectionError(errorMessage));
return;
}

Expand All @@ -253,11 +254,11 @@ export class CacheDataClient implements IDataClient {
this.logger.debug(`Connecting! Current state: ${newState}`);
this.connectWithinDeadline(deadline).then(resolve).catch(reject);
} else {
this.logger.error(
`Unable to connect to Momento: Unexpected connection state: ${newState}., oldState: ${currentState}
Please contact Momento if this persists.`
);
resolve();
const errorMessage = `Unable to connect to Momento: Unexpected connection state: ${newState}., oldState: ${currentState}
Please contact Momento if this persists.`;
this.logger.error(errorMessage);
reject(new ConnectionError(errorMessage));
return;
}
});
});
Expand Down
39 changes: 24 additions & 15 deletions packages/client-sdk-nodejs/test/unit/cache-client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import {
SimpleCacheClient,
CreateCache,
StringMomentoTokenProvider,
CredentialProvider,
MomentoErrorCode,
} from '../../src';
import {SimpleCacheClientProps} from '../../src/cache-client-props';
import {CacheSet, ServerUnavailableError} from '@gomomento/sdk-core';
import {ConnectionError} from '@gomomento/sdk-core';

// This auth token is syntactically correct but not actually valid; it won't work with the real Momento Servers.
// Used only for unit testing the constructors etc.
Expand All @@ -32,7 +34,9 @@ describe('CacheClient', () => {
const invalidCacheNames = ['', ' '];
const momento = await CacheClient.create({
configuration: configuration,
credentialProvider: credentialProvider,
credentialProvider: CredentialProvider.fromEnvironmentVariable({
environmentVariableName: 'TEST_AUTH_TOKEN',
}),
defaultTtlSeconds: 100,
});
for (const name of invalidCacheNames) {
Expand Down Expand Up @@ -62,19 +66,24 @@ describe('CacheClient', () => {
}
}
});
it('createWithEagerConnection returns a client even if it cannot connect', async () => {
const momento = await CacheClient.create({
configuration: configuration,
credentialProvider: credentialProvider,
defaultTtlSeconds: 100,
eagerConnectTimeout: 1000,
});
const setResponse = await momento.set('cache', 'key', 'value');
expect(setResponse).toBeInstanceOf(CacheSet.Error);
if (setResponse instanceof CacheSet.Error) {
expect(setResponse.innerException()).toBeInstanceOf(
ServerUnavailableError
);
it('createWithEagerConnection throws if it cannot connect', async () => {
try {
await CacheClient.create({
configuration: configuration,
credentialProvider: credentialProvider,
defaultTtlSeconds: 100,
});
// If the function call above does not throw, explicitly fail the test.
expect('Expected error was not thrown').toBeUndefined();
} catch (e) {
if (e instanceof ConnectionError) {
// Now TypeScript knows 'e' is an Error, so 'message' is accessible.
expect(e._errorCode).toEqual(MomentoErrorCode.CONNECTION_ERROR);
expect(e.message).toContain('Unable to connect to Momento');
} else {
// Handle the case where 'e' is not an Error object.
expect('Error is not an instance of Error').toBeUndefined();
}
}
});
it('cannot create a client with an invalid default TTL', async () => {
Expand Down
9 changes: 9 additions & 0 deletions packages/core/src/errors/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ export enum MomentoErrorCode {
AUTHENTICATION_ERROR = 'AUTHENTICATION_ERROR',
// Request was cancelled by the server
CANCELLED_ERROR = 'CANCELLED_ERROR',
// Error connecting to Momento servers
CONNECTION_ERROR = 'CONNECTION_ERROR',
// Request rate, bandwidth, or object size exceeded the limits for the account
LIMIT_EXCEEDED_ERROR = 'LIMIT_EXCEEDED_ERROR',
// Request was invalid
Expand Down Expand Up @@ -118,6 +120,13 @@ export class CancelledError extends SdkError {
'The request was cancelled by the server; please contact us at [email protected]';
}

/**
* Error when there's a failure to connect to Momento servers.
*/
export class ConnectionError extends SdkError {
_errorCode = MomentoErrorCode.CONNECTION_ERROR;
}

/**
* Error raised when system in not in a state required for the operation's success
*/
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ import {
AlreadyExistsError,
AuthenticationError,
CancelledError,
ConnectionError,
FailedPreconditionError,
LimitExceededError,
InternalServerError,
Expand Down Expand Up @@ -295,6 +296,7 @@ export {
AlreadyExistsError,
AuthenticationError,
CancelledError,
ConnectionError,
FailedPreconditionError,
LimitExceededError,
InternalServerError,
Expand Down

0 comments on commit d25c68e

Please sign in to comment.