@aws-lambda-powertools/idempotency
Version:
The idempotency package for the Powertools for AWS Lambda (TypeScript) library. It provides options to make your Lambda functions idempotent and safe to retry.
85 lines (84 loc) • 2.84 kB
JavaScript
import { IdempotencyConfig } from './IdempotencyConfig.js';
import { IdempotencyHandler } from './IdempotencyHandler.js';
const isContext = (arg) => {
return (arg !== undefined &&
arg !== null &&
typeof arg === 'object' &&
'getRemainingTimeInMillis' in arg);
};
const isFnHandler = (fn, args) => {
// get arguments of function
return (fn !== undefined &&
fn !== null &&
typeof fn === 'function' &&
isContext(args[1]));
};
const isOptionsWithDataIndexArgument = (options) => {
return (options !== undefined &&
options !== null &&
typeof options === 'object' &&
'dataIndexArgument' in options);
};
/**
* Use function wrapper to make your function idempotent.
* @example
* ```ts
* // this is your processing function with an example record { transactionId: '123', foo: 'bar' }
* const processRecord = (record: Record<string, unknown>): any => {
* // you custom processing logic
* return result;
* };
*
* // we use wrapper to make processing function idempotent with DynamoDBPersistenceLayer
* const processIdempotently = makeIdempotent(processRecord, {
* persistenceStore: new DynamoDBPersistenceLayer()
* dataKeywordArgument: 'transactionId', // keyword argument to hash the payload and the result
* });
*
* export const handler = async (
* _event: EventRecords,
* _context: Context
* ): Promise<void> => {
* for (const record of _event.records) {
* const result = await processIdempotently(record);
* // do something with the result
* }
*
* return Promise.resolve();
* };
*
* @param fn - the function to make idempotent
* @param options - the options to configure the idempotency behavior
* ```
*/
function makeIdempotent(fn, options) {
const { persistenceStore, config, keyPrefix } = options;
const idempotencyConfig = config ? config : new IdempotencyConfig({});
if (!idempotencyConfig.isEnabled())
return fn;
return function (...args) {
let functionPayloadToBeHashed;
if (isFnHandler(fn, args)) {
idempotencyConfig.registerLambdaContext(args[1]);
functionPayloadToBeHashed = args[0];
}
else {
if (isOptionsWithDataIndexArgument(options)) {
functionPayloadToBeHashed = args[options.dataIndexArgument];
}
else {
functionPayloadToBeHashed = args[0];
}
}
return new IdempotencyHandler({
functionToMakeIdempotent: fn,
idempotencyConfig: idempotencyConfig,
persistenceStore: persistenceStore,
keyPrefix: keyPrefix,
functionArguments: args,
functionPayloadToBeHashed,
thisArg: this,
}).handle();
};
}
export { makeIdempotent };