@autofleet/sequelize-utils 6.2.0-alpha.2 → 6.2.0-alpha.3
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 +7 -7
- package/dist/cli.js +2 -2
- package/dist/cli.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -100,22 +100,22 @@ set -e
|
|
|
100
100
|
|
|
101
101
|
node_modules/.bin/sequelize db:create || echo 'Failed creating database, possibly since it already exists.'
|
|
102
102
|
|
|
103
|
-
npx sequelize-utils
|
|
104
|
-
node --run migrate
|
|
105
|
-
npx sequelize-utils unlock-migrations
|
|
103
|
+
npx sequelize-utils run-migrations --db-name-env DB_NAME --db-username-env DB_USERNAME --db-password-env DB_PASSWORD -- npm run migrate
|
|
106
104
|
```
|
|
107
105
|
|
|
106
|
+
`run-migrations` acquires the lock, runs the migration command, and always releases the lock — even if the migration crashes. Pass the migration command after `--`.
|
|
107
|
+
|
|
108
108
|
The `--*-env` flags tell the CLI which environment variable to read for each connection parameter. This lets services use their own env var naming conventions without wrapper scripts.
|
|
109
109
|
|
|
110
110
|
### What happens with multiple pods
|
|
111
111
|
|
|
112
112
|
```
|
|
113
|
-
Pod 1 →
|
|
114
|
-
Pod 2 →
|
|
115
|
-
Pod 3 →
|
|
113
|
+
Pod 1 → run-migrations (acquires pg advisory lock) → migrate (runs DDL) → (releases lock)
|
|
114
|
+
Pod 2 → run-migrations (blocks) ───────────────────────────────────────→ (unblocks) → migrate (no-op, already applied) → (releases lock)
|
|
115
|
+
Pod 3 → run-migrations (blocks) ───────────────────────────────────────→ (unblocks) → migrate (no-op, already applied) → (releases lock)
|
|
116
116
|
```
|
|
117
117
|
|
|
118
|
-
If a pod crashes
|
|
118
|
+
If a pod crashes mid-migration, PostgreSQL automatically releases the advisory lock when the daemon connection closes — no manual cleanup needed.
|
|
119
119
|
|
|
120
120
|
### CLI flags
|
|
121
121
|
|
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{fork as e}from"node:child_process";import{existsSync as
|
|
3
|
-
`);for(let t of e){let e=/^([^#=\s][^=]*)=(.*)$/.exec(t);if(e){let t=e[1].trim(),n=e[2].trim().replace(/^["']|["']$/g,``);t in process.env||(process.env[t]=n)}}}catch{}const
|
|
2
|
+
import{fork as e,spawn as t}from"node:child_process";import{existsSync as n,readFileSync as r,unlinkSync as i,writeFileSync as a}from"node:fs";import o from"pg";try{let e=r(`.env`,`utf8`).split(`
|
|
3
|
+
`);for(let t of e){let e=/^([^#=\s][^=]*)=(.*)$/.exec(t);if(e){let t=e[1].trim(),n=e[2].trim().replace(/^["']|["']$/g,``);t in process.env||(process.env[t]=n)}}}catch{}const s=`/tmp/__sequelize_migration_lock.pid`,c=e=>process.stdout.write(`[sequelize-utils] ${e}\n`),l=e=>process.stderr.write(`[sequelize-utils] ${e}\n`),u=e=>process.stderr.write(`[sequelize-utils] ${e}\n`);function d(e){let t={};for(let n=0;n<e.length;n++)e[n].startsWith(`--`)&&n+1<e.length&&!e[n+1].startsWith(`--`)&&(t[e[n].slice(2)]=e[n+1],n++);return t}function f(e,t,n){return process.env[e[t]??n]}async function p(e){let t=Number(f(e,`lock-key-env`,`MIGRATION_LOCK_KEY`))||1234567890,n=new o.Client({host:f(e,`db-host-env`,`DB_HOST`)??`localhost`,port:Number(f(e,`db-port-env`,`DB_PORT`))||5432,database:f(e,`db-name-env`,`DB_NAME`),user:f(e,`db-username-env`,`DB_USERNAME`),password:f(e,`db-password-env`,`DB_PASSWORD`)});await n.connect(),await n.query(`SELECT pg_advisory_lock(${t})`),process.send?.(`locked`);let r=()=>{n.query(`SELECT pg_advisory_unlock(${t})`).then(()=>n.end()).finally(()=>process.exit(0))};process.once(`SIGTERM`,r),process.once(`SIGINT`,r)}async function m(t){let n=Number(f(t,`lock-timeout-env`,`MIGRATION_LOCK_TIMEOUT_MS`))||6e4,r=Object.entries(t).flatMap(([e,t])=>[`--${e}`,t]),i=e(process.argv[1],[`--daemon`,...r],{stdio:[`ignore`,`inherit`,`inherit`,`ipc`],env:process.env,execArgv:process.execArgv});await new Promise((e,t)=>{let r=setTimeout(()=>{i.kill(),t(Error(`Timed out waiting for migration lock after ${n}ms`))},n);i.once(`message`,n=>{clearTimeout(r),n===`locked`?e():(i.kill(),t(Error(`Lock daemon error: ${JSON.stringify(n)}`)))}),i.once(`error`,e=>{clearTimeout(r),t(e)})}),a(s,String(i.pid)),i.disconnect(),i.unref(),c(`Migration lock acquired (pid=${i.pid})`)}function h(){if(!n(s)){l(`No lock file found — nothing to release`);return}let e=Number(r(s,`utf8`).trim());try{process.kill(e,`SIGTERM`)}catch{l(`Daemon pid=${e} not found (may have already exited)`)}i(s),c(`Migration lock released`)}async function g(e,n){n.length===0&&(u(`run-migrations requires a command after --`),u(`Usage: sequelize-utils run-migrations [--*-env flags] -- <command>`),process.exit(1)),await m(e);let[r,...i]=n,a=0;try{a=await new Promise(e=>{let n=t(r,i,{stdio:`inherit`,shell:!1});n.once(`exit`,t=>e(t??1)),n.once(`error`,t=>{u(`Migration command error: ${t.message}`),e(1)})})}finally{h()}a!==0&&process.exit(a)}if(process.argv.includes(`--daemon`)){let e=process.argv.indexOf(`--daemon`);p(d(process.argv.slice(e+1))).catch(e=>{u(`Lock daemon failed: ${e.message}`),process.exit(1)})}else{let[,,e,...t]=process.argv;switch(e){case`lock-migrations`:m(d(t)).catch(e=>{u(e.message),process.exit(1)});break;case`unlock-migrations`:h();break;case`run-migrations`:{let e=t.indexOf(`--`),n=e===-1?t:t.slice(0,e),r=e===-1?[]:t.slice(e+1);g(d(n),r).catch(e=>{u(e.message),process.exit(1)});break}default:u(`Unknown command: ${e}`),process.stderr.write(`Usage: sequelize-utils <run-migrations|lock-migrations|unlock-migrations> [--*-env flags] [-- <command>]
|
|
4
4
|
`),process.exit(1)}}export{};
|
|
5
5
|
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","names":["result: Args"],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { fork } from 'node:child_process';\nimport { existsSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';\nimport pg from 'pg';\n\n// Auto-load .env from the current working directory (same behaviour as dotenv).\n// Only sets variables that are not already present in process.env.\ntry {\n const lines = readFileSync('.env', 'utf8').split('\\n');\n for (const line of lines) {\n const match = /^([^#=\\s][^=]*)=(.*)$/.exec(line);\n if (match) {\n const key = match[1].trim();\n const value = match[2].trim().replace(/^[\"']|[\"']$/g, '');\n if (!(key in process.env)) {\n process.env[key] = value;\n }\n }\n }\n} catch {\n // no .env file — that's fine\n}\n\nconst LOCK_FILE = '/tmp/__sequelize_migration_lock.pid';\nconst DEFAULT_LOCK_KEY = 1_234_567_890;\nconst DEFAULT_LOCK_TIMEOUT_MS = 60_000;\n\nconst log = (msg: string) => process.stdout.write(`[sequelize-utils] ${msg}\\n`);\nconst warn = (msg: string) => process.stderr.write(`[sequelize-utils] ${msg}\\n`);\nconst fatal = (msg: string) => process.stderr.write(`[sequelize-utils] ${msg}\\n`);\n\n// ─── Arg parsing ──────────────────────────────────────────────────────────────\n\ntype Args = Record<string, string>;\n\nfunction parseArgs(argv: string[]): Args {\n const result: Args = {};\n for (let i = 0; i < argv.length; i++) {\n if (argv[i].startsWith('--') && i + 1 < argv.length && !argv[i + 1].startsWith('--')) {\n result[argv[i].slice(2)] = argv[i + 1];\n i++;\n }\n }\n return result;\n}\n\n// Resolves the value of an env var whose name may be overridden by a CLI arg.\n// e.g. --db-name-env MY_SERVICE_DB_NAME → process.env['MY_SERVICE_DB_NAME']\nfunction env(args: Args, argName: string, defaultEnvVar: string): string | undefined {\n return process.env[args[argName] ?? defaultEnvVar];\n}\n\n// ─── Daemon ───────────────────────────────────────────────────────────────────\n// Spawned as a detached subprocess by `lock-migrations`.\n// Holds a PostgreSQL session-level advisory lock for as long as it lives.\n// When killed by `unlock-migrations`, the connection closes and pg auto-releases the lock.\n\nasync function runDaemon(args: Args): Promise<void> {\n const lockKey = Number(env(args, 'lock-key-env', 'MIGRATION_LOCK_KEY')) || DEFAULT_LOCK_KEY;\n\n const client = new pg.Client({\n host: env(args, 'db-host-env', 'DB_HOST') ?? 'localhost',\n port: Number(env(args, 'db-port-env', 'DB_PORT')) || 5432,\n database: env(args, 'db-name-env', 'DB_NAME'),\n user: env(args, 'db-username-env', 'DB_USERNAME'),\n password: env(args, 'db-password-env', 'DB_PASSWORD'),\n });\n\n await client.connect();\n\n // Blocking — waits until no other pod holds the lock\n await client.query(`SELECT pg_advisory_lock(${lockKey})`);\n\n // Signal parent that the lock is held\n process.send?.('locked');\n\n const release = () => {\n void client.query(`SELECT pg_advisory_unlock(${lockKey})`)\n .then(() => client.end())\n .finally(() => process.exit(0));\n };\n\n process.once('SIGTERM', release);\n process.once('SIGINT', release);\n}\n\n// ─── lock-migrations ──────────────────────────────────────────────────────────\n\nasync function lockMigrations(args: Args): Promise<void> {\n const lockTimeoutMs = Number(env(args, 'lock-timeout-env', 'MIGRATION_LOCK_TIMEOUT_MS')) || DEFAULT_LOCK_TIMEOUT_MS;\n\n // Forward all --*-env args to the daemon so it resolves the same env vars.\n const forwardedArgs = Object.entries(args).flatMap(([k, v]) => [`--${k}`, v]);\n\n const daemon = fork(process.argv[1], ['--daemon', ...forwardedArgs], {\n stdio: ['ignore', 'inherit', 'inherit', 'ipc'],\n env: process.env,\n execArgv: process.execArgv,\n });\n\n await new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(() => {\n daemon.kill();\n reject(new Error(`Timed out waiting for migration lock after ${lockTimeoutMs}ms`));\n }, lockTimeoutMs);\n\n daemon.once('message', (msg) => {\n clearTimeout(timeout);\n if (msg === 'locked') {\n resolve();\n } else {\n daemon.kill();\n reject(new Error(`Lock daemon error: ${JSON.stringify(msg)}`));\n }\n });\n\n daemon.once('error', (err) => {\n clearTimeout(timeout);\n reject(err);\n });\n });\n\n writeFileSync(LOCK_FILE, String(daemon.pid));\n daemon.disconnect(); // close IPC channel so the parent process can exit\n daemon.unref();\n\n log(`Migration lock acquired (pid=${daemon.pid})`);\n}\n\n// ─── unlock-migrations ────────────────────────────────────────────────────────\n\nfunction unlockMigrations(): void {\n if (!existsSync(LOCK_FILE)) {\n warn('No lock file found — nothing to release');\n return;\n }\n\n const pid = Number(readFileSync(LOCK_FILE, 'utf8').trim());\n\n try {\n process.kill(pid, 'SIGTERM');\n } catch {\n warn(`Daemon pid=${pid} not found (may have already exited)`);\n }\n\n unlinkSync(LOCK_FILE);\n log('Migration lock released');\n}\n\n// ─── Entry point ──────────────────────────────────────────────────────────────\n\nif (process.argv.includes('--daemon')) {\n const daemonArgIdx = process.argv.indexOf('--daemon');\n const args = parseArgs(process.argv.slice(daemonArgIdx + 1));\n runDaemon(args).catch((err: Error) => {\n fatal(`Lock daemon failed: ${err.message}`);\n process.exit(1);\n });\n} else {\n const [,, command, ...rest] = process.argv;\n const args = parseArgs(rest);\n\n switch (command) {\n case 'lock-migrations':\n lockMigrations(args).catch((err: Error) => {\n fatal(err.message);\n process.exit(1);\n });\n break;\n\n case 'unlock-migrations':\n unlockMigrations();\n break;\n\n default:\n fatal(`Unknown command: ${command}`);\n process.stderr.write('Usage: sequelize-utils <lock-migrations|unlock-migrations> [--db-host-env VAR] [--db-port-env VAR] [--db-name-env VAR] [--db-username-env VAR] [--db-password-env VAR]\\n');\n process.exit(1);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cli.js","names":["result: Args"],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { fork, spawn } from 'node:child_process';\nimport { existsSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';\nimport pg from 'pg';\n\n// Auto-load .env from the current working directory (same behaviour as dotenv).\n// Only sets variables that are not already present in process.env.\ntry {\n const lines = readFileSync('.env', 'utf8').split('\\n');\n for (const line of lines) {\n const match = /^([^#=\\s][^=]*)=(.*)$/.exec(line);\n if (match) {\n const key = match[1].trim();\n const value = match[2].trim().replace(/^[\"']|[\"']$/g, '');\n if (!(key in process.env)) {\n process.env[key] = value;\n }\n }\n }\n} catch {\n // no .env file — that's fine\n}\n\nconst LOCK_FILE = '/tmp/__sequelize_migration_lock.pid';\nconst DEFAULT_LOCK_KEY = 1_234_567_890;\nconst DEFAULT_LOCK_TIMEOUT_MS = 60_000;\n\nconst log = (msg: string) => process.stdout.write(`[sequelize-utils] ${msg}\\n`);\nconst warn = (msg: string) => process.stderr.write(`[sequelize-utils] ${msg}\\n`);\nconst fatal = (msg: string) => process.stderr.write(`[sequelize-utils] ${msg}\\n`);\n\n// ─── Arg parsing ──────────────────────────────────────────────────────────────\n\ntype Args = Record<string, string>;\n\nfunction parseArgs(argv: string[]): Args {\n const result: Args = {};\n for (let i = 0; i < argv.length; i++) {\n if (argv[i].startsWith('--') && i + 1 < argv.length && !argv[i + 1].startsWith('--')) {\n result[argv[i].slice(2)] = argv[i + 1];\n i++;\n }\n }\n return result;\n}\n\n// Resolves the value of an env var whose name may be overridden by a CLI arg.\n// e.g. --db-name-env MY_SERVICE_DB_NAME → process.env['MY_SERVICE_DB_NAME']\nfunction env(args: Args, argName: string, defaultEnvVar: string): string | undefined {\n return process.env[args[argName] ?? defaultEnvVar];\n}\n\n// ─── Daemon ───────────────────────────────────────────────────────────────────\n// Spawned as a detached subprocess by `lock-migrations`.\n// Holds a PostgreSQL session-level advisory lock for as long as it lives.\n// When killed by `unlock-migrations`, the connection closes and pg auto-releases the lock.\n\nasync function runDaemon(args: Args): Promise<void> {\n const lockKey = Number(env(args, 'lock-key-env', 'MIGRATION_LOCK_KEY')) || DEFAULT_LOCK_KEY;\n\n const client = new pg.Client({\n host: env(args, 'db-host-env', 'DB_HOST') ?? 'localhost',\n port: Number(env(args, 'db-port-env', 'DB_PORT')) || 5432,\n database: env(args, 'db-name-env', 'DB_NAME'),\n user: env(args, 'db-username-env', 'DB_USERNAME'),\n password: env(args, 'db-password-env', 'DB_PASSWORD'),\n });\n\n await client.connect();\n\n // Blocking — waits until no other pod holds the lock\n await client.query(`SELECT pg_advisory_lock(${lockKey})`);\n\n // Signal parent that the lock is held\n process.send?.('locked');\n\n const release = () => {\n void client.query(`SELECT pg_advisory_unlock(${lockKey})`)\n .then(() => client.end())\n .finally(() => process.exit(0));\n };\n\n process.once('SIGTERM', release);\n process.once('SIGINT', release);\n}\n\n// ─── lock-migrations ──────────────────────────────────────────────────────────\n\nasync function lockMigrations(args: Args): Promise<void> {\n const lockTimeoutMs = Number(env(args, 'lock-timeout-env', 'MIGRATION_LOCK_TIMEOUT_MS')) || DEFAULT_LOCK_TIMEOUT_MS;\n\n // Forward all --*-env args to the daemon so it resolves the same env vars.\n const forwardedArgs = Object.entries(args).flatMap(([k, v]) => [`--${k}`, v]);\n\n const daemon = fork(process.argv[1], ['--daemon', ...forwardedArgs], {\n stdio: ['ignore', 'inherit', 'inherit', 'ipc'],\n env: process.env,\n execArgv: process.execArgv,\n });\n\n await new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(() => {\n daemon.kill();\n reject(new Error(`Timed out waiting for migration lock after ${lockTimeoutMs}ms`));\n }, lockTimeoutMs);\n\n daemon.once('message', (msg) => {\n clearTimeout(timeout);\n if (msg === 'locked') {\n resolve();\n } else {\n daemon.kill();\n reject(new Error(`Lock daemon error: ${JSON.stringify(msg)}`));\n }\n });\n\n daemon.once('error', (err) => {\n clearTimeout(timeout);\n reject(err);\n });\n });\n\n writeFileSync(LOCK_FILE, String(daemon.pid));\n daemon.disconnect(); // close IPC channel so the parent process can exit\n daemon.unref();\n\n log(`Migration lock acquired (pid=${daemon.pid})`);\n}\n\n// ─── unlock-migrations ────────────────────────────────────────────────────────\n\nfunction unlockMigrations(): void {\n if (!existsSync(LOCK_FILE)) {\n warn('No lock file found — nothing to release');\n return;\n }\n\n const pid = Number(readFileSync(LOCK_FILE, 'utf8').trim());\n\n try {\n process.kill(pid, 'SIGTERM');\n } catch {\n warn(`Daemon pid=${pid} not found (may have already exited)`);\n }\n\n unlinkSync(LOCK_FILE);\n log('Migration lock released');\n}\n\n// ─── run-migrations ───────────────────────────────────────────────────────────\n// Preferred over the separate lock/unlock commands — always releases the lock\n// even if the migration crashes.\n\nasync function runMigrations(args: Args, migrationCmd: string[]): Promise<void> {\n if (migrationCmd.length === 0) {\n fatal('run-migrations requires a command after --');\n fatal('Usage: sequelize-utils run-migrations [--*-env flags] -- <command>');\n process.exit(1);\n }\n\n await lockMigrations(args);\n\n const [cmd, ...cmdArgs] = migrationCmd;\n let exitCode = 0;\n\n try {\n exitCode = await new Promise<number>((resolve) => {\n const child = spawn(cmd, cmdArgs, { stdio: 'inherit', shell: false });\n child.once('exit', (code) => resolve(code ?? 1));\n child.once('error', (err) => {\n fatal(`Migration command error: ${err.message}`);\n resolve(1);\n });\n });\n } finally {\n unlockMigrations();\n }\n\n if (exitCode !== 0) {\n process.exit(exitCode);\n }\n}\n\n// ─── Entry point ──────────────────────────────────────────────────────────────\n\nif (process.argv.includes('--daemon')) {\n const daemonArgIdx = process.argv.indexOf('--daemon');\n const args = parseArgs(process.argv.slice(daemonArgIdx + 1));\n runDaemon(args).catch((err: Error) => {\n fatal(`Lock daemon failed: ${err.message}`);\n process.exit(1);\n });\n} else {\n const [,, command, ...rest] = process.argv;\n\n switch (command) {\n case 'lock-migrations':\n lockMigrations(parseArgs(rest)).catch((err: Error) => {\n fatal(err.message);\n process.exit(1);\n });\n break;\n\n case 'unlock-migrations':\n unlockMigrations();\n break;\n\n case 'run-migrations': {\n const sepIdx = rest.indexOf('--');\n const flagArgs = sepIdx === -1 ? rest : rest.slice(0, sepIdx);\n const migrationCmd = sepIdx === -1 ? [] : rest.slice(sepIdx + 1);\n runMigrations(parseArgs(flagArgs), migrationCmd).catch((err: Error) => {\n fatal(err.message);\n process.exit(1);\n });\n break;\n }\n\n default:\n fatal(`Unknown command: ${command}`);\n process.stderr.write('Usage: sequelize-utils <run-migrations|lock-migrations|unlock-migrations> [--*-env flags] [-- <command>]\\n');\n process.exit(1);\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@autofleet/sequelize-utils",
|
|
3
|
-
"version": "6.2.0-alpha.
|
|
3
|
+
"version": "6.2.0-alpha.3",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -55,8 +55,8 @@
|
|
|
55
55
|
"pg": "^8.16.3",
|
|
56
56
|
"sequelize": "^6.37.7",
|
|
57
57
|
"ts-node": "^10.9.2",
|
|
58
|
-
"@autofleet/
|
|
59
|
-
"@autofleet/
|
|
58
|
+
"@autofleet/network": "^1.11.2",
|
|
59
|
+
"@autofleet/logger": "^4.2.51"
|
|
60
60
|
},
|
|
61
61
|
"scripts": {
|
|
62
62
|
"start": "ts-node src/index.ts",
|