@plakboek/db 0.1.0 → 0.1.2
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/README.md +5 -5
- package/dist/index.js +24 -3
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -8,11 +8,11 @@ for Plakboek CMS installations.
|
|
|
8
8
|
- `createDb` -- a Drizzle (`drizzle-orm/postgres-js`) connection factory
|
|
9
9
|
over the `postgres` (porsager) driver.
|
|
10
10
|
- `runMigrations` -- applies this package's own statically registered
|
|
11
|
-
migrations,
|
|
12
|
-
concurrent migrators can never double-apply (D-03). What
|
|
13
|
-
step invokes.
|
|
14
|
-
- `
|
|
15
|
-
|
|
11
|
+
migrations, taking a session-scoped Postgres advisory lock internally for
|
|
12
|
+
the whole run so concurrent migrators can never double-apply (D-03). What
|
|
13
|
+
Phase 6's deploy step invokes.
|
|
14
|
+
- `MigrationLockTimeoutError` -- thrown by `runMigrations` when another
|
|
15
|
+
migrator still holds that advisory lock after `lockWaitMs`.
|
|
16
16
|
- The migration authoring convention every migration -- this package's own
|
|
17
17
|
and every host/host-extension migration -- follows: see
|
|
18
18
|
[`MIGRATIONS.md`](./MIGRATIONS.md).
|
package/dist/index.js
CHANGED
|
@@ -32,6 +32,15 @@ function createDb(options) {
|
|
|
32
32
|
}
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
|
+
//#endregion
|
|
36
|
+
//#region src/lock.ts
|
|
37
|
+
/**
|
|
38
|
+
* Fixed advisory-lock key reserved for @plakboek/db's migration runner.
|
|
39
|
+
* Postgres advisory locks share a single namespace per database across every
|
|
40
|
+
* caller -- this key must never be reused by another subsystem within a
|
|
41
|
+
* @plakboek/db-managed database.
|
|
42
|
+
*/
|
|
43
|
+
const MIGRATION_LOCK_KEY = "4839120657231098713";
|
|
35
44
|
var MigrationLockTimeoutError = class extends Error {
|
|
36
45
|
waitedMs;
|
|
37
46
|
constructor(waitedMs) {
|
|
@@ -92,14 +101,26 @@ async function runGuarded(fn) {
|
|
|
92
101
|
*
|
|
93
102
|
* The unlock query always runs after `fn` settles (success or failure) --
|
|
94
103
|
* this is expressed as unconditional sequential code (not a `try/finally`)
|
|
95
|
-
* so returning `outcome.value` never needs an unsafe cast to narrow `T`.
|
|
104
|
+
* so returning `outcome.value` never needs an unsafe cast to narrow `T`. The
|
|
105
|
+
* unlock query itself is guarded the same way `fn` is: if `fn` already
|
|
106
|
+
* succeeded (its work is already durable in Postgres) and the unlock query
|
|
107
|
+
* then fails -- e.g. the connection drops between commit and unlock -- that
|
|
108
|
+
* failure is logged rather than thrown, so a lock-release problem can never
|
|
109
|
+
* discard an already-successful `outcome.value`. Postgres releases a
|
|
110
|
+
* session-scoped advisory lock automatically once the session disconnects,
|
|
111
|
+
* so a failed unlock does not leave the lock stuck. If `fn` itself failed,
|
|
112
|
+
* `fn`'s error is what gets thrown regardless of the unlock outcome.
|
|
96
113
|
*/
|
|
97
114
|
async function withMigrationLock(client, fn, options) {
|
|
98
115
|
await acquire(client, options?.waitMs ?? DEFAULT_WAIT_MS, options?.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS);
|
|
99
116
|
const outcome = await runGuarded(fn);
|
|
100
|
-
const
|
|
117
|
+
const unlockOutcome = await runGuarded(() => client.query("SELECT pg_advisory_unlock($1::bigint) AS unlocked", [MIGRATION_LOCK_KEY]));
|
|
101
118
|
if (outcome.ok) {
|
|
102
|
-
if (!
|
|
119
|
+
if (!unlockOutcome.ok) {
|
|
120
|
+
console.error("@plakboek/db: migrations applied successfully, but releasing the migration lock failed -- the lock releases automatically once this session disconnects", unlockOutcome.error);
|
|
121
|
+
return outcome.value;
|
|
122
|
+
}
|
|
123
|
+
if (!(unlockOutcome.value.rows[0]?.unlocked ?? false)) throw new Error("@plakboek/db: migration lock was not held at release -- this indicates a bug in withMigrationLock or an external pg_advisory_unlock call on the same key");
|
|
103
124
|
return outcome.value;
|
|
104
125
|
}
|
|
105
126
|
throw outcome.error;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plakboek/db",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Postgres connection factory and migration-lock primitives for Plakboek CMS installations",
|
|
5
5
|
"homepage": "https://github.com/flovan/plakboek/tree/main/packages/db#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -25,7 +25,8 @@
|
|
|
25
25
|
"./package.json": "./package.json"
|
|
26
26
|
},
|
|
27
27
|
"publishConfig": {
|
|
28
|
-
"access": "public"
|
|
28
|
+
"access": "public",
|
|
29
|
+
"provenance": true
|
|
29
30
|
},
|
|
30
31
|
"dependencies": {
|
|
31
32
|
"pg": "^8.23.0",
|
|
@@ -45,7 +46,7 @@
|
|
|
45
46
|
"drizzle-orm": "^0.45.2"
|
|
46
47
|
},
|
|
47
48
|
"engines": {
|
|
48
|
-
"node": ">=22.
|
|
49
|
+
"node": ">=22.18"
|
|
49
50
|
},
|
|
50
51
|
"scripts": {
|
|
51
52
|
"build": "tsdown",
|