@ftschopp/dynatable-migrations 1.2.2 → 1.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DynamoDBMigrationTracker = void 0;
3
+ exports.DynamoDBMigrationTracker = exports.DEFAULT_LOCK_TTL_SECONDS = void 0;
4
4
  const lib_dynamodb_1 = require("@aws-sdk/lib-dynamodb");
5
- const LOCK_TTL_SECONDS = 300; // 5 minutes
5
+ const semver_1 = require("./semver");
6
+ /** Default lock TTL in seconds. Configurable via MigrationConfig.lockTtlSeconds. */
7
+ exports.DEFAULT_LOCK_TTL_SECONDS = 300; // 5 minutes
6
8
  class DynamoDBMigrationTracker {
7
9
  constructor(client, config) {
8
10
  this.lockId = null;
@@ -10,6 +12,34 @@ class DynamoDBMigrationTracker {
10
12
  this.tableName = config.tableName;
11
13
  this.trackingPrefix = config.trackingPrefix || '_SCHEMA#VERSION';
12
14
  this.gsi1Name = config.gsi1Name || 'GSI1';
15
+ this.lockTtlSeconds = config.lockTtlSeconds ?? exports.DEFAULT_LOCK_TTL_SECONDS;
16
+ }
17
+ get lockKey() {
18
+ return {
19
+ PK: `${this.trackingPrefix}#LOCK`,
20
+ SK: `${this.trackingPrefix}#LOCK`,
21
+ };
22
+ }
23
+ /** Throws if there is no active lock. Call before any tracker write. */
24
+ requireLock() {
25
+ if (!this.lockId) {
26
+ throw new Error('Tracker has no active lock; refusing to issue tracker mutations. ' +
27
+ 'Call acquireLock() first.');
28
+ }
29
+ }
30
+ /** Builds a TransactWrite ConditionCheck that asserts we still own the lock. */
31
+ lockOwnershipCheck() {
32
+ this.requireLock();
33
+ return {
34
+ ConditionCheck: {
35
+ TableName: this.tableName,
36
+ Key: this.lockKey,
37
+ ConditionExpression: 'lockId = :lockId',
38
+ ExpressionAttributeValues: {
39
+ ':lockId': this.lockId,
40
+ },
41
+ },
42
+ };
13
43
  }
14
44
  async initialize() {
15
45
  // Check if current version pointer exists, if not create it
@@ -33,24 +63,21 @@ class DynamoDBMigrationTracker {
33
63
  * Acquire a distributed lock to prevent concurrent migrations
34
64
  */
35
65
  async acquireLock() {
36
- const lockKey = {
37
- PK: `${this.trackingPrefix}#LOCK`,
38
- SK: `${this.trackingPrefix}#LOCK`,
39
- };
40
66
  const now = Date.now();
41
- const expiresAt = now + LOCK_TTL_SECONDS * 1000;
67
+ const expiresAt = now + this.lockTtlSeconds * 1000;
42
68
  this.lockId = `lock-${now}-${Math.random().toString(36).substring(7)}`;
43
69
  try {
44
70
  await this.client.send(new lib_dynamodb_1.PutCommand({
45
71
  TableName: this.tableName,
46
72
  Item: {
47
- ...lockKey,
73
+ ...this.lockKey,
48
74
  lockId: this.lockId,
49
75
  acquiredAt: new Date().toISOString(),
50
76
  expiresAt,
51
77
  },
52
- // Only succeed if lock doesn't exist or has expired
53
- ConditionExpression: 'attribute_not_exists(PK) OR expiresAt < :now',
78
+ // Only succeed if lock doesn't exist or has expired. The `<=`
79
+ // covers the boundary where two clocks read the exact ms.
80
+ ConditionExpression: 'attribute_not_exists(PK) OR expiresAt <= :now',
54
81
  ExpressionAttributeValues: {
55
82
  ':now': now,
56
83
  },
@@ -65,20 +92,37 @@ class DynamoDBMigrationTracker {
65
92
  throw error;
66
93
  }
67
94
  }
95
+ /**
96
+ * Extend the lock's expiration by another `lockTtlSeconds`. Throws
97
+ * `ConditionalCheckFailedException` if another worker has already taken
98
+ * the lock — callers should treat that as "we lost the race; stop
99
+ * making writes". Silent no-op if no lock is currently held.
100
+ */
101
+ async refreshLock() {
102
+ if (!this.lockId)
103
+ return;
104
+ const newExpiresAt = Date.now() + this.lockTtlSeconds * 1000;
105
+ await this.client.send(new lib_dynamodb_1.UpdateCommand({
106
+ TableName: this.tableName,
107
+ Key: this.lockKey,
108
+ UpdateExpression: 'SET expiresAt = :exp',
109
+ ConditionExpression: 'lockId = :lockId',
110
+ ExpressionAttributeValues: {
111
+ ':exp': newExpiresAt,
112
+ ':lockId': this.lockId,
113
+ },
114
+ }));
115
+ }
68
116
  /**
69
117
  * Release the distributed lock
70
118
  */
71
119
  async releaseLock() {
72
120
  if (!this.lockId)
73
121
  return;
74
- const lockKey = {
75
- PK: `${this.trackingPrefix}#LOCK`,
76
- SK: `${this.trackingPrefix}#LOCK`,
77
- };
78
122
  try {
79
123
  await this.client.send(new lib_dynamodb_1.DeleteCommand({
80
124
  TableName: this.tableName,
81
- Key: lockKey,
125
+ Key: this.lockKey,
82
126
  // Only delete if we own the lock
83
127
  ConditionExpression: 'lockId = :lockId',
84
128
  ExpressionAttributeValues: {
@@ -131,6 +175,7 @@ class DynamoDBMigrationTracker {
131
175
  * Handles both new migrations and re-applying rolled back migrations
132
176
  */
133
177
  async markAsApplied(version, name, schemaDefinition, schemaChanges, checksum) {
178
+ this.requireLock();
134
179
  const now = new Date().toISOString();
135
180
  // Check if migration record already exists (e.g., rolled back or failed)
136
181
  const existing = await this.getMigration(version);
@@ -157,6 +202,7 @@ class DynamoDBMigrationTracker {
157
202
  }
158
203
  await this.client.send(new lib_dynamodb_1.TransactWriteCommand({
159
204
  TransactItems: [
205
+ this.lockOwnershipCheck(),
160
206
  {
161
207
  Update: {
162
208
  TableName: this.tableName,
@@ -197,6 +243,7 @@ class DynamoDBMigrationTracker {
197
243
  // Create new migration record
198
244
  await this.client.send(new lib_dynamodb_1.TransactWriteCommand({
199
245
  TransactItems: [
246
+ this.lockOwnershipCheck(),
200
247
  {
201
248
  Put: {
202
249
  TableName: this.tableName,
@@ -212,8 +259,9 @@ class DynamoDBMigrationTracker {
212
259
  schemaChanges,
213
260
  checksum,
214
261
  },
215
- // Ensure migration wasn't already applied
216
- ConditionExpression: 'attribute_not_exists(PK)',
262
+ // Ensure migration wasn't already applied (uniqueness on
263
+ // SK; PK is shared across all migration rows).
264
+ ConditionExpression: 'attribute_not_exists(SK)',
217
265
  },
218
266
  },
219
267
  {
@@ -239,16 +287,18 @@ class DynamoDBMigrationTracker {
239
287
  * Mark migration as rolled back using TransactWrite for atomicity
240
288
  */
241
289
  async markAsRolledBack(version) {
290
+ this.requireLock();
242
291
  const now = new Date().toISOString();
243
292
  // Find previous version
244
293
  const migrations = await this.getAppliedMigrations();
245
294
  const appliedMigrations = migrations
246
295
  .filter((m) => m.status === 'applied' && m.version !== version)
247
- .sort((a, b) => b.version.localeCompare(a.version));
296
+ .sort((a, b) => (0, semver_1.compareSemver)(b.version, a.version));
248
297
  const previousVersion = appliedMigrations[0]?.version || 'v0000';
249
298
  // Use TransactWrite to atomically update record and pointer
250
299
  await this.client.send(new lib_dynamodb_1.TransactWriteCommand({
251
300
  TransactItems: [
301
+ this.lockOwnershipCheck(),
252
302
  {
253
303
  Update: {
254
304
  TableName: this.tableName,
@@ -285,62 +335,86 @@ class DynamoDBMigrationTracker {
285
335
  }));
286
336
  }
287
337
  async markAsFailed(version, error) {
338
+ this.requireLock();
288
339
  // Check if the migration record exists first
289
340
  const existing = await this.getMigration(version);
341
+ const now = new Date().toISOString();
290
342
  if (existing) {
291
- // Update existing record
292
- await this.client.send(new lib_dynamodb_1.UpdateCommand({
293
- TableName: this.tableName,
294
- Key: {
295
- PK: this.trackingPrefix,
296
- SK: version,
297
- },
298
- UpdateExpression: 'SET #status = :status, #error = :error, failedAt = :timestamp',
299
- ExpressionAttributeNames: {
300
- '#status': 'status',
301
- '#error': 'error',
302
- },
303
- ExpressionAttributeValues: {
304
- ':status': 'failed',
305
- ':error': error,
306
- ':timestamp': new Date().toISOString(),
307
- },
343
+ // Update existing record, gated by lock ownership
344
+ await this.client.send(new lib_dynamodb_1.TransactWriteCommand({
345
+ TransactItems: [
346
+ this.lockOwnershipCheck(),
347
+ {
348
+ Update: {
349
+ TableName: this.tableName,
350
+ Key: {
351
+ PK: this.trackingPrefix,
352
+ SK: version,
353
+ },
354
+ UpdateExpression: 'SET #status = :status, #error = :error, failedAt = :timestamp',
355
+ ExpressionAttributeNames: {
356
+ '#status': 'status',
357
+ '#error': 'error',
358
+ },
359
+ ExpressionAttributeValues: {
360
+ ':status': 'failed',
361
+ ':error': error,
362
+ ':timestamp': now,
363
+ },
364
+ },
365
+ },
366
+ ],
308
367
  }));
309
368
  }
310
369
  else {
311
- // Create new record for failed migration
312
- await this.client.send(new lib_dynamodb_1.PutCommand({
313
- TableName: this.tableName,
314
- Item: {
315
- PK: this.trackingPrefix,
316
- SK: version,
317
- version,
318
- name: 'unknown',
319
- status: 'failed',
320
- error,
321
- failedAt: new Date().toISOString(),
322
- timestamp: new Date().toISOString(),
323
- },
370
+ // Create new record for failed migration, gated by lock ownership
371
+ await this.client.send(new lib_dynamodb_1.TransactWriteCommand({
372
+ TransactItems: [
373
+ this.lockOwnershipCheck(),
374
+ {
375
+ Put: {
376
+ TableName: this.tableName,
377
+ Item: {
378
+ PK: this.trackingPrefix,
379
+ SK: version,
380
+ version,
381
+ name: 'unknown',
382
+ status: 'failed',
383
+ error,
384
+ failedAt: now,
385
+ timestamp: now,
386
+ },
387
+ },
388
+ },
389
+ ],
324
390
  }));
325
391
  }
326
392
  }
327
393
  async recordSchemaChange(change) {
394
+ this.requireLock();
328
395
  const currentVersion = await this.getCurrentVersion();
329
396
  if (!currentVersion || currentVersion === 'v0000') {
330
397
  throw new Error('Cannot record schema change: No migration has been applied yet');
331
398
  }
332
- // Append to schemaChanges array
333
- await this.client.send(new lib_dynamodb_1.UpdateCommand({
334
- TableName: this.tableName,
335
- Key: {
336
- PK: this.trackingPrefix,
337
- SK: currentVersion,
338
- },
339
- UpdateExpression: 'SET schemaChanges = list_append(if_not_exists(schemaChanges, :empty_list), :change)',
340
- ExpressionAttributeValues: {
341
- ':empty_list': [],
342
- ':change': [change],
343
- },
399
+ // Append to schemaChanges array, gated by lock ownership
400
+ await this.client.send(new lib_dynamodb_1.TransactWriteCommand({
401
+ TransactItems: [
402
+ this.lockOwnershipCheck(),
403
+ {
404
+ Update: {
405
+ TableName: this.tableName,
406
+ Key: {
407
+ PK: this.trackingPrefix,
408
+ SK: currentVersion,
409
+ },
410
+ UpdateExpression: 'SET schemaChanges = list_append(if_not_exists(schemaChanges, :empty_list), :change)',
411
+ ExpressionAttributeValues: {
412
+ ':empty_list': [],
413
+ ':change': [change],
414
+ },
415
+ },
416
+ },
417
+ ],
344
418
  }));
345
419
  }
346
420
  async getMigration(version) {
@@ -1 +1 @@
1
- {"version":3,"file":"tracker.js","sourceRoot":"","sources":["../../src/core/tracker.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tracker.js","sourceRoot":"","sources":["../../src/core/tracker.ts"],"names":[],"mappings":";;;AACA,wDAO+B;AAE/B,qCAAyC;AAEzC,oFAAoF;AACvE,QAAA,wBAAwB,GAAG,GAAG,CAAC,CAAC,YAAY;AAEzD,MAAa,wBAAwB;IASnC,YAAY,MAA8B,EAAE,MAAuB;QAJ3D,WAAM,GAAkB,IAAI,CAAC;QAKnC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;QAClC,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC,cAAc,IAAI,iBAAiB,CAAC;QACjE,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC;QAC1C,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC,cAAc,IAAI,gCAAwB,CAAC;IAC1E,CAAC;IAED,IAAY,OAAO;QACjB,OAAO;YACL,EAAE,EAAE,GAAG,IAAI,CAAC,cAAc,OAAO;YACjC,EAAE,EAAE,GAAG,IAAI,CAAC,cAAc,OAAO;SAClC,CAAC;IACJ,CAAC;IAED,wEAAwE;IAChE,WAAW;QACjB,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CACb,mEAAmE;gBACjE,2BAA2B,CAC9B,CAAC;QACJ,CAAC;IACH,CAAC;IAED,gFAAgF;IACxE,kBAAkB;QACxB,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,OAAO;YACL,cAAc,EAAE;gBACd,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,GAAG,EAAE,IAAI,CAAC,OAAO;gBACjB,mBAAmB,EAAE,kBAAkB;gBACvC,yBAAyB,EAAE;oBACzB,SAAS,EAAE,IAAI,CAAC,MAAM;iBACvB;aACF;SACF,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,UAAU;QACd,4DAA4D;QAC5D,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC/C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,iCAAiC;YACjC,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CACpB,IAAI,yBAAU,CAAC;gBACb,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,IAAI,EAAE;oBACJ,EAAE,EAAE,GAAG,IAAI,CAAC,cAAc,UAAU;oBACpC,EAAE,EAAE,GAAG,IAAI,CAAC,cAAc,UAAU;oBACpC,MAAM,EAAE,gBAAgB;oBACxB,MAAM,EAAE,OAAO;oBACf,cAAc,EAAE,OAAO;oBACvB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;iBACpC;aACF,CAAC,CACH,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,WAAW;QACf,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,SAAS,GAAG,GAAG,GAAG,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;QACnD,IAAI,CAAC,MAAM,GAAG,QAAQ,GAAG,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;QAEvE,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CACpB,IAAI,yBAAU,CAAC;gBACb,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,IAAI,EAAE;oBACJ,GAAG,IAAI,CAAC,OAAO;oBACf,MAAM,EAAE,IAAI,CAAC,MAAM;oBACnB,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;oBACpC,SAAS;iBACV;gBACD,8DAA8D;gBAC9D,0DAA0D;gBAC1D,mBAAmB,EAAE,+CAA+C;gBACpE,yBAAyB,EAAE;oBACzB,MAAM,EAAE,GAAG;iBACZ;aACF,CAAC,CACH,CAAC;YACF,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,IAAI,KAAK,CAAC,IAAI,KAAK,iCAAiC,EAAE,CAAC;gBACrD,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;gBACnB,OAAO,KAAK,CAAC;YACf,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,WAAW;QACf,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO;QAEzB,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;QAE7D,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CACpB,IAAI,4BAAa,CAAC;YAChB,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,GAAG,EAAE,IAAI,CAAC,OAAO;YACjB,gBAAgB,EAAE,sBAAsB;YACxC,mBAAmB,EAAE,kBAAkB;YACvC,yBAAyB,EAAE;gBACzB,MAAM,EAAE,YAAY;gBACpB,SAAS,EAAE,IAAI,CAAC,MAAM;aACvB;SACF,CAAC,CACH,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,WAAW;QACf,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO;QAEzB,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CACpB,IAAI,4BAAa,CAAC;gBAChB,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,GAAG,EAAE,IAAI,CAAC,OAAO;gBACjB,iCAAiC;gBACjC,mBAAmB,EAAE,kBAAkB;gBACvC,yBAAyB,EAAE;oBACzB,SAAS,EAAE,IAAI,CAAC,MAAM;iBACvB;aACF,CAAC,CACH,CAAC;QACJ,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,sDAAsD;YACtD,IAAI,KAAK,CAAC,IAAI,KAAK,iCAAiC,EAAE,CAAC;gBACrD,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACrB,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,oBAAoB;QACxB,MAAM,KAAK,GAAsB,EAAE,CAAC;QACpC,IAAI,OAAwC,CAAC;QAE7C,GAAG,CAAC;YACF,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CACnC,IAAI,2BAAY,CAAC;gBACf,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,sBAAsB,EAAE,UAAU;gBAClC,yBAAyB,EAAE;oBACzB,KAAK,EAAE,IAAI,CAAC,cAAc;iBAC3B;gBACD,iBAAiB,EAAE,OAAO;aAC3B,CAAC,CACH,CAAC;YAEF,KAAK,CAAC,IAAI,CAAC,GAAI,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CAAuB,CAAC,CAAC;YAC3D,OAAO,GAAG,MAAM,CAAC,gBAAgB,CAAC;QACpC,CAAC,QAAQ,OAAO,EAAE;QAElB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,KAAK,CAAC,iBAAiB;QACrB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CACnC,IAAI,yBAAU,CAAC;YACb,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,GAAG,EAAE;gBACH,EAAE,EAAE,GAAG,IAAI,CAAC,cAAc,UAAU;gBACpC,EAAE,EAAE,GAAG,IAAI,CAAC,cAAc,UAAU;aACrC;SACF,CAAC,CACH,CAAC;QAEF,OAAO,MAAM,CAAC,IAAI,EAAE,cAAc,IAAI,IAAI,CAAC;IAC7C,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,aAAa,CACjB,OAAe,EACf,IAAY,EACZ,gBAAsC,EACtC,aAA8B,EAC9B,QAAiB;QAEjB,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAErC,yEAAyE;QACzE,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QAElD,IAAI,QAAQ,EAAE,CAAC;YACb,yEAAyE;YACzE,6EAA6E;YAC7E,MAAM,QAAQ,GAAG,CAAC,mBAAmB,EAAE,wBAAwB,EAAE,eAAe,CAAC,CAAC;YAClF,MAAM,gBAAgB,GAAwB;gBAC5C,SAAS,EAAE,SAAS;gBACpB,YAAY,EAAE,GAAG;gBACjB,OAAO,EAAE,IAAI;aACd,CAAC;YAEF,IAAI,gBAAgB,KAAK,SAAS,EAAE,CAAC;gBACnC,QAAQ,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;gBAC/C,gBAAgB,CAAC,YAAY,CAAC,GAAG,gBAAgB,CAAC;YACpD,CAAC;YACD,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;gBAChC,QAAQ,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC;gBAChD,gBAAgB,CAAC,gBAAgB,CAAC,GAAG,aAAa,CAAC;YACrD,CAAC;YACD,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;gBAC3B,QAAQ,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;gBACtC,gBAAgB,CAAC,WAAW,CAAC,GAAG,QAAQ,CAAC;YAC3C,CAAC;YAED,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CACpB,IAAI,mCAAoB,CAAC;gBACvB,aAAa,EAAE;oBACb,IAAI,CAAC,kBAAkB,EAAE;oBACzB;wBACE,MAAM,EAAE;4BACN,SAAS,EAAE,IAAI,CAAC,SAAS;4BACzB,GAAG,EAAE;gCACH,EAAE,EAAE,IAAI,CAAC,cAAc;gCACvB,EAAE,EAAE,OAAO;6BACZ;4BACD,gBAAgB,EAAE,OAAO,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,wCAAwC;4BACpF,wBAAwB,EAAE;gCACxB,SAAS,EAAE,QAAQ;gCACnB,OAAO,EAAE,MAAM;gCACf,QAAQ,EAAE,OAAO;6BAClB;4BACD,yBAAyB,EAAE,gBAAgB;4BAC3C,kDAAkD;4BAClD,mBAAmB,EAAE,oBAAoB;yBAC1C;qBACF;oBACD;wBACE,MAAM,EAAE;4BACN,SAAS,EAAE,IAAI,CAAC,SAAS;4BACzB,GAAG,EAAE;gCACH,EAAE,EAAE,GAAG,IAAI,CAAC,cAAc,UAAU;gCACpC,EAAE,EAAE,GAAG,IAAI,CAAC,cAAc,UAAU;6BACrC;4BACD,gBAAgB,EACd,yEAAyE;4BAC3E,yBAAyB,EAAE;gCACzB,UAAU,EAAE,OAAO;gCACnB,YAAY,EAAE,GAAG;gCACjB,SAAS,EAAE,OAAO;6BACnB;yBACF;qBACF;iBACF;aACF,CAAC,CACH,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,8BAA8B;YAC9B,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CACpB,IAAI,mCAAoB,CAAC;gBACvB,aAAa,EAAE;oBACb,IAAI,CAAC,kBAAkB,EAAE;oBACzB;wBACE,GAAG,EAAE;4BACH,SAAS,EAAE,IAAI,CAAC,SAAS;4BACzB,IAAI,EAAE;gCACJ,EAAE,EAAE,IAAI,CAAC,cAAc;gCACvB,EAAE,EAAE,OAAO;gCACX,OAAO;gCACP,IAAI;gCACJ,SAAS,EAAE,GAAG;gCACd,SAAS,EAAE,GAAG;gCACd,MAAM,EAAE,SAAS;gCACjB,gBAAgB;gCAChB,aAAa;gCACb,QAAQ;6BACU;4BACpB,yDAAyD;4BACzD,+CAA+C;4BAC/C,mBAAmB,EAAE,0BAA0B;yBAChD;qBACF;oBACD;wBACE,MAAM,EAAE;4BACN,SAAS,EAAE,IAAI,CAAC,SAAS;4BACzB,GAAG,EAAE;gCACH,EAAE,EAAE,GAAG,IAAI,CAAC,cAAc,UAAU;gCACpC,EAAE,EAAE,GAAG,IAAI,CAAC,cAAc,UAAU;6BACrC;4BACD,gBAAgB,EACd,yEAAyE;4BAC3E,yBAAyB,EAAE;gCACzB,UAAU,EAAE,OAAO;gCACnB,YAAY,EAAE,GAAG;gCACjB,SAAS,EAAE,OAAO;6BACnB;yBACF;qBACF;iBACF;aACF,CAAC,CACH,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,gBAAgB,CAAC,OAAe;QACpC,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAErC,wBAAwB;QACxB,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,oBAAoB,EAAE,CAAC;QACrD,MAAM,iBAAiB,GAAG,UAAU;aACjC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,OAAO,KAAK,OAAO,CAAC;aAC9D,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAA,sBAAa,EAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;QAEvD,MAAM,eAAe,GAAG,iBAAiB,CAAC,CAAC,CAAC,EAAE,OAAO,IAAI,OAAO,CAAC;QAEjE,4DAA4D;QAC5D,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CACpB,IAAI,mCAAoB,CAAC;YACvB,aAAa,EAAE;gBACb,IAAI,CAAC,kBAAkB,EAAE;gBACzB;oBACE,MAAM,EAAE;wBACN,SAAS,EAAE,IAAI,CAAC,SAAS;wBACzB,GAAG,EAAE;4BACH,EAAE,EAAE,IAAI,CAAC,cAAc;4BACvB,EAAE,EAAE,OAAO;yBACZ;wBACD,gBAAgB,EAAE,kDAAkD;wBACpE,wBAAwB,EAAE;4BACxB,SAAS,EAAE,QAAQ;yBACpB;wBACD,yBAAyB,EAAE;4BACzB,SAAS,EAAE,aAAa;4BACxB,YAAY,EAAE,GAAG;yBAClB;qBACF;iBACF;gBACD;oBACE,MAAM,EAAE;wBACN,SAAS,EAAE,IAAI,CAAC,SAAS;wBACzB,GAAG,EAAE;4BACH,EAAE,EAAE,GAAG,IAAI,CAAC,cAAc,UAAU;4BACpC,EAAE,EAAE,GAAG,IAAI,CAAC,cAAc,UAAU;yBACrC;wBACD,gBAAgB,EACd,yEAAyE;wBAC3E,yBAAyB,EAAE;4BACzB,UAAU,EAAE,eAAe;4BAC3B,YAAY,EAAE,GAAG;4BACjB,SAAS,EAAE,eAAe;yBAC3B;qBACF;iBACF;aACF;SACF,CAAC,CACH,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,OAAe,EAAE,KAAa;QAC/C,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,6CAA6C;QAC7C,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QAClD,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAErC,IAAI,QAAQ,EAAE,CAAC;YACb,kDAAkD;YAClD,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CACpB,IAAI,mCAAoB,CAAC;gBACvB,aAAa,EAAE;oBACb,IAAI,CAAC,kBAAkB,EAAE;oBACzB;wBACE,MAAM,EAAE;4BACN,SAAS,EAAE,IAAI,CAAC,SAAS;4BACzB,GAAG,EAAE;gCACH,EAAE,EAAE,IAAI,CAAC,cAAc;gCACvB,EAAE,EAAE,OAAO;6BACZ;4BACD,gBAAgB,EACd,+DAA+D;4BACjE,wBAAwB,EAAE;gCACxB,SAAS,EAAE,QAAQ;gCACnB,QAAQ,EAAE,OAAO;6BAClB;4BACD,yBAAyB,EAAE;gCACzB,SAAS,EAAE,QAAQ;gCACnB,QAAQ,EAAE,KAAK;gCACf,YAAY,EAAE,GAAG;6BAClB;yBACF;qBACF;iBACF;aACF,CAAC,CACH,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,kEAAkE;YAClE,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CACpB,IAAI,mCAAoB,CAAC;gBACvB,aAAa,EAAE;oBACb,IAAI,CAAC,kBAAkB,EAAE;oBACzB;wBACE,GAAG,EAAE;4BACH,SAAS,EAAE,IAAI,CAAC,SAAS;4BACzB,IAAI,EAAE;gCACJ,EAAE,EAAE,IAAI,CAAC,cAAc;gCACvB,EAAE,EAAE,OAAO;gCACX,OAAO;gCACP,IAAI,EAAE,SAAS;gCACf,MAAM,EAAE,QAAQ;gCAChB,KAAK;gCACL,QAAQ,EAAE,GAAG;gCACb,SAAS,EAAE,GAAG;6BACf;yBACF;qBACF;iBACF;aACF,CAAC,CACH,CAAC;QACJ,CAAC;IACH,CAAC;IAED,KAAK,CAAC,kBAAkB,CAAC,MAAoB;QAC3C,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACtD,IAAI,CAAC,cAAc,IAAI,cAAc,KAAK,OAAO,EAAE,CAAC;YAClD,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;QACpF,CAAC;QAED,yDAAyD;QACzD,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CACpB,IAAI,mCAAoB,CAAC;YACvB,aAAa,EAAE;gBACb,IAAI,CAAC,kBAAkB,EAAE;gBACzB;oBACE,MAAM,EAAE;wBACN,SAAS,EAAE,IAAI,CAAC,SAAS;wBACzB,GAAG,EAAE;4BACH,EAAE,EAAE,IAAI,CAAC,cAAc;4BACvB,EAAE,EAAE,cAAc;yBACnB;wBACD,gBAAgB,EACd,qFAAqF;wBACvF,yBAAyB,EAAE;4BACzB,aAAa,EAAE,EAAE;4BACjB,SAAS,EAAE,CAAC,MAAM,CAAC;yBACpB;qBACF;iBACF;aACF;SACF,CAAC,CACH,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,OAAe;QAChC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CACnC,IAAI,yBAAU,CAAC;YACb,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,GAAG,EAAE;gBACH,EAAE,EAAE,IAAI,CAAC,cAAc;gBACvB,EAAE,EAAE,OAAO;aACZ;SACF,CAAC,CACH,CAAC;QAEF,OAAQ,MAAM,CAAC,IAAwB,IAAI,IAAI,CAAC;IAClD,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,OAAe;QAC7B,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QACnD,OAAO,SAAS,EAAE,MAAM,KAAK,SAAS,CAAC;IACzC,CAAC;CACF;AAlfD,4DAkfC"}
@@ -95,6 +95,12 @@ export interface MigrationConfig {
95
95
  migrationsDir?: string;
96
96
  trackingPrefix?: string;
97
97
  gsi1Name?: string;
98
+ /**
99
+ * How long an acquired migration lock stays valid before another worker
100
+ * can take it over, in seconds. The runner sends a heartbeat every
101
+ * `lockTtlSeconds / 3` to extend it. Default: 300 (5 minutes).
102
+ */
103
+ lockTtlSeconds?: number;
98
104
  }
99
105
  /**
100
106
  * Migration tracker interface
@@ -120,6 +126,11 @@ export interface MigrationTracker {
120
126
  * Release the distributed lock
121
127
  */
122
128
  releaseLock(): Promise<void>;
129
+ /**
130
+ * Extend the lock's expiration. Throws `ConditionalCheckFailedException`
131
+ * if the lock has already been taken by someone else.
132
+ */
133
+ refreshLock(): Promise<void>;
123
134
  /**
124
135
  * Mark migration as applied
125
136
  */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
package/jest.config.js ADDED
@@ -0,0 +1,8 @@
1
+ /** @type {import('jest').Config} */
2
+ module.exports = {
3
+ preset: 'ts-jest',
4
+ testEnvironment: 'node',
5
+ testMatch: ['**/?(*.)+(test).[tj]s'],
6
+ testPathIgnorePatterns: ['/node_modules/', '/dist/'],
7
+ roots: ['<rootDir>/src'],
8
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ftschopp/dynatable-migrations",
3
- "version": "1.2.2",
3
+ "version": "1.2.4",
4
4
  "description": "DynamoDB migration tool for single table design with schema versioning",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -14,7 +14,7 @@
14
14
  "build": "tsc",
15
15
  "dev": "tsc --watch",
16
16
  "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist",
17
- "test": "echo \"No tests yet!\""
17
+ "test": "jest"
18
18
  },
19
19
  "keywords": [
20
20
  "dynamodb",
@@ -28,6 +28,7 @@
28
28
  "@repo/typescript-config": "*",
29
29
  "@types/jest": "^30.0.0",
30
30
  "@types/node": "^25.0.3",
31
+ "aws-sdk-client-mock": "^4.1.0",
31
32
  "jest": "^30.2.0",
32
33
  "ts-jest": "^29.4.6",
33
34
  "typescript": "5.9.3"
@@ -2,6 +2,7 @@ import * as fs from 'fs';
2
2
  import * as path from 'path';
3
3
  import * as crypto from 'crypto';
4
4
  import { Migration, MigrationFile } from '../types';
5
+ import { compareSemver } from './semver';
5
6
 
6
7
  /**
7
8
  * Load all migration files from directory
@@ -41,7 +42,7 @@ export class MigrationLoader {
41
42
  // Sort by semver
42
43
  const versionA = a.match(/^(\d+\.\d+\.\d+)/)?.[1] || '0.0.0';
43
44
  const versionB = b.match(/^(\d+\.\d+\.\d+)/)?.[1] || '0.0.0';
44
- return this.compareSemver(versionA, versionB);
45
+ return compareSemver(versionA, versionB);
45
46
  });
46
47
 
47
48
  const migrations: MigrationFile[] = [];
@@ -252,22 +253,4 @@ export class MigrationLoader {
252
253
  return '0.1.0';
253
254
  }
254
255
 
255
- /**
256
- * Compare semver versions
257
- * Returns: -1 if a < b, 0 if a === b, 1 if a > b
258
- */
259
- private compareSemver(a: string, b: string): number {
260
- const partsA = a.split('.').map((n) => parseInt(n, 10));
261
- const partsB = b.split('.').map((n) => parseInt(n, 10));
262
-
263
- for (let i = 0; i < 3; i++) {
264
- const numA = partsA[i] || 0;
265
- const numB = partsB[i] || 0;
266
-
267
- if (numA > numB) return 1;
268
- if (numA < numB) return -1;
269
- }
270
-
271
- return 0;
272
- }
273
256
  }
@@ -0,0 +1,78 @@
1
+ import { startLockHeartbeat } from './lock-heartbeat';
2
+ import type { MigrationTracker } from '../types';
3
+
4
+ beforeEach(() => {
5
+ jest.useFakeTimers();
6
+ });
7
+
8
+ afterEach(() => {
9
+ jest.useRealTimers();
10
+ });
11
+
12
+ function makeTracker(refresh: jest.Mock): MigrationTracker {
13
+ // Only the methods the heartbeat actually touches need to be present.
14
+ return {
15
+ refreshLock: refresh,
16
+ } as unknown as MigrationTracker;
17
+ }
18
+
19
+ describe('startLockHeartbeat', () => {
20
+ test('calls refreshLock every ~ttl/3 seconds', () => {
21
+ const refresh = jest.fn().mockResolvedValue(undefined);
22
+ const tracker = makeTracker(refresh);
23
+ const stop = startLockHeartbeat(tracker, 30); // every 10s
24
+
25
+ jest.advanceTimersByTime(10_000);
26
+ expect(refresh).toHaveBeenCalledTimes(1);
27
+
28
+ jest.advanceTimersByTime(10_000);
29
+ expect(refresh).toHaveBeenCalledTimes(2);
30
+
31
+ stop();
32
+ });
33
+
34
+ test('stop() clears the interval and prevents further refreshes', () => {
35
+ const refresh = jest.fn().mockResolvedValue(undefined);
36
+ const tracker = makeTracker(refresh);
37
+ const stop = startLockHeartbeat(tracker, 30);
38
+
39
+ jest.advanceTimersByTime(10_000);
40
+ stop();
41
+ jest.advanceTimersByTime(60_000);
42
+
43
+ expect(refresh).toHaveBeenCalledTimes(1);
44
+ });
45
+
46
+ test('clamps the interval to a 1s minimum even with absurdly small TTLs', () => {
47
+ const refresh = jest.fn().mockResolvedValue(undefined);
48
+ const tracker = makeTracker(refresh);
49
+ const stop = startLockHeartbeat(tracker, 0.5); // would compute < 1s
50
+
51
+ jest.advanceTimersByTime(999);
52
+ expect(refresh).toHaveBeenCalledTimes(0);
53
+ jest.advanceTimersByTime(1);
54
+ expect(refresh).toHaveBeenCalledTimes(1);
55
+
56
+ stop();
57
+ });
58
+
59
+ test('swallows refresh errors so transient failures do not crash the runner', async () => {
60
+ const warn = jest.spyOn(console, 'warn').mockImplementation(() => {});
61
+ const refresh = jest
62
+ .fn()
63
+ .mockRejectedValueOnce(Object.assign(new Error('boom'), { name: 'NetworkError' }));
64
+ const tracker = makeTracker(refresh);
65
+ const stop = startLockHeartbeat(tracker, 30);
66
+
67
+ jest.advanceTimersByTime(10_000);
68
+ // Let the rejected promise settle
69
+ await Promise.resolve();
70
+ await Promise.resolve();
71
+
72
+ expect(refresh).toHaveBeenCalledTimes(1);
73
+ expect(warn).toHaveBeenCalled();
74
+
75
+ stop();
76
+ warn.mockRestore();
77
+ });
78
+ });
@@ -0,0 +1,48 @@
1
+ import type { MigrationTracker } from '../types';
2
+
3
+ /**
4
+ * Periodically refreshes the migration lock so that migrations longer than
5
+ * the lock TTL don't have their lock taken by another worker.
6
+ *
7
+ * Returns a stop function. Call it from the same `finally` that releases
8
+ * the lock to make sure the interval doesn't leak.
9
+ *
10
+ * The heartbeat fires every `ttlSeconds / 3` seconds. Errors from the
11
+ * underlying refresh are logged and swallowed: if the lock is genuinely
12
+ * lost, the next tracker mutation will fail its ConditionCheck and the
13
+ * runner will surface a clear `TransactionCanceledException` to the user.
14
+ */
15
+ export function startLockHeartbeat(
16
+ tracker: MigrationTracker,
17
+ ttlSeconds: number
18
+ ): () => void {
19
+ // Fire well before expiry so a single missed beat doesn't drop the lock.
20
+ const intervalMs = Math.max(1_000, Math.floor((ttlSeconds * 1000) / 3));
21
+ let active = true;
22
+
23
+ const handle = setInterval(() => {
24
+ if (!active) return;
25
+ void tracker.refreshLock().catch((err: unknown) => {
26
+ const name = (err as { name?: string } | null)?.name;
27
+ const message = (err as { message?: string } | null)?.message ?? String(err);
28
+ if (name === 'ConditionalCheckFailedException') {
29
+ console.warn(
30
+ '⚠️ Migration lock was taken by another process. ' +
31
+ 'Subsequent tracker writes will fail.'
32
+ );
33
+ } else {
34
+ console.warn(`⚠️ Failed to refresh migration lock: ${message}`);
35
+ }
36
+ });
37
+ }, intervalMs);
38
+
39
+ // Don't keep the Node event loop alive just for the heartbeat.
40
+ if (typeof handle.unref === 'function') {
41
+ handle.unref();
42
+ }
43
+
44
+ return () => {
45
+ active = false;
46
+ clearInterval(handle);
47
+ };
48
+ }
@@ -14,6 +14,8 @@ import {
14
14
  import { MigrationConfig, MigrationContext, MigrationFile, MigrationStatus } from '../types';
15
15
  import { DynamoDBMigrationTracker } from './tracker';
16
16
  import { MigrationLoader } from './loader';
17
+ import { compareSemver } from './semver';
18
+ import { startLockHeartbeat } from './lock-heartbeat';
17
19
 
18
20
  export interface RunOptions {
19
21
  limit?: number;
@@ -49,6 +51,7 @@ export class MigrationRunner {
49
51
  await this.initialize();
50
52
 
51
53
  // Acquire lock unless dry run
54
+ let stopHeartbeat: (() => void) | undefined;
52
55
  if (!dryRun) {
53
56
  const lockAcquired = await this.tracker.acquireLock();
54
57
  if (!lockAcquired) {
@@ -57,6 +60,7 @@ export class MigrationRunner {
57
60
  'If you believe this is an error, wait a few minutes and try again.'
58
61
  );
59
62
  }
63
+ stopHeartbeat = startLockHeartbeat(this.tracker, this.tracker.lockTtlSeconds);
60
64
  }
61
65
 
62
66
  try {
@@ -132,7 +136,9 @@ export class MigrationRunner {
132
136
 
133
137
  return executed;
134
138
  } finally {
135
- // Always release lock
139
+ // Always stop the heartbeat and release the lock — in that order, so
140
+ // we don't refresh a lock we're about to delete.
141
+ if (stopHeartbeat) stopHeartbeat();
136
142
  if (!dryRun) {
137
143
  await this.tracker.releaseLock();
138
144
  }
@@ -146,18 +152,20 @@ export class MigrationRunner {
146
152
  await this.initialize();
147
153
 
148
154
  // Acquire lock unless dry run
155
+ let stopHeartbeat: (() => void) | undefined;
149
156
  if (!dryRun) {
150
157
  const lockAcquired = await this.tracker.acquireLock();
151
158
  if (!lockAcquired) {
152
159
  throw new Error('Could not acquire migration lock. Another migration may be in progress.');
153
160
  }
161
+ stopHeartbeat = startLockHeartbeat(this.tracker, this.tracker.lockTtlSeconds);
154
162
  }
155
163
 
156
164
  try {
157
165
  const appliedMigrations = await this.tracker.getAppliedMigrations();
158
166
  const applied = appliedMigrations
159
167
  .filter((m) => m.status === 'applied')
160
- .sort((a, b) => b.version.localeCompare(a.version))
168
+ .sort((a, b) => compareSemver(b.version, a.version))
161
169
  .slice(0, steps);
162
170
 
163
171
  if (applied.length === 0) {
@@ -206,6 +214,7 @@ export class MigrationRunner {
206
214
 
207
215
  return rolledBack;
208
216
  } finally {
217
+ if (stopHeartbeat) stopHeartbeat();
209
218
  if (!dryRun) {
210
219
  await this.tracker.releaseLock();
211
220
  }