diff --git a/packages/client-sdk-nodejs/src/config/retry/default-eligibility-strategy.ts b/packages/client-sdk-nodejs/src/config/retry/default-eligibility-strategy.ts index 34f8117b5..3dae36b41 100644 --- a/packages/client-sdk-nodejs/src/config/retry/default-eligibility-strategy.ts +++ b/packages/client-sdk-nodejs/src/config/retry/default-eligibility-strategy.ts @@ -10,7 +10,9 @@ const retryableGrpcStatusCodes: Array = [ // commenting out the ones we don't want to retry on for now. // Status.OK, - // Status.CANCELLED, + // Idempotent operations can be safely retried for CANCELLED errors. These may pop us sometimes during + // client or server side deployments + Status.CANCELLED, // Status.UNKNOWN, // Status.INVALID_ARGUMENT, // Status.DEADLINE_EXCEEDED, diff --git a/packages/client-sdk-nodejs/test/unit/config/retry/default-eligibility-strategy.test.ts b/packages/client-sdk-nodejs/test/unit/config/retry/default-eligibility-strategy.test.ts new file mode 100644 index 000000000..0a862689c --- /dev/null +++ b/packages/client-sdk-nodejs/test/unit/config/retry/default-eligibility-strategy.test.ts @@ -0,0 +1,108 @@ +import { + DefaultEligibilityStrategy, + DefaultMomentoLoggerFactory, +} from '../../../../src'; +import {Status} from '@grpc/grpc-js/build/src/constants'; +import {Metadata, StatusObject} from '@grpc/grpc-js'; +import {ClientMethodDefinition} from '@grpc/grpc-js/build/src/make-client'; + +describe('DefaultEligibilityStrategy', () => { + const testLoggerFactory = new DefaultMomentoLoggerFactory(); + const eligibilityStrategy = new DefaultEligibilityStrategy(testLoggerFactory); + + it('should return true for INTERNAL status code and GET request path', () => { + const grpcStatus = {code: Status.INTERNAL} as StatusObject; + const grpcRequest = { + path: '/cache_client.Scs/Get', + } as ClientMethodDefinition; + const requestMetadata = new Metadata(); + + const isEligible = eligibilityStrategy.isEligibleForRetry({ + grpcStatus, + grpcRequest, + requestMetadata, + }); + + expect(isEligible).toBe(true); + }); + + it('should return false for UNKNOWN status code and GET request path', () => { + const grpcStatus = {code: Status.UNKNOWN} as StatusObject; + const grpcRequest = { + path: '/cache_client.Scs/Get', + } as ClientMethodDefinition; + const requestMetadata = new Metadata(); + + const isEligible = eligibilityStrategy.isEligibleForRetry({ + grpcStatus, + grpcRequest, + requestMetadata, + }); + + expect(isEligible).toBe(false); + }); + + it('should return true for UNAVAILABLE status code and SET request path', () => { + const grpcStatus = {code: Status.UNAVAILABLE} as StatusObject; + const grpcRequest = { + path: '/cache_client.Scs/Set', + } as ClientMethodDefinition; + const requestMetadata = new Metadata(); + + const isEligible = eligibilityStrategy.isEligibleForRetry({ + grpcStatus, + grpcRequest, + requestMetadata, + }); + + expect(isEligible).toBe(true); + }); + + it('should return true for CANCELLED status code and GET request path', () => { + const grpcStatus = {code: Status.CANCELLED} as StatusObject; + const grpcRequest = { + path: '/cache_client.Scs/Get', + } as ClientMethodDefinition; + const requestMetadata = new Metadata(); + + const isEligible = eligibilityStrategy.isEligibleForRetry({ + grpcStatus, + grpcRequest, + requestMetadata, + }); + + expect(isEligible).toBe(true); + }); + + it('should return true for CANCELLED status code and SET request path', () => { + const grpcStatus = {code: Status.CANCELLED} as StatusObject; + const grpcRequest = { + path: '/cache_client.Scs/Set', + } as ClientMethodDefinition; + const requestMetadata = new Metadata(); + + const isEligible = eligibilityStrategy.isEligibleForRetry({ + grpcStatus, + grpcRequest, + requestMetadata, + }); + + expect(isEligible).toBe(true); + }); + + it('should return false for CANCELLED status code and dictionary increment request path', () => { + const grpcStatus = {code: Status.CANCELLED} as StatusObject; + const grpcRequest = { + path: '/cache_client.Scs/DictionaryIncrement', + } as ClientMethodDefinition; + const requestMetadata = new Metadata(); + + const isEligible = eligibilityStrategy.isEligibleForRetry({ + grpcStatus, + grpcRequest, + requestMetadata, + }); + + expect(isEligible).toBe(false); + }); +});