@ftschopp/dynatable-migrations 1.2.3 → 1.2.5
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.
- package/CHANGELOG.md +14 -0
- package/dist/core/errors.d.ts +25 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +47 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/lock-heartbeat.d.ts +15 -0
- package/dist/core/lock-heartbeat.d.ts.map +1 -0
- package/dist/core/lock-heartbeat.js +44 -0
- package/dist/core/lock-heartbeat.js.map +1 -0
- package/dist/core/runner.d.ts.map +1 -1
- package/dist/core/runner.js +11 -1
- package/dist/core/runner.js.map +1 -1
- package/dist/core/tracker.d.ts +30 -0
- package/dist/core/tracker.d.ts.map +1 -1
- package/dist/core/tracker.js +262 -148
- package/dist/core/tracker.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/types/index.d.ts +11 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +2 -1
- package/src/core/errors.ts +55 -0
- package/src/core/lock-heartbeat.test.ts +78 -0
- package/src/core/lock-heartbeat.ts +48 -0
- package/src/core/runner.ts +9 -1
- package/src/core/tracker.test.ts +281 -0
- package/src/core/tracker.ts +286 -158
- package/src/index.ts +1 -0
- package/src/types/index.ts +12 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## @ftschopp/dynatable-migrations [1.2.5](https://github.com/ftschopp/dynatable/compare/@ftschopp/dynatable-migrations@1.2.4...@ftschopp/dynatable-migrations@1.2.5) (2026-05-08)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **migrations:** make markAsApplied idempotent and surface typed errors ([#29](https://github.com/ftschopp/dynatable/issues/29)) ([133b836](https://github.com/ftschopp/dynatable/commit/133b83656c0891a04a155c603f53220dadaa6f87)), closes [#10](https://github.com/ftschopp/dynatable/issues/10)
|
|
7
|
+
|
|
8
|
+
## @ftschopp/dynatable-migrations [1.2.4](https://github.com/ftschopp/dynatable/compare/@ftschopp/dynatable-migrations@1.2.3...@ftschopp/dynatable-migrations@1.2.4) (2026-05-08)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* **migrations:** add lock refresh and gate tracker writes on ownership ([#28](https://github.com/ftschopp/dynatable/issues/28)) ([5d9d033](https://github.com/ftschopp/dynatable/commit/5d9d0336c0e79179208209906f4c72797eb5f275)), closes [#9](https://github.com/ftschopp/dynatable/issues/9)
|
|
14
|
+
|
|
1
15
|
## @ftschopp/dynatable-migrations [1.2.3](https://github.com/ftschopp/dynatable/compare/@ftschopp/dynatable-migrations@1.2.2...@ftschopp/dynatable-migrations@1.2.3) (2026-05-08)
|
|
2
16
|
|
|
3
17
|
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thrown by `markAsApplied` when the version already has a tracking record
|
|
3
|
+
* in a non-applied state (e.g. `failed`, `rolled_back`) and therefore
|
|
4
|
+
* cannot be silently treated as an idempotent re-apply. Surfaces the
|
|
5
|
+
* existing state so the caller can decide whether to retry, recover, or
|
|
6
|
+
* roll back.
|
|
7
|
+
*/
|
|
8
|
+
export declare class MigrationAlreadyAppliedError extends Error {
|
|
9
|
+
readonly version: string;
|
|
10
|
+
readonly currentStatus: string | undefined;
|
|
11
|
+
constructor(version: string, currentStatus: string | undefined);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Thrown when a tracker write is cancelled because the migration lock was
|
|
15
|
+
* taken by another process between `acquireLock()` and the write itself
|
|
16
|
+
* (e.g. the original lock TTL expired and a second worker took over).
|
|
17
|
+
*
|
|
18
|
+
* The transaction was rolled back atomically — no partial state was
|
|
19
|
+
* written. The safe action is to stop the current `up()` / `down()` run.
|
|
20
|
+
*/
|
|
21
|
+
export declare class MigrationLockLostError extends Error {
|
|
22
|
+
readonly version: string;
|
|
23
|
+
constructor(version: string);
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,qBAAa,4BAA6B,SAAQ,KAAK;IACrD,SAAgB,OAAO,EAAE,MAAM,CAAC;IAChC,SAAgB,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;gBAEtC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,SAAS;CAgB/D;AAED;;;;;;;GAOG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;IAC/C,SAAgB,OAAO,EAAE,MAAM,CAAC;gBAEpB,OAAO,EAAE,MAAM;CAc5B"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MigrationLockLostError = exports.MigrationAlreadyAppliedError = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Thrown by `markAsApplied` when the version already has a tracking record
|
|
6
|
+
* in a non-applied state (e.g. `failed`, `rolled_back`) and therefore
|
|
7
|
+
* cannot be silently treated as an idempotent re-apply. Surfaces the
|
|
8
|
+
* existing state so the caller can decide whether to retry, recover, or
|
|
9
|
+
* roll back.
|
|
10
|
+
*/
|
|
11
|
+
class MigrationAlreadyAppliedError extends Error {
|
|
12
|
+
constructor(version, currentStatus) {
|
|
13
|
+
super(`Migration "${version}" already has a tracking record in state ` +
|
|
14
|
+
`"${currentStatus ?? 'unknown'}" — cannot mark as applied. ` +
|
|
15
|
+
`If you want to re-apply this version, roll it back first ` +
|
|
16
|
+
`(or recover the failed run) and try again.`);
|
|
17
|
+
this.name = 'MigrationAlreadyAppliedError';
|
|
18
|
+
this.version = version;
|
|
19
|
+
this.currentStatus = currentStatus;
|
|
20
|
+
if (typeof Error.captureStackTrace === 'function') {
|
|
21
|
+
Error.captureStackTrace(this, MigrationAlreadyAppliedError);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
exports.MigrationAlreadyAppliedError = MigrationAlreadyAppliedError;
|
|
26
|
+
/**
|
|
27
|
+
* Thrown when a tracker write is cancelled because the migration lock was
|
|
28
|
+
* taken by another process between `acquireLock()` and the write itself
|
|
29
|
+
* (e.g. the original lock TTL expired and a second worker took over).
|
|
30
|
+
*
|
|
31
|
+
* The transaction was rolled back atomically — no partial state was
|
|
32
|
+
* written. The safe action is to stop the current `up()` / `down()` run.
|
|
33
|
+
*/
|
|
34
|
+
class MigrationLockLostError extends Error {
|
|
35
|
+
constructor(version) {
|
|
36
|
+
super(`Migration lock was lost during markAsApplied("${version}"). ` +
|
|
37
|
+
`Another worker may have taken over. The transaction was rolled ` +
|
|
38
|
+
`back atomically; no partial state was written.`);
|
|
39
|
+
this.name = 'MigrationLockLostError';
|
|
40
|
+
this.version = version;
|
|
41
|
+
if (typeof Error.captureStackTrace === 'function') {
|
|
42
|
+
Error.captureStackTrace(this, MigrationLockLostError);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
exports.MigrationLockLostError = MigrationLockLostError;
|
|
47
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":";;;AAAA;;;;;;GAMG;AACH,MAAa,4BAA6B,SAAQ,KAAK;IAIrD,YAAY,OAAe,EAAE,aAAiC;QAC5D,KAAK,CACH,cAAc,OAAO,2CAA2C;YAC9D,IAAI,aAAa,IAAI,SAAS,8BAA8B;YAC5D,2DAA2D;YAC3D,4CAA4C,CAC/C,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,8BAA8B,CAAC;QAC3C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;QACnC,IAAI,OAAQ,KAAoD,CAAC,iBAAiB,KAAK,UAAU,EAAE,CAAC;YAEhG,KACD,CAAC,iBAAiB,CAAC,IAAI,EAAE,4BAA4B,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC;CACF;AApBD,oEAoBC;AAED;;;;;;;GAOG;AACH,MAAa,sBAAuB,SAAQ,KAAK;IAG/C,YAAY,OAAe;QACzB,KAAK,CACH,iDAAiD,OAAO,MAAM;YAC5D,iEAAiE;YACjE,gDAAgD,CACnD,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAC;QACrC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,OAAQ,KAAoD,CAAC,iBAAiB,KAAK,UAAU,EAAE,CAAC;YAEhG,KACD,CAAC,iBAAiB,CAAC,IAAI,EAAE,sBAAsB,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;CACF;AAjBD,wDAiBC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { MigrationTracker } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Periodically refreshes the migration lock so that migrations longer than
|
|
4
|
+
* the lock TTL don't have their lock taken by another worker.
|
|
5
|
+
*
|
|
6
|
+
* Returns a stop function. Call it from the same `finally` that releases
|
|
7
|
+
* the lock to make sure the interval doesn't leak.
|
|
8
|
+
*
|
|
9
|
+
* The heartbeat fires every `ttlSeconds / 3` seconds. Errors from the
|
|
10
|
+
* underlying refresh are logged and swallowed: if the lock is genuinely
|
|
11
|
+
* lost, the next tracker mutation will fail its ConditionCheck and the
|
|
12
|
+
* runner will surface a clear `TransactionCanceledException` to the user.
|
|
13
|
+
*/
|
|
14
|
+
export declare function startLockHeartbeat(tracker: MigrationTracker, ttlSeconds: number): () => void;
|
|
15
|
+
//# sourceMappingURL=lock-heartbeat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lock-heartbeat.d.ts","sourceRoot":"","sources":["../../src/core/lock-heartbeat.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAEjD;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,gBAAgB,EACzB,UAAU,EAAE,MAAM,GACjB,MAAM,IAAI,CA8BZ"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.startLockHeartbeat = startLockHeartbeat;
|
|
4
|
+
/**
|
|
5
|
+
* Periodically refreshes the migration lock so that migrations longer than
|
|
6
|
+
* the lock TTL don't have their lock taken by another worker.
|
|
7
|
+
*
|
|
8
|
+
* Returns a stop function. Call it from the same `finally` that releases
|
|
9
|
+
* the lock to make sure the interval doesn't leak.
|
|
10
|
+
*
|
|
11
|
+
* The heartbeat fires every `ttlSeconds / 3` seconds. Errors from the
|
|
12
|
+
* underlying refresh are logged and swallowed: if the lock is genuinely
|
|
13
|
+
* lost, the next tracker mutation will fail its ConditionCheck and the
|
|
14
|
+
* runner will surface a clear `TransactionCanceledException` to the user.
|
|
15
|
+
*/
|
|
16
|
+
function startLockHeartbeat(tracker, ttlSeconds) {
|
|
17
|
+
// Fire well before expiry so a single missed beat doesn't drop the lock.
|
|
18
|
+
const intervalMs = Math.max(1000, Math.floor((ttlSeconds * 1000) / 3));
|
|
19
|
+
let active = true;
|
|
20
|
+
const handle = setInterval(() => {
|
|
21
|
+
if (!active)
|
|
22
|
+
return;
|
|
23
|
+
void tracker.refreshLock().catch((err) => {
|
|
24
|
+
const name = err?.name;
|
|
25
|
+
const message = err?.message ?? String(err);
|
|
26
|
+
if (name === 'ConditionalCheckFailedException') {
|
|
27
|
+
console.warn('⚠️ Migration lock was taken by another process. ' +
|
|
28
|
+
'Subsequent tracker writes will fail.');
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
console.warn(`⚠️ Failed to refresh migration lock: ${message}`);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
}, intervalMs);
|
|
35
|
+
// Don't keep the Node event loop alive just for the heartbeat.
|
|
36
|
+
if (typeof handle.unref === 'function') {
|
|
37
|
+
handle.unref();
|
|
38
|
+
}
|
|
39
|
+
return () => {
|
|
40
|
+
active = false;
|
|
41
|
+
clearInterval(handle);
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=lock-heartbeat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lock-heartbeat.js","sourceRoot":"","sources":["../../src/core/lock-heartbeat.ts"],"names":[],"mappings":";;AAcA,gDAiCC;AA7CD;;;;;;;;;;;GAWG;AACH,SAAgB,kBAAkB,CAChC,OAAyB,EACzB,UAAkB;IAElB,yEAAyE;IACzE,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,IAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACxE,IAAI,MAAM,GAAG,IAAI,CAAC;IAElB,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,EAAE;QAC9B,IAAI,CAAC,MAAM;YAAE,OAAO;QACpB,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;YAChD,MAAM,IAAI,GAAI,GAAgC,EAAE,IAAI,CAAC;YACrD,MAAM,OAAO,GAAI,GAAmC,EAAE,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC;YAC7E,IAAI,IAAI,KAAK,iCAAiC,EAAE,CAAC;gBAC/C,OAAO,CAAC,IAAI,CACV,mDAAmD;oBACjD,sCAAsC,CACzC,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,IAAI,CAAC,yCAAyC,OAAO,EAAE,CAAC,CAAC;YACnE,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,EAAE,UAAU,CAAC,CAAC;IAEf,+DAA+D;IAC/D,IAAI,OAAO,MAAM,CAAC,KAAK,KAAK,UAAU,EAAE,CAAC;QACvC,MAAM,CAAC,KAAK,EAAE,CAAC;IACjB,CAAC;IAED,OAAO,GAAG,EAAE;QACV,MAAM,GAAG,KAAK,CAAC;QACf,aAAa,CAAC,MAAM,CAAC,CAAC;IACxB,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/core/runner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAa/D,OAAO,EAAE,eAAe,EAAoB,aAAa,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/core/runner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAa/D,OAAO,EAAE,eAAe,EAAoB,aAAa,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAM7F,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAyB;IACvC,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,MAAM,CAAkB;gBAEpB,MAAM,EAAE,sBAAsB,EAAE,MAAM,EAAE,eAAe;IAOnE;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAIjC;;OAEG;IACG,EAAE,CAAC,OAAO,GAAE,UAAe,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;IAoG5D;;OAEG;IACG,IAAI,CAAC,KAAK,GAAE,MAAU,EAAE,MAAM,GAAE,OAAe,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;IAyEhF;;OAEG;IACG,MAAM,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;IA6B1C;;OAEG;IACG,iBAAiB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAKjD;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAa5B;;OAEG;IACH,OAAO,CAAC,aAAa;CAoBtB"}
|
package/dist/core/runner.js
CHANGED
|
@@ -5,6 +5,7 @@ const lib_dynamodb_1 = require("@aws-sdk/lib-dynamodb");
|
|
|
5
5
|
const tracker_1 = require("./tracker");
|
|
6
6
|
const loader_1 = require("./loader");
|
|
7
7
|
const semver_1 = require("./semver");
|
|
8
|
+
const lock_heartbeat_1 = require("./lock-heartbeat");
|
|
8
9
|
class MigrationRunner {
|
|
9
10
|
constructor(client, config) {
|
|
10
11
|
this.client = client;
|
|
@@ -25,12 +26,14 @@ class MigrationRunner {
|
|
|
25
26
|
const { limit, dryRun = false } = options;
|
|
26
27
|
await this.initialize();
|
|
27
28
|
// Acquire lock unless dry run
|
|
29
|
+
let stopHeartbeat;
|
|
28
30
|
if (!dryRun) {
|
|
29
31
|
const lockAcquired = await this.tracker.acquireLock();
|
|
30
32
|
if (!lockAcquired) {
|
|
31
33
|
throw new Error('Could not acquire migration lock. Another migration may be in progress. ' +
|
|
32
34
|
'If you believe this is an error, wait a few minutes and try again.');
|
|
33
35
|
}
|
|
36
|
+
stopHeartbeat = (0, lock_heartbeat_1.startLockHeartbeat)(this.tracker, this.tracker.lockTtlSeconds);
|
|
34
37
|
}
|
|
35
38
|
try {
|
|
36
39
|
const appliedMigrations = await this.tracker.getAppliedMigrations();
|
|
@@ -85,7 +88,10 @@ class MigrationRunner {
|
|
|
85
88
|
return executed;
|
|
86
89
|
}
|
|
87
90
|
finally {
|
|
88
|
-
// Always release lock
|
|
91
|
+
// Always stop the heartbeat and release the lock — in that order, so
|
|
92
|
+
// we don't refresh a lock we're about to delete.
|
|
93
|
+
if (stopHeartbeat)
|
|
94
|
+
stopHeartbeat();
|
|
89
95
|
if (!dryRun) {
|
|
90
96
|
await this.tracker.releaseLock();
|
|
91
97
|
}
|
|
@@ -97,11 +103,13 @@ class MigrationRunner {
|
|
|
97
103
|
async down(steps = 1, dryRun = false) {
|
|
98
104
|
await this.initialize();
|
|
99
105
|
// Acquire lock unless dry run
|
|
106
|
+
let stopHeartbeat;
|
|
100
107
|
if (!dryRun) {
|
|
101
108
|
const lockAcquired = await this.tracker.acquireLock();
|
|
102
109
|
if (!lockAcquired) {
|
|
103
110
|
throw new Error('Could not acquire migration lock. Another migration may be in progress.');
|
|
104
111
|
}
|
|
112
|
+
stopHeartbeat = (0, lock_heartbeat_1.startLockHeartbeat)(this.tracker, this.tracker.lockTtlSeconds);
|
|
105
113
|
}
|
|
106
114
|
try {
|
|
107
115
|
const appliedMigrations = await this.tracker.getAppliedMigrations();
|
|
@@ -145,6 +153,8 @@ class MigrationRunner {
|
|
|
145
153
|
return rolledBack;
|
|
146
154
|
}
|
|
147
155
|
finally {
|
|
156
|
+
if (stopHeartbeat)
|
|
157
|
+
stopHeartbeat();
|
|
148
158
|
if (!dryRun) {
|
|
149
159
|
await this.tracker.releaseLock();
|
|
150
160
|
}
|
package/dist/core/runner.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/core/runner.ts"],"names":[],"mappings":";;;AACA,wDAW+B;AAE/B,uCAAqD;AACrD,qCAA2C;AAC3C,qCAAyC;
|
|
1
|
+
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/core/runner.ts"],"names":[],"mappings":"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"}
|
package/dist/core/tracker.d.ts
CHANGED
|
@@ -1,17 +1,33 @@
|
|
|
1
1
|
import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb';
|
|
2
2
|
import { MigrationTracker, MigrationRecord, SchemaChange, MigrationConfig } from '../types';
|
|
3
|
+
/** Default lock TTL in seconds. Configurable via MigrationConfig.lockTtlSeconds. */
|
|
4
|
+
export declare const DEFAULT_LOCK_TTL_SECONDS = 300;
|
|
3
5
|
export declare class DynamoDBMigrationTracker implements MigrationTracker {
|
|
4
6
|
private client;
|
|
5
7
|
private tableName;
|
|
6
8
|
private trackingPrefix;
|
|
7
9
|
private gsi1Name;
|
|
8
10
|
private lockId;
|
|
11
|
+
/** TTL for newly-acquired or refreshed locks. */
|
|
12
|
+
readonly lockTtlSeconds: number;
|
|
9
13
|
constructor(client: DynamoDBDocumentClient, config: MigrationConfig);
|
|
14
|
+
private get lockKey();
|
|
15
|
+
/** Throws if there is no active lock. Call before any tracker write. */
|
|
16
|
+
private requireLock;
|
|
17
|
+
/** Builds a TransactWrite ConditionCheck that asserts we still own the lock. */
|
|
18
|
+
private lockOwnershipCheck;
|
|
10
19
|
initialize(): Promise<void>;
|
|
11
20
|
/**
|
|
12
21
|
* Acquire a distributed lock to prevent concurrent migrations
|
|
13
22
|
*/
|
|
14
23
|
acquireLock(): Promise<boolean>;
|
|
24
|
+
/**
|
|
25
|
+
* Extend the lock's expiration by another `lockTtlSeconds`. Throws
|
|
26
|
+
* `ConditionalCheckFailedException` if another worker has already taken
|
|
27
|
+
* the lock — callers should treat that as "we lost the race; stop
|
|
28
|
+
* making writes". Silent no-op if no lock is currently held.
|
|
29
|
+
*/
|
|
30
|
+
refreshLock(): Promise<void>;
|
|
15
31
|
/**
|
|
16
32
|
* Release the distributed lock
|
|
17
33
|
*/
|
|
@@ -26,6 +42,20 @@ export declare class DynamoDBMigrationTracker implements MigrationTracker {
|
|
|
26
42
|
* Handles both new migrations and re-applying rolled back migrations
|
|
27
43
|
*/
|
|
28
44
|
markAsApplied(version: string, name: string, schemaDefinition?: Record<string, any>, schemaChanges?: SchemaChange[], checksum?: string): Promise<void>;
|
|
45
|
+
/**
|
|
46
|
+
* Inspect a `TransactionCanceledException` raised by `markAsApplied` and
|
|
47
|
+
* either swallow it (idempotent re-apply) or re-throw a typed error.
|
|
48
|
+
*
|
|
49
|
+
* The TransactWrite items are: [lockOwnershipCheck, migrationRow, currentPointer].
|
|
50
|
+
* Each item produces an entry in `CancellationReasons`.
|
|
51
|
+
* - reasons[0] failing → the lock was lost → MigrationLockLostError.
|
|
52
|
+
* - reasons[1] failing → the migration row already exists in a state the
|
|
53
|
+
* write refused. Re-fetch the record:
|
|
54
|
+
* * status === 'applied' → idempotent re-apply, return silently.
|
|
55
|
+
* * other states → MigrationAlreadyAppliedError with the
|
|
56
|
+
* current state, so the caller can decide what to do.
|
|
57
|
+
*/
|
|
58
|
+
private handleMarkAsAppliedCancellation;
|
|
29
59
|
/**
|
|
30
60
|
* Mark migration as rolled back using TransactWrite for atomicity
|
|
31
61
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tracker.d.ts","sourceRoot":"","sources":["../../src/core/tracker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAS/D,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"tracker.d.ts","sourceRoot":"","sources":["../../src/core/tracker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAS/D,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAI5F,oFAAoF;AACpF,eAAO,MAAM,wBAAwB,MAAM,CAAC;AAE5C,qBAAa,wBAAyB,YAAW,gBAAgB;IAC/D,OAAO,CAAC,MAAM,CAAyB;IACvC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,MAAM,CAAuB;IACrC,iDAAiD;IACjD,SAAgB,cAAc,EAAE,MAAM,CAAC;gBAE3B,MAAM,EAAE,sBAAsB,EAAE,MAAM,EAAE,eAAe;IAQnE,OAAO,KAAK,OAAO,GAKlB;IAED,wEAAwE;IACxE,OAAO,CAAC,WAAW;IASnB,gFAAgF;IAChF,OAAO,CAAC,kBAAkB;IAcpB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAqBjC;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAiCrC;;;;;OAKG;IACG,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAmBlC;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAyBlC;;OAEG;IACG,oBAAoB,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;IAuBlD,iBAAiB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAcjD;;;OAGG;IACG,aAAa,CACjB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACtC,aAAa,CAAC,EAAE,YAAY,EAAE,EAC9B,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC;IA2HhB;;;;;;;;;;;;OAYG;YACW,+BAA+B;IA2B7C;;OAEG;IACG,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAuDhD,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA8D3D,kBAAkB,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAgCvD,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAc9D,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAInD"}
|