velocious 1.0.530 → 1.0.532

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 CHANGED
@@ -2013,7 +2013,7 @@ New jobs default to `executionMode: "pooled"`: a worker runs them in warm, reusa
2013
2013
 
2014
2014
  `maxConcurrentForkedJobs` (default: `4`) caps how many out-of-process `executionMode: "forked"` or `executionMode: "spawned"` jobs one worker may keep in flight. Forked jobs use `child_process.fork()` with an attached IPC channel. After the main process acknowledges their durable status report, forked and spawned one-shot runners exit without waiting for graceful Beacon/database teardown; the OS closes their process-owned resources. A missing or rejected status acknowledgement makes the runner exit as failed instead of reporting clean success. Spawned jobs use the legacy `background-jobs-runner` CLI process via `child_process.spawn()` and are only for callers that intentionally want that spawned behavior.
2015
2015
 
2016
- `jobTimeoutMs` (or `VELOCIOUS_BACKGROUND_JOBS_JOB_TIMEOUT_MS`, milliseconds; default: disabled) is a wall-clock backstop for a single `"forked"` runner. A forked job still running after the timeout is terminated (`SIGTERM`, then `SIGKILL` after the reaping grace) and reported `failed`, so a genuinely-hung runner can't pin a worker — and its whole-app boot and DB connections — indefinitely (notably a retired-release worker draining after a deploy). It's a coarse safety net, not per-job tuning: it applies to every forked runner, so set it well above the longest legitimate forked job. Omit it, or set `null`/`<= 0`, to disable. `"inline"` jobs are not covered — they share the worker's process and can't be killed without killing the worker. See [docs/background-jobs.md](docs/background-jobs.md#forked-job-timeout-hung-runner-backstop).
2016
+ `jobTimeoutMs` (or `VELOCIOUS_BACKGROUND_JOBS_JOB_TIMEOUT_MS`, milliseconds; default: disabled) is a wall-clock backstop for `"forked"` and `"pooled"` jobs. A job still running after the timeout is terminated (`SIGTERM`, then `SIGKILL` after the reaping grace) and reported `failed`, so a genuinely-hung job can't pin a worker's capacity — and its whole-app boot and DB connections — indefinitely (notably a retired-release worker draining after a deploy). For a **pooled** job the whole child running it is killed, so its concurrent in-flight siblings on that child are also reported `failed` and requeued — a hung JS job can't be cancelled any other way — before a replacement child is spawned. It's a coarse safety net, not per-job tuning: it applies to every forked and pooled job, so set it well above the longest legitimate job. Omit it, or set `null`/`<= 0`, to disable. `"inline"` jobs are not covered — they share the worker's process and can't be killed without killing the worker. See [docs/background-jobs.md](docs/background-jobs.md#job-timeout-hung-runner-backstop).
2017
2017
 
2018
2018
  ### Dispatch strategy
2019
2019
 
@@ -2327,4 +2327,6 @@ npx velocious db:tenants:migrate projectTenant --parallel 20
2327
2327
 
2328
2328
  At runtime, the apartment-style `Tenant` façade (`velocious/build/src/tenants/tenant.js`) is the single entry point: `Tenant.with(tenant, callback)` / `Tenant.current()` to switch into and read a tenant context, `Tenant.each({identifier, callback, parallel?, filter?})` to run a callback within every provider-listed tenant, and `Tenant.drop({identifier, tenant})` (plus the `db:tenants:drop` CLI command) to drop a tenant's database through the provider's `dropDatabase` hook. `Tenant.with` and `Tenant.each` run their callbacks inside `ensureConnections`, so switching into a tenant establishes its database connections (global + tenant) and passes them to the callback — the tenant is immediately queryable without the caller wiring up connections (already-open connections are reused, so nesting does not double-connect). `Tenant.with` is generic over its callback's return type, so a value returned from inside the tenant context comes back to the caller with its type preserved (no cast needed). `Tenant.aggregateAcross({identifier, aggregates, keyColumns, subquery, tenants?, filter?})` runs one aggregate over the same table across many tenant databases and returns the merged result — grouping tenants by server and using a single cross-database `UNION ALL` where the driver supports two-part `` `database`.`table` `` references (MySQL/MariaDB) or one query per tenant otherwise (PostgreSQL/SQLite/MSSQL).
2329
2329
 
2330
+ `SchemaCloner` adds a missing auto-increment column and its separate source unique index in one schema alteration, including on MySQL/MariaDB where an auto-increment column must be keyed when it is created.
2331
+
2330
2332
  See [docs/tenant-databases.md](docs/tenant-databases.md) for the full configuration and migration pattern.
@@ -72,7 +72,7 @@ export default class BackgroundJobsWorker {
72
72
  * @param {number} [args.pooledRunnerMaxLifetimeMs] - Override the per-runner recycle lifetime.
73
73
  * @param {number} [args.forkedChildSigkillGraceMs] - Override the grace period between SIGTERM and SIGKILL when reaping lingering process runners on stop.
74
74
  * @param {number} [args.heartbeatIntervalMs] - Override the liveness heartbeat interval (default 15000ms).
75
- * @param {number} [args.jobTimeoutMs] - Override the forked-job wall-clock timeout from `configuration.getBackgroundJobsConfig()`. `0` disables it.
75
+ * @param {number} [args.jobTimeoutMs] - Override the wall-clock timeout for forked and pooled jobs from `configuration.getBackgroundJobsConfig()`. `0` disables it.
76
76
  */
77
77
  constructor({configuration, host, port, maxConcurrentForkedJobs, maxConcurrentInlineJobs, pooledRunnerCount, pooledRunnerConcurrency, pooledRunnerMaxJobs, pooledRunnerMaxRssBytes, pooledRunnerMaxLifetimeMs, forkedChildSigkillGraceMs, heartbeatIntervalMs, jobTimeoutMs} = {}) {
78
78
  /**
@@ -129,7 +129,7 @@ export default class BackgroundJobsWorker {
129
129
  ? forkedChildSigkillGraceMs
130
130
  : FORKED_CHILD_SIGKILL_GRACE_MS
131
131
  /**
132
- * Constructor override for the forked-job wall-clock timeout. When unset the
132
+ * Constructor override for the forked and pooled wall-clock job timeout. When unset the
133
133
  * timeout is read from `configuration.getBackgroundJobsConfig().jobTimeoutMs`
134
134
  * at fork time (default: disabled).
135
135
  * @type {number | undefined}
@@ -186,7 +186,7 @@ export default class BackgroundJobsWorker {
186
186
  this.inflightPooledJobs = new Set()
187
187
  /** @type {Set<import("node:child_process").ChildProcess>} */
188
188
  this.pooledChildren = new Set()
189
- /** @type {Map<import("node:child_process").ChildProcess, {createdAtMs: number, jobsRun: number, inflight: Map<string, {payload: import("./types.js").BackgroundJobPayload & {id: string}, resolve?: (value: void) => void}>, retiring: boolean, settling?: boolean}>} */
189
+ /** @type {Map<import("node:child_process").ChildProcess, {createdAtMs: number, jobsRun: number, inflight: Map<string, {payload: import("./types.js").BackgroundJobPayload & {id: string}, resolve?: (value: void) => void, timeoutTimer?: ReturnType<typeof setTimeout> | null}>, retiring: boolean, settling?: boolean, timeoutSigkillTimer?: ReturnType<typeof setTimeout> | null}>} */
190
190
  this.pooledChildStates = new Map()
191
191
  }
192
192
 
@@ -659,7 +659,9 @@ export default class BackgroundJobsWorker {
659
659
  if (!state) throw new Error("Pooled runner state missing")
660
660
 
661
661
  return new Promise((resolve) => {
662
- state.inflight.set(payload.id, {payload, resolve})
662
+ const timeoutTimer = this._armPooledJobTimeout({child, jobId: payload.id})
663
+
664
+ state.inflight.set(payload.id, {payload, resolve, timeoutTimer})
663
665
  try {
664
666
  child.send({type: "job", payload})
665
667
  } catch (error) {
@@ -668,6 +670,58 @@ export default class BackgroundJobsWorker {
668
670
  })
669
671
  }
670
672
 
673
+ /**
674
+ * Arms a per-job wall-clock backstop for a pooled job. A pooled child hosts many
675
+ * concurrent jobs, so a single genuinely-hung job would otherwise pin its
676
+ * runner's concurrency slot forever — the lifetime recycle only retires a child
677
+ * once its in-flight set drains, which a hung job never does. On overrun the
678
+ * whole child is terminated so the hung job (and its siblings) requeue. Returns
679
+ * the timer, or null when no timeout is configured.
680
+ * @param {object} args - Options.
681
+ * @param {import("node:child_process").ChildProcess} args.child - Pooled child.
682
+ * @param {string} args.jobId - Job id whose overrun is guarded.
683
+ * @returns {ReturnType<typeof setTimeout> | null} - The armed timer, or null.
684
+ */
685
+ _armPooledJobTimeout({child, jobId}) {
686
+ const timeoutMs = this._resolveJobTimeoutMs()
687
+
688
+ if (!(typeof timeoutMs === "number" && timeoutMs > 0)) return null
689
+
690
+ return setTimeout(() => this._onPooledJobTimeout({child, jobId}), timeoutMs)
691
+ }
692
+
693
+ /**
694
+ * Fired when a pooled job overruns its timeout. Terminates the child running it
695
+ * (SIGTERM, then SIGKILL after the grace) — a hung JS job cannot be cancelled
696
+ * any other way. The non-clean exit flows through `_handlePooledChildFailure`,
697
+ * which reports every in-flight job on the child failed (so they requeue) and
698
+ * drops it from tracking; capacity is refilled on the next dispatch.
699
+ * @param {object} args - Options.
700
+ * @param {import("node:child_process").ChildProcess} args.child - Pooled child.
701
+ * @param {string} args.jobId - Job id that overran.
702
+ * @returns {void}
703
+ */
704
+ _onPooledJobTimeout({child, jobId}) {
705
+ const state = this.pooledChildStates.get(child)
706
+
707
+ // Already settling/gone, or the job finished in the race with this timer.
708
+ if (!state || state.settling || !state.inflight.has(jobId)) return
709
+
710
+ try {
711
+ child.kill("SIGTERM")
712
+ } catch {
713
+ // Child already exited; nothing to do.
714
+ }
715
+
716
+ state.timeoutSigkillTimer = setTimeout(() => {
717
+ try {
718
+ child.kill("SIGKILL")
719
+ } catch {
720
+ // Child already exited; nothing to do.
721
+ }
722
+ }, this.forkedChildSigkillGraceMs)
723
+ }
724
+
671
725
  /**
672
726
  * Creates a reusable pooled child.
673
727
  * @returns {import("node:child_process").ChildProcess} - New pooled child.
@@ -705,6 +759,7 @@ export default class BackgroundJobsWorker {
705
759
  const entry = state.inflight.get(record.jobId)
706
760
  if (!entry) return
707
761
 
762
+ if (entry.timeoutTimer) clearTimeout(entry.timeoutTimer)
708
763
  state.inflight.delete(record.jobId)
709
764
  state.jobsRun += 1
710
765
  const resolve = entry.resolve
@@ -789,7 +844,15 @@ export default class BackgroundJobsWorker {
789
844
  async _handlePooledChildFailure({child, error}) {
790
845
  const state = this.pooledChildStates.get(child)
791
846
  if (state?.settling) return
792
- if (state) state.settling = true
847
+ if (state) {
848
+ state.settling = true
849
+ // Cancel this child's pending timers before its in-flight set is reported —
850
+ // the SIGKILL grace from a timeout kill, and every armed per-job backstop.
851
+ if (state.timeoutSigkillTimer) clearTimeout(state.timeoutSigkillTimer)
852
+ for (const inflightEntry of state.inflight.values()) {
853
+ if (inflightEntry.timeoutTimer) clearTimeout(inflightEntry.timeoutTimer)
854
+ }
855
+ }
793
856
  this.pooledChildren.delete(child)
794
857
  this.inflightProcessChildren.delete(child)
795
858
 
@@ -908,7 +971,7 @@ export default class BackgroundJobsWorker {
908
971
  * @returns {ForkedJobTimeoutState} - Timeout state.
909
972
  */
910
973
  _armForkedJobTimeout({child}) {
911
- const timeoutMs = this._resolveForkedJobTimeoutMs()
974
+ const timeoutMs = this._resolveJobTimeoutMs()
912
975
  /** @type {ForkedJobTimeoutState} */
913
976
  const state = {timedOut: false, timeoutMs, timer: null, sigkillTimer: null}
914
977
 
@@ -920,12 +983,12 @@ export default class BackgroundJobsWorker {
920
983
  }
921
984
 
922
985
  /**
923
- * Resolves the effective forked-job timeout in ms, or null when disabled. The
986
+ * Resolves the effective wall-clock job timeout in ms (shared by forked and pooled jobs), or null when disabled. The
924
987
  * constructor override wins; otherwise the value comes from the background-jobs
925
988
  * configuration. A non-positive value disables the backstop.
926
989
  * @returns {number | null} - Timeout in ms, or null when disabled.
927
990
  */
928
- _resolveForkedJobTimeoutMs() {
991
+ _resolveJobTimeoutMs() {
929
992
  const raw = typeof this.jobTimeoutMsOverride === "number"
930
993
  ? this.jobTimeoutMsOverride
931
994
  : (this.configuration ? this.configuration.getBackgroundJobsConfig().jobTimeoutMs : null)
@@ -1,6 +1,48 @@
1
1
  // @ts-check
2
2
 
3
3
  import AlterTableBase from "../../../query/alter-table-base.js"
4
+ import TableColumn from "../../../table-data/table-column.js"
4
5
 
5
6
  export default class VelociousDatabaseConnectionDriversMysqlSqlAlterTable extends AlterTableBase {
7
+ /**
8
+ * Builds MySQL ALTER TABLE statements, adding indexes atomically with columns.
9
+ * @returns {Promise<string[]>} - Resolves with SQL statements.
10
+ */
11
+ async toSQLs() {
12
+ const sqls = await super.toSQLs()
13
+ const indexes = this.tableData.getIndexes()
14
+
15
+ if (indexes.length === 0) return sqls
16
+ if (sqls.length !== 1) throw new Error("Expected one MySQL ALTER TABLE statement when adding indexes")
17
+
18
+ const options = this.getOptions()
19
+ let sql = sqls[0]
20
+
21
+ for (const index of indexes) {
22
+ sql += ", ADD"
23
+
24
+ if (index.getUnique()) sql += " UNIQUE"
25
+
26
+ sql += " INDEX"
27
+
28
+ const indexName = index.getName()
29
+
30
+ if (typeof indexName === "string") {
31
+ sql += ` ${options.quoteIndexName(indexName)}`
32
+ }
33
+
34
+ sql += " ("
35
+ sql += index
36
+ .getColumns()
37
+ .map((column) => {
38
+ const columnName = column instanceof TableColumn ? column.getName() : column
39
+
40
+ return options.quoteColumnName(columnName)
41
+ })
42
+ .join(", ")
43
+ sql += ")"
44
+ }
45
+
46
+ return [sql]
47
+ }
6
48
  }
@@ -58,8 +58,8 @@ export default class VelociousDatabaseQueryPreloaderBelongsTo {
58
58
 
59
59
  /**
60
60
  * Foreign key values.
61
- * @type {Array<number | string>} */
62
- const foreignKeyValues = []
61
+ * @type {Set<number | string>} */
62
+ const foreignKeyValues = new Set()
63
63
 
64
64
  for (const model of modelsToLoad) {
65
65
  const foreignKeyValue = /** @type {string | number | null | undefined} */ (model.readColumn(foreignKey))
@@ -69,7 +69,7 @@ export default class VelociousDatabaseQueryPreloaderBelongsTo {
69
69
  // throws on non-string primary-key columns.
70
70
  if (foreignKeyValue === null || foreignKeyValue === undefined) continue
71
71
 
72
- if (!foreignKeyValues.includes(foreignKeyValue)) foreignKeyValues.push(foreignKeyValue)
72
+ foreignKeyValues.add(foreignKeyValue)
73
73
  }
74
74
 
75
75
  /**
@@ -83,7 +83,7 @@ export default class VelociousDatabaseQueryPreloaderBelongsTo {
83
83
  let targetModels = []
84
84
 
85
85
  // Only query when at least one model has a non-null foreign key.
86
- if (foreignKeyValues.length > 0) {
86
+ if (foreignKeyValues.size > 0) {
87
87
  await ensureModelClassInitialized(targetModelClass, this.relationship.getConfiguration())
88
88
 
89
89
  /**
@@ -91,7 +91,7 @@ export default class VelociousDatabaseQueryPreloaderBelongsTo {
91
91
  * @type {Record<string, string | number | Array<string | number>>} */
92
92
  const whereArgs = {}
93
93
 
94
- whereArgs[primaryKey] = foreignKeyValues
94
+ whereArgs[primaryKey] = [...foreignKeyValues]
95
95
 
96
96
  // Load target models to be preloaded on the given models
97
97
  let query = targetModelClass.where(whereArgs)
@@ -178,15 +178,15 @@ export default class VelociousDatabaseQueryPreloaderBelongsTo {
178
178
 
179
179
  /**
180
180
  * Foreign key values by type.
181
- * @type {Record<string, Array<number | string>>} */
181
+ * @type {Record<string, Set<number | string>>} */
182
182
  const foreignKeyValuesByType = {}
183
183
 
184
184
  for (const meta of modelMeta) {
185
185
  if (meta.targetType === undefined || meta.targetType === null) continue
186
186
  if (meta.foreignKeyValue === undefined || meta.foreignKeyValue === null) continue
187
187
 
188
- if (!foreignKeyValuesByType[meta.targetType]) foreignKeyValuesByType[meta.targetType] = []
189
- if (!foreignKeyValuesByType[meta.targetType].includes(meta.foreignKeyValue)) foreignKeyValuesByType[meta.targetType].push(meta.foreignKeyValue)
188
+ if (!foreignKeyValuesByType[meta.targetType]) foreignKeyValuesByType[meta.targetType] = new Set()
189
+ foreignKeyValuesByType[meta.targetType].add(meta.foreignKeyValue)
190
190
  }
191
191
 
192
192
  /**
@@ -209,7 +209,7 @@ export default class VelociousDatabaseQueryPreloaderBelongsTo {
209
209
  * @type {Record<string, string | number | Array<string | number>>} */
210
210
  const whereArgs = {}
211
211
 
212
- whereArgs[primaryKey] = foreignKeyValuesByType[targetType]
212
+ whereArgs[primaryKey] = [...foreignKeyValuesByType[targetType]]
213
213
 
214
214
  let query = targetModelClass.where(whereArgs)
215
215
 
@@ -130,8 +130,8 @@ export default class VelociousDatabaseQueryPreloaderHasMany {
130
130
 
131
131
  /**
132
132
  * Models primary key values.
133
- * @type {Array<number | string>} */
134
- const modelsPrimaryKeyValues = []
133
+ * @type {Set<number | string>} */
134
+ const modelsPrimaryKeyValues = new Set()
135
135
 
136
136
  /**
137
137
  * Models by primary key value.
@@ -148,7 +148,7 @@ export default class VelociousDatabaseQueryPreloaderHasMany {
148
148
 
149
149
  preloadCollections[primaryKeyValue] = []
150
150
 
151
- if (!modelsPrimaryKeyValues.includes(primaryKeyValue)) modelsPrimaryKeyValues.push(primaryKeyValue)
151
+ modelsPrimaryKeyValues.add(primaryKeyValue)
152
152
  if (!(primaryKeyValue in modelsByPrimaryKeyValue)) modelsByPrimaryKeyValue[primaryKeyValue] = []
153
153
 
154
154
  modelsByPrimaryKeyValue[primaryKeyValue].push(model)
@@ -156,7 +156,7 @@ export default class VelociousDatabaseQueryPreloaderHasMany {
156
156
 
157
157
  // Step 1: Query the through table to build parent→target ID mapping
158
158
  const throughModels = await throughModelClass
159
- .where({[throughForeignKey]: modelsPrimaryKeyValues})
159
+ .where({[throughForeignKey]: [...modelsPrimaryKeyValues]})
160
160
  .toArray()
161
161
 
162
162
  /**
@@ -260,8 +260,8 @@ export default class VelociousDatabaseQueryPreloaderHasMany {
260
260
 
261
261
  /**
262
262
  * Models primary key values.
263
- * @type {Array<number | string>} */
264
- const modelsPrimaryKeyValues = []
263
+ * @type {Set<number | string>} */
264
+ const modelsPrimaryKeyValues = new Set()
265
265
 
266
266
  /**
267
267
  * Models by primary key value.
@@ -278,7 +278,7 @@ export default class VelociousDatabaseQueryPreloaderHasMany {
278
278
 
279
279
  preloadCollections[primaryKeyValue] = []
280
280
 
281
- if (!modelsPrimaryKeyValues.includes(primaryKeyValue)) modelsPrimaryKeyValues.push(primaryKeyValue)
281
+ modelsPrimaryKeyValues.add(primaryKeyValue)
282
282
  if (!(primaryKeyValue in modelsByPrimaryKeyValue)) modelsByPrimaryKeyValue[primaryKeyValue] = []
283
283
 
284
284
  modelsByPrimaryKeyValue[primaryKeyValue].push(model)
@@ -289,7 +289,7 @@ export default class VelociousDatabaseQueryPreloaderHasMany {
289
289
  * @type {Record<string, string | number | Array<string | number>>} */
290
290
  const whereArgs = {}
291
291
 
292
- whereArgs[foreignKey] = modelsPrimaryKeyValues
292
+ whereArgs[foreignKey] = [...modelsPrimaryKeyValues]
293
293
 
294
294
  if (this.relationship.getPolymorphic()) {
295
295
  const typeColumn = this.relationship.getPolymorphicTypeColumn()
@@ -23,8 +23,8 @@ export default class VelociousDatabaseQueryPreloaderHasOne {
23
23
  async run() {
24
24
  /**
25
25
  * Models primary key values.
26
- * @type {Array<number | string>} */
27
- const modelsPrimaryKeyValues = []
26
+ * @type {Set<number | string>} */
27
+ const modelsPrimaryKeyValues = new Set()
28
28
 
29
29
  /**
30
30
  * Models by primary key value.
@@ -63,20 +63,20 @@ export default class VelociousDatabaseQueryPreloaderHasOne {
63
63
 
64
64
  preloadCollections[primaryKeyValue] = undefined
65
65
 
66
- if (!modelsPrimaryKeyValues.includes(primaryKeyValue)) modelsPrimaryKeyValues.push(primaryKeyValue)
66
+ modelsPrimaryKeyValues.add(primaryKeyValue)
67
67
  if (!(primaryKeyValue in modelsByPrimaryKeyValue)) modelsByPrimaryKeyValue[primaryKeyValue] = []
68
68
 
69
69
  modelsByPrimaryKeyValue[primaryKeyValue].push(model)
70
70
  }
71
71
 
72
- if (modelsPrimaryKeyValues.length == 0) return satisfiedTargets
72
+ if (modelsPrimaryKeyValues.size == 0) return satisfiedTargets
73
73
 
74
74
  /**
75
75
  * Where args.
76
76
  * @type {Record<string, string | number | Array<string | number>>} */
77
77
  const whereArgs = {}
78
78
 
79
- whereArgs[foreignKey] = modelsPrimaryKeyValues
79
+ whereArgs[foreignKey] = [...modelsPrimaryKeyValues]
80
80
 
81
81
  if (this.relationship.getPolymorphic()) {
82
82
  const typeColumn = this.relationship.getPolymorphicTypeColumn()
@@ -143,6 +143,37 @@ export default class SchemaCloner {
143
143
  tableData.addColumn(sourceColumn.getName(), this.columnArgsFromSourceColumn(sourceColumn, {isNewColumn: false}))
144
144
  }
145
145
 
146
+ if (this.targetDb.getType() === "mysql") {
147
+ const missingAutoIncrementColumnNames = new Set(
148
+ missingColumns
149
+ .filter((sourceColumn) => sourceColumn.getAutoIncrement())
150
+ .map((sourceColumn) => sourceColumn.getName())
151
+ )
152
+ const targetIndexesByName = new Map(
153
+ (await targetTable.getIndexes()).map((targetIndex) => [targetIndex.getName(), targetIndex])
154
+ )
155
+
156
+ for (const sourceIndex of await sourceTable.getIndexes()) {
157
+ if (
158
+ !sourceIndex.isPrimaryKey() &&
159
+ sourceIndex.isUnique() &&
160
+ missingAutoIncrementColumnNames.has(sourceIndex.getColumnNames()[0])
161
+ ) {
162
+ const targetIndex = targetIndexesByName.get(sourceIndex.getName())
163
+
164
+ if (targetIndex) {
165
+ if (this.indexesMatch(sourceIndex, targetIndex)) continue
166
+
167
+ this.assertSafeIndexReplacement({sourceIndex, tableName, targetIndex})
168
+ await this.dropTargetIndex({tableName, targetIndex})
169
+ targetIndexesByName.delete(targetIndex.getName())
170
+ }
171
+
172
+ tableData.addIndex(this.tableDataIndexFromSourceIndex(sourceIndex))
173
+ }
174
+ }
175
+ }
176
+
146
177
  for (const alterSql of await this.targetDb.alterTableSQLs(tableData)) {
147
178
  await this.targetDb.query(alterSql)
148
179
  }
@@ -186,15 +217,7 @@ export default class SchemaCloner {
186
217
 
187
218
  if (targetIndex) {
188
219
  if (!this.indexesMatch(sourceIndex, targetIndex)) {
189
- // Replacing a non-unique index with a unique one is unsafe because
190
- // the target may have duplicate values that will reject the new
191
- // unique constraint, and the old index was already dropped by this
192
- // point. The opposite direction (unique → non-unique) is always
193
- // safe — non-unique indexes never fail on duplicate values.
194
- if (sourceIndex.isUnique() && !targetIndex.isUnique()) {
195
- throw new Error(`Schema clone index drift for ${tableName}.${sourceIndex.getName()}: cannot safely replace a non-unique index with a unique one.`)
196
- }
197
-
220
+ this.assertSafeIndexReplacement({sourceIndex, tableName, targetIndex})
198
221
  await this.dropTargetIndex({tableName, targetIndex})
199
222
  targetIndexesByName.delete(targetIndex.getName())
200
223
  targetIndexSignatures.delete(this.indexSignature(targetIndex))
@@ -241,6 +264,20 @@ export default class SchemaCloner {
241
264
  }
242
265
  }
243
266
 
267
+ /**
268
+ * Refuses index replacements that could fail after the existing index is dropped.
269
+ * @param {{sourceIndex: import("../drivers/base-columns-index.js").default, tableName: string, targetIndex: import("../drivers/base-columns-index.js").default}} args - Source and target index definitions.
270
+ * @returns {void}
271
+ */
272
+ assertSafeIndexReplacement({sourceIndex, tableName, targetIndex}) {
273
+ // Replacing a non-unique index with a unique one is unsafe because the
274
+ // target may have duplicate values that will reject the new constraint.
275
+ // The opposite direction is safe because non-unique indexes accept them.
276
+ if (sourceIndex.isUnique() && !targetIndex.isUnique()) {
277
+ throw new Error(`Schema clone index drift for ${tableName}.${sourceIndex.getName()}: cannot safely replace a non-unique index with a unique one.`)
278
+ }
279
+ }
280
+
244
281
  /**
245
282
  * Baselines the target ledger so the cloned schema is recorded as already-applied.
246
283
  * @returns {Promise<string[]>} The versions newly recorded on the target.
@@ -22,7 +22,7 @@ export default class BackgroundJobsWorker {
22
22
  * @param {number} [args.pooledRunnerMaxLifetimeMs] - Override the per-runner recycle lifetime.
23
23
  * @param {number} [args.forkedChildSigkillGraceMs] - Override the grace period between SIGTERM and SIGKILL when reaping lingering process runners on stop.
24
24
  * @param {number} [args.heartbeatIntervalMs] - Override the liveness heartbeat interval (default 15000ms).
25
- * @param {number} [args.jobTimeoutMs] - Override the forked-job wall-clock timeout from `configuration.getBackgroundJobsConfig()`. `0` disables it.
25
+ * @param {number} [args.jobTimeoutMs] - Override the wall-clock timeout for forked and pooled jobs from `configuration.getBackgroundJobsConfig()`. `0` disables it.
26
26
  */
27
27
  constructor({ configuration, host, port, maxConcurrentForkedJobs, maxConcurrentInlineJobs, pooledRunnerCount, pooledRunnerConcurrency, pooledRunnerMaxJobs, pooledRunnerMaxRssBytes, pooledRunnerMaxLifetimeMs, forkedChildSigkillGraceMs, heartbeatIntervalMs, jobTimeoutMs }?: {
28
28
  configuration?: import("../configuration.js").default | undefined;
@@ -87,7 +87,7 @@ export default class BackgroundJobsWorker {
87
87
  */
88
88
  forkedChildSigkillGraceMs: number;
89
89
  /**
90
- * Constructor override for the forked-job wall-clock timeout. When unset the
90
+ * Constructor override for the forked and pooled wall-clock job timeout. When unset the
91
91
  * timeout is read from `configuration.getBackgroundJobsConfig().jobTimeoutMs`
92
92
  * at fork time (default: disabled).
93
93
  * @type {number | undefined}
@@ -142,7 +142,7 @@ export default class BackgroundJobsWorker {
142
142
  inflightPooledJobs: Set<Promise<void>>;
143
143
  /** @type {Set<import("node:child_process").ChildProcess>} */
144
144
  pooledChildren: Set<import("node:child_process").ChildProcess>;
145
- /** @type {Map<import("node:child_process").ChildProcess, {createdAtMs: number, jobsRun: number, inflight: Map<string, {payload: import("./types.js").BackgroundJobPayload & {id: string}, resolve?: (value: void) => void}>, retiring: boolean, settling?: boolean}>} */
145
+ /** @type {Map<import("node:child_process").ChildProcess, {createdAtMs: number, jobsRun: number, inflight: Map<string, {payload: import("./types.js").BackgroundJobPayload & {id: string}, resolve?: (value: void) => void, timeoutTimer?: ReturnType<typeof setTimeout> | null}>, retiring: boolean, settling?: boolean, timeoutSigkillTimer?: ReturnType<typeof setTimeout> | null}>} */
146
146
  pooledChildStates: Map<import("node:child_process").ChildProcess, {
147
147
  createdAtMs: number;
148
148
  jobsRun: number;
@@ -151,9 +151,11 @@ export default class BackgroundJobsWorker {
151
151
  id: string;
152
152
  };
153
153
  resolve?: (value: void) => void;
154
+ timeoutTimer?: ReturnType<typeof setTimeout> | null;
154
155
  }>;
155
156
  retiring: boolean;
156
157
  settling?: boolean;
158
+ timeoutSigkillTimer?: ReturnType<typeof setTimeout> | null;
157
159
  }>;
158
160
  /**
159
161
  * Runs start.
@@ -295,6 +297,37 @@ export default class BackgroundJobsWorker {
295
297
  _runPooledJob(payload: import("./types.js").BackgroundJobPayload & {
296
298
  id: string;
297
299
  }): Promise<void>;
300
+ /**
301
+ * Arms a per-job wall-clock backstop for a pooled job. A pooled child hosts many
302
+ * concurrent jobs, so a single genuinely-hung job would otherwise pin its
303
+ * runner's concurrency slot forever — the lifetime recycle only retires a child
304
+ * once its in-flight set drains, which a hung job never does. On overrun the
305
+ * whole child is terminated so the hung job (and its siblings) requeue. Returns
306
+ * the timer, or null when no timeout is configured.
307
+ * @param {object} args - Options.
308
+ * @param {import("node:child_process").ChildProcess} args.child - Pooled child.
309
+ * @param {string} args.jobId - Job id whose overrun is guarded.
310
+ * @returns {ReturnType<typeof setTimeout> | null} - The armed timer, or null.
311
+ */
312
+ _armPooledJobTimeout({ child, jobId }: {
313
+ child: import("node:child_process").ChildProcess;
314
+ jobId: string;
315
+ }): ReturnType<typeof setTimeout> | null;
316
+ /**
317
+ * Fired when a pooled job overruns its timeout. Terminates the child running it
318
+ * (SIGTERM, then SIGKILL after the grace) — a hung JS job cannot be cancelled
319
+ * any other way. The non-clean exit flows through `_handlePooledChildFailure`,
320
+ * which reports every in-flight job on the child failed (so they requeue) and
321
+ * drops it from tracking; capacity is refilled on the next dispatch.
322
+ * @param {object} args - Options.
323
+ * @param {import("node:child_process").ChildProcess} args.child - Pooled child.
324
+ * @param {string} args.jobId - Job id that overran.
325
+ * @returns {void}
326
+ */
327
+ _onPooledJobTimeout({ child, jobId }: {
328
+ child: import("node:child_process").ChildProcess;
329
+ jobId: string;
330
+ }): void;
298
331
  /**
299
332
  * Creates a reusable pooled child.
300
333
  * @returns {import("node:child_process").ChildProcess} - New pooled child.
@@ -397,12 +430,12 @@ export default class BackgroundJobsWorker {
397
430
  child: import("node:child_process").ChildProcess;
398
431
  }): ForkedJobTimeoutState;
399
432
  /**
400
- * Resolves the effective forked-job timeout in ms, or null when disabled. The
433
+ * Resolves the effective wall-clock job timeout in ms (shared by forked and pooled jobs), or null when disabled. The
401
434
  * constructor override wins; otherwise the value comes from the background-jobs
402
435
  * configuration. A non-positive value disables the backstop.
403
436
  * @returns {number | null} - Timeout in ms, or null when disabled.
404
437
  */
405
- _resolveForkedJobTimeoutMs(): number | null;
438
+ _resolveJobTimeoutMs(): number | null;
406
439
  /**
407
440
  * Fired when a forked runner overruns its timeout. Sends SIGTERM for a clean
408
441
  * shutdown, then SIGKILL after the grace for a runner that ignores it. The
@@ -1 +1 @@
1
- {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../../src/background-jobs/worker.js"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../../src/background-jobs/worker.js"],"names":[],"mappings":"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"}