import { DynamoDB } from 'aws-sdk'; export type DynamoDbLockConfig = { dynamodb: DynamoDB.DocumentClient; lockTable: string; }; export enum LockStatus { OK, EXISTED, ERROR, } export type LockResult = { status: LockStatus; id: string; key: string; message?: string; retriable?: boolean; }; export class DynamoDbLockClient { config: DynamoDbLockConfig; constructor(config: DynamoDbLockConfig) { this.config = config; } acquireLock = async (id: string): Promise => { const { dynamodb, lockTable } = this.config; const key = `L#${id}`; return dynamodb .put({ TableName: lockTable, Item: { PK: key, SK: key, EntityType: 'Lock', }, ConditionExpression: 'attribute_not_exists(PK)', }) .promise() .then(() => ({ id: id, key: key, status: LockStatus.OK, })) .catch(e => { return e.code === 'ConditionalCheckFailedException' ? { id: id, key: key, status: LockStatus.EXISTED, message: 'lock existed', } : { id: id, key: key, status: LockStatus.ERROR, retryable: e.retryable, message: e.message, }; }); }; acquireLocks = async (keys: string[]) => { const locks = await Promise.all(keys.map(key => this.acquireLock(key))); return locks.filter(key => !!key); }; }