diff --git a/packages/idempotency/src/IdempotencyHandler.ts b/packages/idempotency/src/IdempotencyHandler.ts index c5d5e4ee6b..96505222b7 100644 --- a/packages/idempotency/src/IdempotencyHandler.ts +++ b/packages/idempotency/src/IdempotencyHandler.ts @@ -383,20 +383,20 @@ export class IdempotencyHandler { if (error.name === 'IdempotencyItemAlreadyExistsError') { let idempotencyRecord = (error as IdempotencyItemAlreadyExistsError) .existingRecord; - if (idempotencyRecord !== undefined) { - // If the error includes the existing record, we can use it to validate - // the record being processed and cache it in memory. - idempotencyRecord = this.#persistenceStore.processExistingRecord( - idempotencyRecord, - this.#functionPayloadToBeHashed - ); + if (idempotencyRecord === undefined) { // If the error doesn't include the existing record, we need to fetch // it from the persistence layer. In doing so, we also call the processExistingRecord // method to validate the record and cache it in memory. - } else { idempotencyRecord = await this.#persistenceStore.getRecord( this.#functionPayloadToBeHashed ); + } else { + // If the error includes the existing record, we can use it to validate + // the record being processed and cache it in memory. + idempotencyRecord = this.#persistenceStore.processExistingRecord( + idempotencyRecord, + this.#functionPayloadToBeHashed + ); } returnValue.isIdempotent = true; diff --git a/packages/idempotency/src/idempotencyDecorator.ts b/packages/idempotency/src/idempotencyDecorator.ts index 968b3bd10e..ba9e63effa 100644 --- a/packages/idempotency/src/idempotencyDecorator.ts +++ b/packages/idempotency/src/idempotencyDecorator.ts @@ -70,7 +70,7 @@ const idempotent = ( ) { const childFunction = descriptor.value; - descriptor.value = async function (this: Handler, ...args: unknown[]) { + descriptor.value = function (this: Handler, ...args: unknown[]) { return makeIdempotent(childFunction, options).bind(this)(...args); }; diff --git a/packages/idempotency/src/middleware/makeHandlerIdempotent.ts b/packages/idempotency/src/middleware/makeHandlerIdempotent.ts index d48dcc221d..0d75c65ab0 100644 --- a/packages/idempotency/src/middleware/makeHandlerIdempotent.ts +++ b/packages/idempotency/src/middleware/makeHandlerIdempotent.ts @@ -112,7 +112,7 @@ const makeHandlerIdempotent = ( * * @param request - The Middy request object */ - const before = async (request: MiddyLikeRequest): Promise => { + const before = (request: MiddyLikeRequest): unknown => { const idempotencyConfig = options.config ? options.config : new IdempotencyConfig({}); diff --git a/packages/idempotency/src/persistence/DynamoDBPersistenceLayer.ts b/packages/idempotency/src/persistence/DynamoDBPersistenceLayer.ts index 4e88f99b51..6dfbeb63f5 100644 --- a/packages/idempotency/src/persistence/DynamoDBPersistenceLayer.ts +++ b/packages/idempotency/src/persistence/DynamoDBPersistenceLayer.ts @@ -88,13 +88,13 @@ class DynamoDBPersistenceLayer extends BasePersistenceLayer { config.staticPkValue ?? `idempotency#${this.idempotencyKeyPrefix}`; if (config.awsSdkV3Client) { - if (!isSdkClient(config.awsSdkV3Client)) { + if (isSdkClient(config.awsSdkV3Client)) { + this.client = config.awsSdkV3Client; + } else { console.warn( 'awsSdkV3Client is not an AWS SDK v3 client, using default client' ); this.client = new DynamoDBClient(config.clientConfig ?? {}); - } else { - this.client = config.awsSdkV3Client; } } else { this.client = new DynamoDBClient(config.clientConfig ?? {}); @@ -168,9 +168,9 @@ class DynamoDBPersistenceLayer extends BasePersistenceLayer { * | (in_progress_expiry) (expiry) * * Conditions to successfully save a record: - * * The idempotency key does not exist: - * - first time that this invocation key is used - * - previous invocation with the same key was deleted due to TTL + * - The idempotency key does not exist: + * - first time that this invocation key is used + * - previous invocation with the same key was deleted due to TTL */ const idempotencyKeyDoesNotExist = 'attribute_not_exists(#id)'; // * The idempotency key exists but it is expired diff --git a/packages/idempotency/tests/e2e/idempotentDecorator.test.FunctionCode.ts b/packages/idempotency/tests/e2e/idempotentDecorator.test.FunctionCode.ts index 9063d652cd..e4bb5205e9 100644 --- a/packages/idempotency/tests/e2e/idempotentDecorator.test.FunctionCode.ts +++ b/packages/idempotency/tests/e2e/idempotentDecorator.test.FunctionCode.ts @@ -2,7 +2,7 @@ import type { LambdaInterface } from '@aws-lambda-powertools/commons/types'; import { Logger } from '@aws-lambda-powertools/logger'; import type { Context } from 'aws-lambda'; import { IdempotencyConfig } from '../../src/IdempotencyConfig.js'; -import { idempotent } from '../../src/idempotencyDecorator'; +import { idempotent } from '../../src/idempotencyDecorator.js'; import { DynamoDBPersistenceLayer } from '../../src/persistence/DynamoDBPersistenceLayer.js'; const IDEMPOTENCY_TABLE_NAME = @@ -35,19 +35,13 @@ class DefaultLambda implements LambdaInterface { logger.info(`${this.message} ${JSON.stringify(_event)}`); // sleep to enforce error with parallel execution await new Promise((resolve) => setTimeout(resolve, 1000)); - - // We return void to test that the utility handles it correctly - return; } @idempotent({ persistenceStore: dynamoDBPersistenceLayerCustomized, config: config, }) - public async handlerCustomized( - event: { foo: string }, - context: Context - ): Promise { + public handlerCustomized(event: { foo: string }, context: Context) { config.registerLambdaContext(context); logger.info('Processed event', { details: event.foo }); @@ -62,10 +56,10 @@ class DefaultLambda implements LambdaInterface { eventKeyJmesPath: 'foo', }), }) - public async handlerExpired( + public handlerExpired( event: { foo: string; invocation: number }, context: Context - ): Promise<{ foo: string; invocation: number }> { + ) { logger.addContext(context); logger.info('Processed event', { details: event.foo }); @@ -77,10 +71,7 @@ class DefaultLambda implements LambdaInterface { } @idempotent({ persistenceStore: dynamoDBPersistenceLayer }) - public async handlerParallel( - event: { foo: string }, - context: Context - ): Promise { + public async handlerParallel(event: { foo: string }, context: Context) { logger.addContext(context); await new Promise((resolve) => setTimeout(resolve, 1500)); @@ -99,7 +90,7 @@ class DefaultLambda implements LambdaInterface { public async handlerTimeout( event: { foo: string; invocation: number }, context: Context - ): Promise<{ foo: string; invocation: number }> { + ) { logger.addContext(context); if (event.invocation === 0) { @@ -130,12 +121,9 @@ const handlerExpired = defaultLambda.handlerExpired.bind(defaultLambda); const logger = new Logger(); class LambdaWithKeywordArgument implements LambdaInterface { - public async handler( - event: { id: string }, - _context: Context - ): Promise { + public handler(event: { id: string }, _context: Context) { config.registerLambdaContext(_context); - await this.process(event.id, 'bar'); + this.process(event.id, 'bar'); return 'Hello World Keyword Argument'; } @@ -145,7 +133,7 @@ class LambdaWithKeywordArgument implements LambdaInterface { config: config, dataIndexArgument: 1, }) - public async process(id: string, foo: string): Promise { + public process(id: string, foo: string) { logger.info('Got test event', { id, foo }); return `idempotent result: ${foo}`; diff --git a/packages/idempotency/tests/e2e/makeHandlerIdempotent.test.FunctionCode.ts b/packages/idempotency/tests/e2e/makeHandlerIdempotent.test.FunctionCode.ts index 6ade59d2ef..62f132e8bb 100644 --- a/packages/idempotency/tests/e2e/makeHandlerIdempotent.test.FunctionCode.ts +++ b/packages/idempotency/tests/e2e/makeHandlerIdempotent.test.FunctionCode.ts @@ -16,14 +16,12 @@ const logger = new Logger(); /** * Test handler with sequential execution. */ -export const handler = middy( - async (event: { foo: string }, context: Context) => { - logger.addContext(context); - logger.info('foo', { details: event.foo }); +export const handler = middy((event: { foo: string }, context: Context) => { + logger.addContext(context); + logger.info('foo', { details: event.foo }); - return event.foo; - } -).use( + return event.foo; +}).use( makeHandlerIdempotent({ persistenceStore: dynamoDBPersistenceLayer, }) @@ -97,7 +95,7 @@ export const handlerTimeout = middy( * was processed by looking at the value in the stored idempotency record. */ export const handlerExpired = middy( - async (event: { foo: string; invocation: number }, context: Context) => { + (event: { foo: string; invocation: number }, context: Context) => { logger.addContext(context); logger.info('Processed event', { details: event.foo }); diff --git a/packages/idempotency/tests/e2e/makeHandlerIdempotent.test.ts b/packages/idempotency/tests/e2e/makeHandlerIdempotent.test.ts index 0c379b5f4e..21e53fde0e 100644 --- a/packages/idempotency/tests/e2e/makeHandlerIdempotent.test.ts +++ b/packages/idempotency/tests/e2e/makeHandlerIdempotent.test.ts @@ -192,15 +192,13 @@ describe('Idempotency E2E tests, middy middleware usage', () => { * We filter the logs to find which one was successful and which one failed, then we check * that they contain the expected logs. */ - const successfulInvocationLogs = functionLogs.find( - (functionLog) => - functionLog.find((log) => log.includes('Processed event')) !== undefined + const successfulInvocationLogs = functionLogs.find((functionLog) => + functionLog.some((log) => log.includes('Processed event')) ); - const failedInvocationLogs = functionLogs.find( - (functionLog) => - functionLog.find((log) => - log.includes('There is already an execution in progress') - ) !== undefined + const failedInvocationLogs = functionLogs.find((functionLog) => + functionLog.some((log) => + log.includes('There is already an execution in progress') + ) ); expect(successfulInvocationLogs).toHaveLength(1); expect(failedInvocationLogs).toHaveLength(1); diff --git a/packages/idempotency/tests/e2e/makeIdempotent.test.FunctionCode.ts b/packages/idempotency/tests/e2e/makeIdempotent.test.FunctionCode.ts index 10e2ce5f73..b35b4444dc 100644 --- a/packages/idempotency/tests/e2e/makeIdempotent.test.FunctionCode.ts +++ b/packages/idempotency/tests/e2e/makeIdempotent.test.FunctionCode.ts @@ -90,7 +90,7 @@ export const handlerCustomized = async ( * Test idempotent Lambda handler with JMESPath expression to extract event key. */ export const handlerLambda = makeIdempotent( - async (event: { body: string }, context: Context) => { + (event: { body: string }, context: Context) => { logger.addContext(context); const body = JSON.parse(event.body); logger.info('foo', { details: body.foo }); diff --git a/packages/idempotency/tests/unit/IdempotencyConfig.test.ts b/packages/idempotency/tests/unit/IdempotencyConfig.test.ts index 8174c7727d..4aec6d0927 100644 --- a/packages/idempotency/tests/unit/IdempotencyConfig.test.ts +++ b/packages/idempotency/tests/unit/IdempotencyConfig.test.ts @@ -87,7 +87,7 @@ describe('Class: IdempotencyConfig', () => { }); describe('Method: registerLambdaContext', () => { - it('stores the provided context', async () => { + it('stores the provided context', () => { // Prepare const config = new IdempotencyConfig({}); diff --git a/packages/idempotency/tests/unit/IdempotencyHandler.test.ts b/packages/idempotency/tests/unit/IdempotencyHandler.test.ts index ebcdbddf59..2481314dc1 100644 --- a/packages/idempotency/tests/unit/IdempotencyHandler.test.ts +++ b/packages/idempotency/tests/unit/IdempotencyHandler.test.ts @@ -68,7 +68,7 @@ describe('Class IdempotencyHandler', () => { }, ])( 'throws when the record is in progress and within expiry window ($case)', - async ({ keys, expectedErrorMsg }) => { + ({ keys, expectedErrorMsg }) => { // Prepare const stubRecord = new IdempotencyRecord({ ...keys, @@ -89,7 +89,7 @@ describe('Class IdempotencyHandler', () => { } ); - it('throws when the record is in progress and outside expiry window', async () => { + it('throws when the record is in progress and outside expiry window', () => { // Prepare const stubRecord = new IdempotencyRecord({ idempotencyKey: 'idempotencyKey', @@ -109,7 +109,7 @@ describe('Class IdempotencyHandler', () => { expect(mockResponseHook).not.toHaveBeenCalled(); }); - it('throws when the idempotency record is expired', async () => { + it('throws when the idempotency record is expired', () => { // Prepare const stubRecord = new IdempotencyRecord({ idempotencyKey: 'idempotencyKey', diff --git a/packages/idempotency/tests/unit/deepSort.test.ts b/packages/idempotency/tests/unit/deepSort.test.ts index e37c6c6d91..057643ab52 100644 --- a/packages/idempotency/tests/unit/deepSort.test.ts +++ b/packages/idempotency/tests/unit/deepSort.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest'; -import { deepSort } from '../../src/deepSort'; +import { deepSort } from '../../src/deepSort.js'; describe('Function: deepSort', () => { it('can sort string correctly', () => { diff --git a/packages/idempotency/tests/unit/idempotencyDecorator.test.ts b/packages/idempotency/tests/unit/idempotencyDecorator.test.ts index b153c01418..c37ff829f4 100644 --- a/packages/idempotency/tests/unit/idempotencyDecorator.test.ts +++ b/packages/idempotency/tests/unit/idempotencyDecorator.test.ts @@ -15,10 +15,7 @@ describe('Given a class with a function to decorate', () => { @idempotent({ persistenceStore: new PersistenceLayerTestClass(), }) - public async handler( - _event: unknown, - _context: Context - ): Promise { + public handler(_event: unknown, _context: Context) { return this.privateMethod(); } @@ -48,10 +45,7 @@ describe('Given a class with a function to decorate', () => { config: idempotencyConfig, keyPrefix: 'my-custom-prefix', }) - public async handler( - _event: unknown, - _context: Context - ): Promise { + public handler(_event: unknown, _context: Context) { return true; } } diff --git a/packages/idempotency/tests/unit/makeIdempotent.test.ts b/packages/idempotency/tests/unit/makeIdempotent.test.ts index bc567d452f..1c8a15e99b 100644 --- a/packages/idempotency/tests/unit/makeIdempotent.test.ts +++ b/packages/idempotency/tests/unit/makeIdempotent.test.ts @@ -20,7 +20,7 @@ const mockIdempotencyOptions = { }; const remainingTImeInMillis = 1234; const fnSuccessfull = async () => true; -const fnError = async () => { +const fnError = () => { throw new Error('Something went wrong'); }; @@ -525,7 +525,7 @@ describe('Function: makeIdempotent', () => { it('throws immediately if an object other than an error was thrown (wrapper)', async () => { // Prepare - const fn = async (_event: unknown, _context: Context) => { + const fn = (_event: unknown, _context: Context) => { throw 'a string'; }; const handler = makeIdempotent(fn, mockIdempotencyOptions); diff --git a/packages/idempotency/tests/unit/persistence/DynamoDbPersistenceLayer.test.ts b/packages/idempotency/tests/unit/persistence/DynamoDbPersistenceLayer.test.ts index f786774cbb..35121122e3 100644 --- a/packages/idempotency/tests/unit/persistence/DynamoDbPersistenceLayer.test.ts +++ b/packages/idempotency/tests/unit/persistence/DynamoDbPersistenceLayer.test.ts @@ -149,7 +149,7 @@ describe('Class: DynamoDBPersistenceLayer', () => { ); }); - it('falls back on a new SDK client and logs a warning when an unknown object is provided instead of a client', async () => { + it('falls back on a new SDK client and logs a warning when an unknown object is provided instead of a client', () => { // Act const persistenceLayer = new DynamoDBPersistenceLayerTestClass({ tableName: dummyTableName, @@ -424,7 +424,7 @@ describe('Class: DynamoDBPersistenceLayer', () => { expiryTimestamp: 0, inProgressExpiryTimestamp: 0, }); - client.on(PutItemCommand).rejects(new Error()); + client.on(PutItemCommand).rejects(new Error('some error')); // Act & Assess await expect(persistenceLayer._putRecord(record)).rejects.toThrow(); @@ -576,7 +576,7 @@ describe('Class: DynamoDBPersistenceLayer', () => { }); }); - it('updates the item when the response_data is undefined', async () => { + it('updates the item when the response_data is undefined', () => { // Prepare const status = IdempotencyRecordStatus.EXPIRED; const expiryTimestamp = Date.now(); diff --git a/packages/idempotency/vitest.config.ts b/packages/idempotency/vitest.config.ts index baa5cf7463..e962bb6d1c 100644 --- a/packages/idempotency/vitest.config.ts +++ b/packages/idempotency/vitest.config.ts @@ -4,7 +4,7 @@ export default defineProject({ test: { environment: 'node', setupFiles: ['../testing/src/setupEnv.ts'], - hookTimeout: 1_000 * 60 * 10, // 10 minutes - testTimeout: 1_000 * 60 * 3, // 3 minutes + hookTimeout: 1000 * 60 * 10, // 10 minutes + testTimeout: 1000 * 60 * 3, // 3 minutes }, });