@mcma/aws-dynamodb
Version:
Node module with code for using DynamoDB as the backing data storage for MCMA API handlers and workers.
86 lines (85 loc) • 3.31 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DynamoDbMutex = void 0;
const lib_dynamodb_1 = require("@aws-sdk/lib-dynamodb");
const data_1 = require("@mcma/data");
class DynamoDbMutex extends data_1.DocumentDatabaseMutex {
dc;
tableDescription;
_versionId;
constructor(dc, tableDescription, mutexName, mutexHolder, lockTimeout = 300000, logger) {
super(mutexName, mutexHolder, lockTimeout, logger);
this.dc = dc;
this.tableDescription = tableDescription;
this._versionId = (Math.random() * 2147483648 << 0).toString();
}
get versionId() {
return this._versionId;
}
generateTableKey() {
const Key = {};
if (this.tableDescription.keyNames.sort) {
Key[this.tableDescription.keyNames.partition] = "Mutex";
Key[this.tableDescription.keyNames.sort] = this.mutexName;
}
else {
Key[this.tableDescription.keyNames.partition] = "Mutex-" + this.mutexName;
}
return Key;
}
generateTableItem() {
const tableItem = {
mutexHolder: this.mutexHolder,
versionId: this.versionId,
timestamp: Date.now()
};
if (this.tableDescription.keyNames.sort) {
tableItem[this.tableDescription.keyNames.partition] = "Mutex";
tableItem[this.tableDescription.keyNames.sort] = this.mutexName;
}
else {
tableItem[this.tableDescription.keyNames.partition] = "Mutex-" + this.mutexName;
}
return tableItem;
}
async getLockData() {
const record = await this.dc.send(new lib_dynamodb_1.GetCommand({
TableName: this.tableDescription.tableName,
Key: this.generateTableKey(),
ConsistentRead: true
}));
// sanity check which removes the record from DynamoDB in case it has incompatible structure. Only possible
// if modified externally, but this could lead to a situation where the lock would never be acquired.
if (record.Item && (!record.Item.mutexHolder || !record.Item.versionId || !record.Item.timestamp)) {
await this.dc.send(new lib_dynamodb_1.DeleteCommand({
TableName: this.tableDescription.tableName,
Key: this.generateTableKey(),
}));
delete record.Item;
}
return record.Item;
}
async putLockData() {
const value = {
TableName: this.tableDescription.tableName,
Item: this.generateTableItem(),
Expected: {
resource_id: {
Exists: false
}
}
};
value.Expected[this.tableDescription.keyNames.partition] = { Exists: false };
await this.dc.send(new lib_dynamodb_1.PutCommand(value));
}
async deleteLockData(versionId) {
await this.dc.send(new lib_dynamodb_1.DeleteCommand({
TableName: this.tableDescription.tableName,
Key: this.generateTableKey(),
ConditionExpression: "#v = :v",
ExpressionAttributeNames: { "#v": "versionId" },
ExpressionAttributeValues: { ":v": versionId }
}));
}
}
exports.DynamoDbMutex = DynamoDbMutex;