velocious 1.0.528 → 1.0.530
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 +12 -1
- package/build/background-jobs/forked-runner-child.js +2 -1
- package/build/background-jobs/job-runner.js +19 -5
- package/build/background-jobs/json-socket.js +2 -0
- package/build/background-jobs/main.js +47 -5
- package/build/background-jobs/pooled-runner-child.js +115 -0
- package/build/background-jobs/runner-process-title.js +6 -0
- package/build/background-jobs/scheduler.js +28 -5
- package/build/background-jobs/store.js +79 -15
- package/build/background-jobs/types.js +5 -5
- package/build/background-jobs/worker.js +272 -5
- package/build/configuration-types.js +5 -0
- package/build/configuration.js +53 -4
- package/build/src/background-jobs/forked-runner-child.js +3 -2
- package/build/src/background-jobs/job-runner.d.ts +10 -1
- package/build/src/background-jobs/job-runner.d.ts.map +1 -1
- package/build/src/background-jobs/job-runner.js +21 -6
- package/build/src/background-jobs/json-socket.d.ts +2 -0
- package/build/src/background-jobs/json-socket.d.ts.map +1 -1
- package/build/src/background-jobs/json-socket.js +3 -1
- package/build/src/background-jobs/main.d.ts +16 -0
- package/build/src/background-jobs/main.d.ts.map +1 -1
- package/build/src/background-jobs/main.js +46 -5
- package/build/src/background-jobs/pooled-runner-child.d.ts +2 -0
- package/build/src/background-jobs/pooled-runner-child.d.ts.map +1 -0
- package/build/src/background-jobs/pooled-runner-child.js +108 -0
- package/build/src/background-jobs/runner-process-title.d.ts +3 -0
- package/build/src/background-jobs/runner-process-title.d.ts.map +1 -0
- package/build/src/background-jobs/runner-process-title.js +6 -0
- package/build/src/background-jobs/scheduler.d.ts +16 -2
- package/build/src/background-jobs/scheduler.d.ts.map +1 -1
- package/build/src/background-jobs/scheduler.js +27 -6
- package/build/src/background-jobs/store.d.ts +24 -0
- package/build/src/background-jobs/store.d.ts.map +1 -1
- package/build/src/background-jobs/store.js +81 -15
- package/build/src/background-jobs/types.d.ts +10 -8
- package/build/src/background-jobs/types.d.ts.map +1 -1
- package/build/src/background-jobs/types.js +6 -6
- package/build/src/background-jobs/worker.d.ts +116 -1
- package/build/src/background-jobs/worker.d.ts.map +1 -1
- package/build/src/background-jobs/worker.js +276 -6
- package/build/src/configuration-types.d.ts +25 -0
- package/build/src/configuration-types.d.ts.map +1 -1
- package/build/src/configuration-types.js +6 -1
- package/build/src/configuration.d.ts +6 -0
- package/build/src/configuration.d.ts.map +1 -1
- package/build/src/configuration.js +54 -4
- package/build/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/background-jobs/forked-runner-child.js +2 -1
- package/src/background-jobs/job-runner.js +19 -5
- package/src/background-jobs/json-socket.js +2 -0
- package/src/background-jobs/main.js +47 -5
- package/src/background-jobs/pooled-runner-child.js +115 -0
- package/src/background-jobs/runner-process-title.js +6 -0
- package/src/background-jobs/scheduler.js +28 -5
- package/src/background-jobs/store.js +79 -15
- package/src/background-jobs/types.js +5 -5
- package/src/background-jobs/worker.js +272 -5
- package/src/configuration-types.js +5 -0
- package/src/configuration.js +53 -4
|
@@ -19,6 +19,7 @@ const FORKED_CHILD_SIGKILL_GRACE_MS = 5000
|
|
|
19
19
|
*/
|
|
20
20
|
const MAX_FORKED_JOB_TIMEOUT_MS = 2_147_483_647
|
|
21
21
|
const FORKED_RUNNER_ENTRY_PATH = fileURLToPath(new URL("./forked-runner-child.js", import.meta.url))
|
|
22
|
+
const POOLED_RUNNER_ENTRY_PATH = fileURLToPath(new URL("./pooled-runner-child.js", import.meta.url))
|
|
22
23
|
/** How often the worker sends a liveness heartbeat to the main. */
|
|
23
24
|
const HEARTBEAT_INTERVAL_MS = 15000
|
|
24
25
|
/** TCP keepalive so a half-open connection to the main surfaces as a close. */
|
|
@@ -26,7 +27,25 @@ const SOCKET_KEEPALIVE_MS = 10000
|
|
|
26
27
|
/**
|
|
27
28
|
* Execution modes.
|
|
28
29
|
* @type {import("./types.js").BackgroundJobExecutionMode[]} */
|
|
29
|
-
const EXECUTION_MODES = ["inline", "forked", "spawned"]
|
|
30
|
+
const EXECUTION_MODES = ["inline", "forked", "pooled", "spawned"]
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Normalizes a candidate pooled-runner count or job limit.
|
|
34
|
+
* @param {number | undefined} value - Candidate positive integer.
|
|
35
|
+
* @returns {number | undefined} - Normalized value.
|
|
36
|
+
*/
|
|
37
|
+
function positiveInteger(value) {
|
|
38
|
+
return typeof value === "number" && Number.isInteger(value) && value > 0 ? value : undefined
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Normalizes a candidate pooled-runner resource limit.
|
|
43
|
+
* @param {number | undefined} value - Candidate positive number.
|
|
44
|
+
* @returns {number | undefined} - Normalized value.
|
|
45
|
+
*/
|
|
46
|
+
function positiveNumber(value) {
|
|
47
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : undefined
|
|
48
|
+
}
|
|
30
49
|
|
|
31
50
|
/**
|
|
32
51
|
* Per-forked-child timeout bookkeeping.
|
|
@@ -46,11 +65,16 @@ export default class BackgroundJobsWorker {
|
|
|
46
65
|
* @param {number} [args.port] - Port.
|
|
47
66
|
* @param {number} [args.maxConcurrentForkedJobs] - Override the process runner concurrency cap from `configuration.getBackgroundJobsConfig()`.
|
|
48
67
|
* @param {number} [args.maxConcurrentInlineJobs] - Override the inline-job concurrency cap from `configuration.getBackgroundJobsConfig()`.
|
|
68
|
+
* @param {number} [args.pooledRunnerCount] - Override the pooled runner count.
|
|
69
|
+
* @param {number} [args.pooledRunnerConcurrency] - Override the per-runner concurrency.
|
|
70
|
+
* @param {number} [args.pooledRunnerMaxJobs] - Override the per-runner recycle job count.
|
|
71
|
+
* @param {number} [args.pooledRunnerMaxRssBytes] - Override the per-runner recycle RSS limit.
|
|
72
|
+
* @param {number} [args.pooledRunnerMaxLifetimeMs] - Override the per-runner recycle lifetime.
|
|
49
73
|
* @param {number} [args.forkedChildSigkillGraceMs] - Override the grace period between SIGTERM and SIGKILL when reaping lingering process runners on stop.
|
|
50
74
|
* @param {number} [args.heartbeatIntervalMs] - Override the liveness heartbeat interval (default 15000ms).
|
|
51
75
|
* @param {number} [args.jobTimeoutMs] - Override the forked-job wall-clock timeout from `configuration.getBackgroundJobsConfig()`. `0` disables it.
|
|
52
76
|
*/
|
|
53
|
-
constructor({configuration, host, port, maxConcurrentForkedJobs, maxConcurrentInlineJobs, forkedChildSigkillGraceMs, heartbeatIntervalMs, jobTimeoutMs} = {}) {
|
|
77
|
+
constructor({configuration, host, port, maxConcurrentForkedJobs, maxConcurrentInlineJobs, pooledRunnerCount, pooledRunnerConcurrency, pooledRunnerMaxJobs, pooledRunnerMaxRssBytes, pooledRunnerMaxLifetimeMs, forkedChildSigkillGraceMs, heartbeatIntervalMs, jobTimeoutMs} = {}) {
|
|
54
78
|
/**
|
|
55
79
|
* Narrows the runtime value to the documented type.
|
|
56
80
|
* @type {Promise<import("../configuration.js").default>} */
|
|
@@ -86,6 +110,16 @@ export default class BackgroundJobsWorker {
|
|
|
86
110
|
* Narrows the runtime value to the documented type.
|
|
87
111
|
* @type {number} */
|
|
88
112
|
this.maxConcurrentForkedJobs = this.maxConcurrentForkedJobsOverride || 4
|
|
113
|
+
this.pooledRunnerCountOverride = positiveInteger(pooledRunnerCount)
|
|
114
|
+
this.pooledRunnerConcurrencyOverride = positiveInteger(pooledRunnerConcurrency)
|
|
115
|
+
this.pooledRunnerMaxJobsOverride = positiveInteger(pooledRunnerMaxJobs)
|
|
116
|
+
this.pooledRunnerMaxRssBytesOverride = positiveNumber(pooledRunnerMaxRssBytes)
|
|
117
|
+
this.pooledRunnerMaxLifetimeMsOverride = positiveNumber(pooledRunnerMaxLifetimeMs)
|
|
118
|
+
this.pooledRunnerCount = this.pooledRunnerCountOverride || 4
|
|
119
|
+
this.pooledRunnerConcurrency = this.pooledRunnerConcurrencyOverride || 1
|
|
120
|
+
this.pooledRunnerMaxJobs = this.pooledRunnerMaxJobsOverride || 100
|
|
121
|
+
this.pooledRunnerMaxRssBytes = this.pooledRunnerMaxRssBytesOverride || 512 * 1024 * 1024
|
|
122
|
+
this.pooledRunnerMaxLifetimeMs = this.pooledRunnerMaxLifetimeMsOverride || 60 * 60 * 1000
|
|
89
123
|
/**
|
|
90
124
|
* Grace period between SIGTERM and SIGKILL when reaping process runners that
|
|
91
125
|
* outlast a bounded shutdown drain.
|
|
@@ -148,6 +182,12 @@ export default class BackgroundJobsWorker {
|
|
|
148
182
|
* @type {Set<import("node:child_process").ChildProcess>}
|
|
149
183
|
*/
|
|
150
184
|
this.inflightProcessChildren = new Set()
|
|
185
|
+
/** @type {Set<Promise<void>>} */
|
|
186
|
+
this.inflightPooledJobs = new Set()
|
|
187
|
+
/** @type {Set<import("node:child_process").ChildProcess>} */
|
|
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}>} */
|
|
190
|
+
this.pooledChildStates = new Map()
|
|
151
191
|
}
|
|
152
192
|
|
|
153
193
|
/**
|
|
@@ -171,6 +211,12 @@ export default class BackgroundJobsWorker {
|
|
|
171
211
|
|
|
172
212
|
this.maxConcurrentForkedJobs = config.maxConcurrentForkedJobs || this.maxConcurrentForkedJobs
|
|
173
213
|
}
|
|
214
|
+
const poolConfig = this.configuration.getBackgroundJobsConfig()
|
|
215
|
+
if (typeof this.pooledRunnerCountOverride !== "number") this.pooledRunnerCount = poolConfig.pooledRunnerCount
|
|
216
|
+
if (typeof this.pooledRunnerConcurrencyOverride !== "number") this.pooledRunnerConcurrency = poolConfig.pooledRunnerConcurrency
|
|
217
|
+
if (typeof this.pooledRunnerMaxJobsOverride !== "number") this.pooledRunnerMaxJobs = poolConfig.pooledRunnerMaxJobs
|
|
218
|
+
if (typeof this.pooledRunnerMaxRssBytesOverride !== "number") this.pooledRunnerMaxRssBytes = poolConfig.pooledRunnerMaxRssBytes
|
|
219
|
+
if (typeof this.pooledRunnerMaxLifetimeMsOverride !== "number") this.pooledRunnerMaxLifetimeMs = poolConfig.pooledRunnerMaxLifetimeMs
|
|
174
220
|
|
|
175
221
|
this.statusReporter = new BackgroundJobsStatusReporter({
|
|
176
222
|
configuration: this.configuration,
|
|
@@ -211,6 +257,7 @@ export default class BackgroundJobsWorker {
|
|
|
211
257
|
}
|
|
212
258
|
|
|
213
259
|
await this._drainInflight(this.inflightInlineJobs, timeoutMs)
|
|
260
|
+
await this._drainInflight(this.inflightPooledJobs, timeoutMs)
|
|
214
261
|
await this._drainInflight(this.inflightProcessJobs, timeoutMs)
|
|
215
262
|
await this._terminateProcessChildren()
|
|
216
263
|
// Give in-flight result reports (now decoupled from job slots) a bounded
|
|
@@ -311,7 +358,7 @@ export default class BackgroundJobsWorker {
|
|
|
311
358
|
})
|
|
312
359
|
|
|
313
360
|
socket.on("connect", () => {
|
|
314
|
-
jsonSocket.send({type: "hello", role: "worker", supportsHandoffIdReporting: true, supportsHeartbeat: true, workerId: this.workerId})
|
|
361
|
+
jsonSocket.send({type: "hello", role: "worker", supportsHandoffIdReporting: true, supportsHeartbeat: true, supportsPooled: true, workerId: this.workerId})
|
|
315
362
|
this._sendReadyIfRunning()
|
|
316
363
|
this._startHeartbeat()
|
|
317
364
|
})
|
|
@@ -364,6 +411,11 @@ export default class BackgroundJobsWorker {
|
|
|
364
411
|
|
|
365
412
|
const executionMode = this._executionModeForPayload(identifiedPayload)
|
|
366
413
|
|
|
414
|
+
if (executionMode === "pooled") {
|
|
415
|
+
this._trackPooledJob(this._runPooledJob(identifiedPayload))
|
|
416
|
+
return
|
|
417
|
+
}
|
|
418
|
+
|
|
367
419
|
if (executionMode !== "inline") {
|
|
368
420
|
this._trackProcessJob(this._startProcessJob({executionMode, payload: identifiedPayload}))
|
|
369
421
|
return
|
|
@@ -433,7 +485,9 @@ export default class BackgroundJobsWorker {
|
|
|
433
485
|
|
|
434
486
|
if (executionMode) return this._normalizeExecutionMode(executionMode)
|
|
435
487
|
|
|
436
|
-
|
|
488
|
+
if (options.forked === false) return "inline"
|
|
489
|
+
if (options.forked === true) return "forked"
|
|
490
|
+
return "pooled"
|
|
437
491
|
}
|
|
438
492
|
|
|
439
493
|
/**
|
|
@@ -532,17 +586,230 @@ export default class BackgroundJobsWorker {
|
|
|
532
586
|
_readyMessage() {
|
|
533
587
|
const acceptsProcessJob = this.inflightProcessJobs.size < this.maxConcurrentForkedJobs
|
|
534
588
|
const acceptsInline = this.inflightInlineJobs.size < this.maxConcurrentInlineJobs
|
|
589
|
+
const acceptsPooled = this._availablePooledSlots() > 0
|
|
535
590
|
|
|
536
|
-
if (!acceptsProcessJob && !acceptsInline) return null
|
|
591
|
+
if (!acceptsProcessJob && !acceptsInline && !acceptsPooled) return null
|
|
537
592
|
|
|
538
593
|
return {
|
|
539
594
|
type: "ready",
|
|
540
595
|
acceptsForked: acceptsProcessJob,
|
|
541
596
|
acceptsInline,
|
|
597
|
+
acceptsPooled,
|
|
542
598
|
acceptsSpawned: acceptsProcessJob
|
|
543
599
|
}
|
|
544
600
|
}
|
|
545
601
|
|
|
602
|
+
/**
|
|
603
|
+
* Tracks a pooled job and re-advertises capacity.
|
|
604
|
+
* @param {Promise<void>} pooledJob - Pooled job promise.
|
|
605
|
+
* @returns {void}
|
|
606
|
+
*/
|
|
607
|
+
_trackPooledJob(pooledJob) {
|
|
608
|
+
/** @type {Promise<void>} */
|
|
609
|
+
let inflight
|
|
610
|
+
inflight = pooledJob.finally(() => {
|
|
611
|
+
this.inflightPooledJobs.delete(inflight)
|
|
612
|
+
if (!this.shouldStop) this._sendReadyIfRunning()
|
|
613
|
+
})
|
|
614
|
+
this.inflightPooledJobs.add(inflight)
|
|
615
|
+
this._sendReadyIfRunning()
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
/**
|
|
619
|
+
* Free pooled slots across the pool: open slots in non-retiring children plus
|
|
620
|
+
* the slots we could add by spawning more children up to `pooledRunnerCount`.
|
|
621
|
+
* Retiring children (draining before replacement) never contribute capacity.
|
|
622
|
+
* @returns {number} - Number of pooled jobs the worker can accept right now.
|
|
623
|
+
*/
|
|
624
|
+
_availablePooledSlots() {
|
|
625
|
+
let openInExisting = 0
|
|
626
|
+
let nonRetiringChildren = 0
|
|
627
|
+
|
|
628
|
+
for (const child of this.pooledChildren) {
|
|
629
|
+
const state = this.pooledChildStates.get(child)
|
|
630
|
+
if (!state || state.retiring) continue
|
|
631
|
+
nonRetiringChildren += 1
|
|
632
|
+
openInExisting += this.pooledRunnerConcurrency - state.inflight.size
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
const spawnableChildren = Math.max(0, this.pooledRunnerCount - nonRetiringChildren)
|
|
636
|
+
|
|
637
|
+
return openInExisting + spawnableChildren * this.pooledRunnerConcurrency
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
/**
|
|
641
|
+
* Runs a payload on a pooled child with a free concurrency slot, spawning a
|
|
642
|
+
* new child when every non-retiring child is full and the pool is below
|
|
643
|
+
* `pooledRunnerCount`. Each child runs up to `pooledRunnerConcurrency` jobs at
|
|
644
|
+
* once on its own event loop.
|
|
645
|
+
* @param {import("./types.js").BackgroundJobPayload & {id: string}} payload - Job payload.
|
|
646
|
+
* @returns {Promise<void>} - Resolves after the durable report.
|
|
647
|
+
*/
|
|
648
|
+
_runPooledJob(payload) {
|
|
649
|
+
let child
|
|
650
|
+
for (const candidate of this.pooledChildren) {
|
|
651
|
+
const state = this.pooledChildStates.get(candidate)
|
|
652
|
+
if (state && !state.retiring && state.inflight.size < this.pooledRunnerConcurrency) {
|
|
653
|
+
child = candidate
|
|
654
|
+
break
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
if (!child) child = this._createPooledChild()
|
|
658
|
+
const state = this.pooledChildStates.get(child)
|
|
659
|
+
if (!state) throw new Error("Pooled runner state missing")
|
|
660
|
+
|
|
661
|
+
return new Promise((resolve) => {
|
|
662
|
+
state.inflight.set(payload.id, {payload, resolve})
|
|
663
|
+
try {
|
|
664
|
+
child.send({type: "job", payload})
|
|
665
|
+
} catch (error) {
|
|
666
|
+
void this._handlePooledChildFailure({child, error})
|
|
667
|
+
}
|
|
668
|
+
})
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
/**
|
|
672
|
+
* Creates a reusable pooled child.
|
|
673
|
+
* @returns {import("node:child_process").ChildProcess} - New pooled child.
|
|
674
|
+
*/
|
|
675
|
+
_createPooledChild() {
|
|
676
|
+
const configuration = this.configuration
|
|
677
|
+
if (!configuration) throw new Error("Background jobs worker configuration not initialized")
|
|
678
|
+
const config = configuration.getBackgroundJobsConfig()
|
|
679
|
+
const child = fork(POOLED_RUNNER_ENTRY_PATH, [], {
|
|
680
|
+
cwd: configuration.getDirectory(), execArgv: [], stdio: ["ignore", "ignore", "ignore", "ipc"],
|
|
681
|
+
env: Object.assign({}, process.env, {VELOCIOUS_ENV: configuration.getEnvironment(), VELOCIOUS_BACKGROUND_JOBS_HOST: config.host, VELOCIOUS_BACKGROUND_JOBS_PORT: `${config.port}`})
|
|
682
|
+
})
|
|
683
|
+
this.pooledChildren.add(child)
|
|
684
|
+
this.inflightProcessChildren.add(child)
|
|
685
|
+
this.pooledChildStates.set(child, {createdAtMs: Date.now(), jobsRun: 0, inflight: new Map(), retiring: false})
|
|
686
|
+
child.on("message", (message) => this._handlePooledChildMessage({child, message}))
|
|
687
|
+
child.once("exit", (code, signal) => this._handlePooledChildFailure({child, error: new Error(`Pooled background job runner exited: code=${code} signal=${signal || "none"}`)}))
|
|
688
|
+
child.once("error", (error) => this._handlePooledChildFailure({child, error}))
|
|
689
|
+
return child
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
/**
|
|
693
|
+
* Handles a pooled child's per-job durable-report acknowledgement. A child
|
|
694
|
+
* runs jobs concurrently and reports one `job-outcome` per job id.
|
|
695
|
+
* @param {object} args - Message details.
|
|
696
|
+
* @param {import("node:child_process").ChildProcess} args.child - Pooled child.
|
|
697
|
+
* @param {?} args.message - IPC message.
|
|
698
|
+
* @returns {void}
|
|
699
|
+
*/
|
|
700
|
+
_handlePooledChildMessage({child, message}) {
|
|
701
|
+
if (!message || typeof message !== "object") return
|
|
702
|
+
const record = /** @type {{type?: ?, jobId?: ?, acknowledged?: ?, rssBytes?: ?, error?: ?}} */ (message)
|
|
703
|
+
const state = this.pooledChildStates.get(child)
|
|
704
|
+
if (record.type !== "job-outcome" || !state || state.settling || typeof record.jobId !== "string") return
|
|
705
|
+
const entry = state.inflight.get(record.jobId)
|
|
706
|
+
if (!entry) return
|
|
707
|
+
|
|
708
|
+
state.inflight.delete(record.jobId)
|
|
709
|
+
state.jobsRun += 1
|
|
710
|
+
const resolve = entry.resolve
|
|
711
|
+
|
|
712
|
+
if (record.acknowledged === true) {
|
|
713
|
+
if (resolve) resolve(undefined)
|
|
714
|
+
} else {
|
|
715
|
+
// The child stayed alive but could not confirm this one job's terminal
|
|
716
|
+
// report; reclaim just this job — its concurrent siblings are unaffected.
|
|
717
|
+
void this._reportJobResult({
|
|
718
|
+
jobId: entry.payload.id,
|
|
719
|
+
status: "failed",
|
|
720
|
+
error: new Error(typeof record.error === "string" ? record.error : "Pooled runner terminal report was not acknowledged"),
|
|
721
|
+
handoffId: entry.payload.handoffId,
|
|
722
|
+
handedOffAtMs: entry.payload.handedOffAtMs,
|
|
723
|
+
workerId: entry.payload.workerId || this.workerId
|
|
724
|
+
}).finally(() => { if (resolve) resolve(undefined) })
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
const rssBytes = typeof record.rssBytes === "number" ? record.rssBytes : Number.POSITIVE_INFINITY
|
|
728
|
+
const runnerAgeMs = Date.now() - state.createdAtMs
|
|
729
|
+
if (!state.retiring && (state.jobsRun >= this.pooledRunnerMaxJobs || rssBytes >= this.pooledRunnerMaxRssBytes || runnerAgeMs >= this.pooledRunnerMaxLifetimeMs || this.shouldStop)) {
|
|
730
|
+
this._beginRetirePooledChild(child)
|
|
731
|
+
}
|
|
732
|
+
this._terminateIfDrained(child)
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
/**
|
|
736
|
+
* Marks a pooled child for retirement and eagerly spawns a single replacement
|
|
737
|
+
* (1-for-1) so its capacity is restored immediately without waiting for it to
|
|
738
|
+
* finish draining. The retiring child stops receiving new jobs and is
|
|
739
|
+
* terminated only once its in-flight set drains, so a long-running job (e.g. a
|
|
740
|
+
* build) is never cut off.
|
|
741
|
+
* @param {import("node:child_process").ChildProcess} child - Child to retire.
|
|
742
|
+
* @returns {void}
|
|
743
|
+
*/
|
|
744
|
+
_beginRetirePooledChild(child) {
|
|
745
|
+
const state = this.pooledChildStates.get(child)
|
|
746
|
+
if (!state || state.retiring) return
|
|
747
|
+
|
|
748
|
+
state.retiring = true
|
|
749
|
+
// Best-effort pre-warm: skip when stopping (no new work) or before the
|
|
750
|
+
// worker is initialized (no configuration to fork a child from).
|
|
751
|
+
if (!this.shouldStop && this.configuration) this._createPooledChild()
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
/**
|
|
755
|
+
* Terminates a retiring pooled child once it has no in-flight jobs left.
|
|
756
|
+
* @param {import("node:child_process").ChildProcess} child - Child to check.
|
|
757
|
+
* @returns {void}
|
|
758
|
+
*/
|
|
759
|
+
_terminateIfDrained(child) {
|
|
760
|
+
const state = this.pooledChildStates.get(child)
|
|
761
|
+
if (!state || !state.retiring || state.inflight.size > 0) return
|
|
762
|
+
|
|
763
|
+
this._retirePooledChild(child)
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
/**
|
|
767
|
+
* Retires a drained pooled child (removes it from tracking, then SIGTERMs it).
|
|
768
|
+
* @param {import("node:child_process").ChildProcess} child - Child process to retire.
|
|
769
|
+
* @returns {void}
|
|
770
|
+
*/
|
|
771
|
+
_retirePooledChild(child) {
|
|
772
|
+
this.pooledChildren.delete(child)
|
|
773
|
+
this.pooledChildStates.delete(child)
|
|
774
|
+
this.inflightProcessChildren.delete(child)
|
|
775
|
+
child.kill("SIGTERM")
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
/**
|
|
779
|
+
* Removes an exited/unhealthy pooled child and reports every job that was
|
|
780
|
+
* in-flight on it as failed — a process-level crash's blast radius is the
|
|
781
|
+
* child's whole in-flight set. Capacity is refilled lazily on the next
|
|
782
|
+
* dispatch (a spawnable slot is still advertised), avoiding a tight respawn
|
|
783
|
+
* loop when a child crashes on startup.
|
|
784
|
+
* @param {object} args - Failure details.
|
|
785
|
+
* @param {import("node:child_process").ChildProcess} args.child - Pooled child.
|
|
786
|
+
* @param {?} args.error - Failure.
|
|
787
|
+
* @returns {Promise<void>}
|
|
788
|
+
*/
|
|
789
|
+
async _handlePooledChildFailure({child, error}) {
|
|
790
|
+
const state = this.pooledChildStates.get(child)
|
|
791
|
+
if (state?.settling) return
|
|
792
|
+
if (state) state.settling = true
|
|
793
|
+
this.pooledChildren.delete(child)
|
|
794
|
+
this.inflightProcessChildren.delete(child)
|
|
795
|
+
|
|
796
|
+
const entries = state ? [...state.inflight.values()] : []
|
|
797
|
+
if (state) state.inflight.clear()
|
|
798
|
+
this.pooledChildStates.delete(child)
|
|
799
|
+
|
|
800
|
+
await Promise.allSettled(entries.map(async (entry) => {
|
|
801
|
+
await this._reportJobResult({
|
|
802
|
+
jobId: entry.payload.id,
|
|
803
|
+
status: "failed",
|
|
804
|
+
error,
|
|
805
|
+
handoffId: entry.payload.handoffId,
|
|
806
|
+
handedOffAtMs: entry.payload.handedOffAtMs,
|
|
807
|
+
workerId: entry.payload.workerId || this.workerId
|
|
808
|
+
})
|
|
809
|
+
if (entry.resolve) entry.resolve(undefined)
|
|
810
|
+
}))
|
|
811
|
+
}
|
|
812
|
+
|
|
546
813
|
/**
|
|
547
814
|
* Runs run job inline.
|
|
548
815
|
* @param {import("./types.js").BackgroundJobPayload} payload - Payload.
|
|
@@ -164,6 +164,11 @@
|
|
|
164
164
|
* allowed to keep in flight. Default: `4`. This is a per-worker safety cap;
|
|
165
165
|
* for workload-shaped limits use per-queue caps (`queues`) instead, which are
|
|
166
166
|
* enforced cluster-wide and are immune to duplicate worker processes.
|
|
167
|
+
* @property {number} [pooledRunnerCount] - Number of warm, reusable child runners owned by each worker. Pooled capacity is separate from inline and forked/spawned capacity. Default: `4`.
|
|
168
|
+
* @property {number} [pooledRunnerConcurrency] - Number of jobs each pooled child runs concurrently on its own event loop. Total per-worker pooled capacity is `pooledRunnerCount × pooledRunnerConcurrency`. `1` (default) keeps each child serial; raise it for I/O-bound jobs so a bounded set of isolated processes handles high concurrency (like the inline lane) without one process per concurrent job. Default: `1`.
|
|
169
|
+
* @property {number} [pooledRunnerMaxJobs] - Number of sequential jobs a pooled child runs before it is replaced, bounding process-level resource accumulation. Default: `100`.
|
|
170
|
+
* @property {number} [pooledRunnerMaxRssBytes] - RSS bytes after an acknowledged job at which a pooled child is replaced. Default: `536870912` (512 MiB).
|
|
171
|
+
* @property {number} [pooledRunnerMaxLifetimeMs] - Age after an acknowledged job at which a pooled child is replaced. Default: `3600000` (one hour).
|
|
167
172
|
* @property {Record<string, {maxConcurrent?: number, priority?: number}>} [queues] - Per-queue
|
|
168
173
|
* concurrency caps and dispatch priorities, Sidekiq-style. A job declares its queue (static
|
|
169
174
|
* `queue` on the job class, or the `queue` enqueue option; defaults to `"default"`), and
|
package/build/configuration.js
CHANGED
|
@@ -192,6 +192,12 @@ export default class VelociousConfiguration {
|
|
|
192
192
|
}
|
|
193
193
|
|
|
194
194
|
this._isInitialized = false
|
|
195
|
+
/**
|
|
196
|
+
* In-progress `initialize()` promise, memoized so concurrent callers await
|
|
197
|
+
* the same bootstrap. Reset to undefined if initialization fails.
|
|
198
|
+
* @type {Promise<void> | undefined}
|
|
199
|
+
*/
|
|
200
|
+
this._initializePromise = undefined
|
|
195
201
|
this.httpServer = httpServer || {}
|
|
196
202
|
/**
|
|
197
203
|
* Stores the http server instance value.
|
|
@@ -1268,12 +1274,22 @@ export default class VelociousConfiguration {
|
|
|
1268
1274
|
const envDatabaseIdentifier = process.env.VELOCIOUS_BACKGROUND_JOBS_DATABASE_IDENTIFIER
|
|
1269
1275
|
const envMaxConcurrentForkedRaw = process.env.VELOCIOUS_BACKGROUND_JOBS_MAX_CONCURRENT_FORKED_JOBS
|
|
1270
1276
|
const envMaxConcurrentRaw = process.env.VELOCIOUS_BACKGROUND_JOBS_MAX_CONCURRENT_INLINE_JOBS
|
|
1277
|
+
const envPooledRunnerCountRaw = process.env.VELOCIOUS_BACKGROUND_JOBS_POOLED_RUNNER_COUNT
|
|
1278
|
+
const envPooledRunnerConcurrencyRaw = process.env.VELOCIOUS_BACKGROUND_JOBS_POOLED_RUNNER_CONCURRENCY
|
|
1279
|
+
const envPooledRunnerMaxJobsRaw = process.env.VELOCIOUS_BACKGROUND_JOBS_POOLED_RUNNER_MAX_JOBS
|
|
1280
|
+
const envPooledRunnerMaxRssBytesRaw = process.env.VELOCIOUS_BACKGROUND_JOBS_POOLED_RUNNER_MAX_RSS_BYTES
|
|
1281
|
+
const envPooledRunnerMaxLifetimeMsRaw = process.env.VELOCIOUS_BACKGROUND_JOBS_POOLED_RUNNER_MAX_LIFETIME_MS
|
|
1271
1282
|
const envDispatchStrategy = process.env.VELOCIOUS_BACKGROUND_JOBS_DISPATCH_STRATEGY
|
|
1272
1283
|
const envPollIntervalRaw = process.env.VELOCIOUS_BACKGROUND_JOBS_POLL_INTERVAL_MS
|
|
1273
1284
|
const envJobTimeoutRaw = process.env.VELOCIOUS_BACKGROUND_JOBS_JOB_TIMEOUT_MS
|
|
1274
1285
|
const envPort = envPortRaw ? Number(envPortRaw) : undefined
|
|
1275
1286
|
const envMaxConcurrentForked = envMaxConcurrentForkedRaw ? Number(envMaxConcurrentForkedRaw) : undefined
|
|
1276
1287
|
const envMaxConcurrent = envMaxConcurrentRaw ? Number(envMaxConcurrentRaw) : undefined
|
|
1288
|
+
const envPooledRunnerCount = envPooledRunnerCountRaw ? Number(envPooledRunnerCountRaw) : undefined
|
|
1289
|
+
const envPooledRunnerConcurrency = envPooledRunnerConcurrencyRaw ? Number(envPooledRunnerConcurrencyRaw) : undefined
|
|
1290
|
+
const envPooledRunnerMaxJobs = envPooledRunnerMaxJobsRaw ? Number(envPooledRunnerMaxJobsRaw) : undefined
|
|
1291
|
+
const envPooledRunnerMaxRssBytes = envPooledRunnerMaxRssBytesRaw ? Number(envPooledRunnerMaxRssBytesRaw) : undefined
|
|
1292
|
+
const envPooledRunnerMaxLifetimeMs = envPooledRunnerMaxLifetimeMsRaw ? Number(envPooledRunnerMaxLifetimeMsRaw) : undefined
|
|
1277
1293
|
const envPollInterval = envPollIntervalRaw ? Number(envPollIntervalRaw) : undefined
|
|
1278
1294
|
const envJobTimeout = envJobTimeoutRaw ? Number(envJobTimeoutRaw) : undefined
|
|
1279
1295
|
const configured = this._backgroundJobs || {}
|
|
@@ -1288,6 +1304,21 @@ export default class VelociousConfiguration {
|
|
|
1288
1304
|
const maxConcurrentForkedJobs = typeof configured.maxConcurrentForkedJobs === "number" && configured.maxConcurrentForkedJobs >= 1
|
|
1289
1305
|
? configured.maxConcurrentForkedJobs
|
|
1290
1306
|
: (typeof envMaxConcurrentForked === "number" && Number.isFinite(envMaxConcurrentForked) && envMaxConcurrentForked >= 1 ? envMaxConcurrentForked : 4)
|
|
1307
|
+
const pooledRunnerCount = typeof configured.pooledRunnerCount === "number" && Number.isFinite(configured.pooledRunnerCount) && Number.isInteger(configured.pooledRunnerCount) && configured.pooledRunnerCount >= 1
|
|
1308
|
+
? configured.pooledRunnerCount
|
|
1309
|
+
: (!("pooledRunnerCount" in configured) && typeof envPooledRunnerCount === "number" && Number.isFinite(envPooledRunnerCount) && Number.isInteger(envPooledRunnerCount) && envPooledRunnerCount >= 1 ? envPooledRunnerCount : 4)
|
|
1310
|
+
const pooledRunnerConcurrency = typeof configured.pooledRunnerConcurrency === "number" && Number.isFinite(configured.pooledRunnerConcurrency) && Number.isInteger(configured.pooledRunnerConcurrency) && configured.pooledRunnerConcurrency >= 1
|
|
1311
|
+
? configured.pooledRunnerConcurrency
|
|
1312
|
+
: (!("pooledRunnerConcurrency" in configured) && typeof envPooledRunnerConcurrency === "number" && Number.isFinite(envPooledRunnerConcurrency) && Number.isInteger(envPooledRunnerConcurrency) && envPooledRunnerConcurrency >= 1 ? envPooledRunnerConcurrency : 1)
|
|
1313
|
+
const pooledRunnerMaxJobs = typeof configured.pooledRunnerMaxJobs === "number" && Number.isFinite(configured.pooledRunnerMaxJobs) && Number.isInteger(configured.pooledRunnerMaxJobs) && configured.pooledRunnerMaxJobs >= 1
|
|
1314
|
+
? configured.pooledRunnerMaxJobs
|
|
1315
|
+
: (!("pooledRunnerMaxJobs" in configured) && typeof envPooledRunnerMaxJobs === "number" && Number.isFinite(envPooledRunnerMaxJobs) && Number.isInteger(envPooledRunnerMaxJobs) && envPooledRunnerMaxJobs >= 1 ? envPooledRunnerMaxJobs : 100)
|
|
1316
|
+
const pooledRunnerMaxRssBytes = typeof configured.pooledRunnerMaxRssBytes === "number" && Number.isFinite(configured.pooledRunnerMaxRssBytes) && configured.pooledRunnerMaxRssBytes >= 1
|
|
1317
|
+
? configured.pooledRunnerMaxRssBytes
|
|
1318
|
+
: (!("pooledRunnerMaxRssBytes" in configured) && typeof envPooledRunnerMaxRssBytes === "number" && Number.isFinite(envPooledRunnerMaxRssBytes) && envPooledRunnerMaxRssBytes >= 1 ? envPooledRunnerMaxRssBytes : 512 * 1024 * 1024)
|
|
1319
|
+
const pooledRunnerMaxLifetimeMs = typeof configured.pooledRunnerMaxLifetimeMs === "number" && Number.isFinite(configured.pooledRunnerMaxLifetimeMs) && configured.pooledRunnerMaxLifetimeMs >= 1
|
|
1320
|
+
? configured.pooledRunnerMaxLifetimeMs
|
|
1321
|
+
: (!("pooledRunnerMaxLifetimeMs" in configured) && typeof envPooledRunnerMaxLifetimeMs === "number" && Number.isFinite(envPooledRunnerMaxLifetimeMs) && envPooledRunnerMaxLifetimeMs >= 1 ? envPooledRunnerMaxLifetimeMs : 60 * 60 * 1000)
|
|
1291
1322
|
const dispatchStrategyRaw = configured.dispatchStrategy || envDispatchStrategy
|
|
1292
1323
|
const dispatchStrategy = dispatchStrategyRaw === "polling" ? "polling" : "beacon"
|
|
1293
1324
|
const pollIntervalMs = typeof configured.pollIntervalMs === "number" && configured.pollIntervalMs >= 1
|
|
@@ -1316,7 +1347,7 @@ export default class VelociousConfiguration {
|
|
|
1316
1347
|
: 60 * 60 * 1000
|
|
1317
1348
|
}
|
|
1318
1349
|
|
|
1319
|
-
return {host, port, databaseIdentifier, maxConcurrentForkedJobs, maxConcurrentInlineJobs, dispatchStrategy, pollIntervalMs, queues, jobTimeoutMs, retention}
|
|
1350
|
+
return {host, port, databaseIdentifier, maxConcurrentForkedJobs, maxConcurrentInlineJobs, pooledRunnerCount, pooledRunnerConcurrency, pooledRunnerMaxJobs, pooledRunnerMaxRssBytes, pooledRunnerMaxLifetimeMs, dispatchStrategy, pollIntervalMs, queues, jobTimeoutMs, retention}
|
|
1320
1351
|
}
|
|
1321
1352
|
|
|
1322
1353
|
/**
|
|
@@ -1914,9 +1945,16 @@ export default class VelociousConfiguration {
|
|
|
1914
1945
|
* @returns {Promise<void>} - Resolves when complete.
|
|
1915
1946
|
*/
|
|
1916
1947
|
async initialize({type} = {type: "undefined"}) {
|
|
1917
|
-
if (
|
|
1918
|
-
|
|
1919
|
-
|
|
1948
|
+
if (this._isInitialized) return
|
|
1949
|
+
// Memoize the in-progress initialization so concurrent callers await the same
|
|
1950
|
+
// bootstrap instead of racing. `_isInitialized` was previously set to `true`
|
|
1951
|
+
// up front, so a second caller (e.g. a pooled runner with
|
|
1952
|
+
// `pooledRunnerConcurrency > 1` starting several jobs on a cold child) could
|
|
1953
|
+
// skip initialization and load models / perform a job while the first call
|
|
1954
|
+
// was still awaiting model discovery and initializers. Mirrors connectBeacon.
|
|
1955
|
+
if (this._initializePromise) return await this._initializePromise
|
|
1956
|
+
|
|
1957
|
+
this._initializePromise = (async () => {
|
|
1920
1958
|
await this.initializeModels({type})
|
|
1921
1959
|
await this.getEnvironmentHandler().autoDiscoverResources(this)
|
|
1922
1960
|
this._mergeDiscoveredAbilityResources()
|
|
@@ -1937,6 +1975,17 @@ export default class VelociousConfiguration {
|
|
|
1937
1975
|
}
|
|
1938
1976
|
}
|
|
1939
1977
|
}
|
|
1978
|
+
|
|
1979
|
+
this._isInitialized = true
|
|
1980
|
+
})()
|
|
1981
|
+
|
|
1982
|
+
try {
|
|
1983
|
+
await this._initializePromise
|
|
1984
|
+
} catch (error) {
|
|
1985
|
+
// Let a later call retry a failed initialization instead of every future
|
|
1986
|
+
// caller awaiting the same cached rejection.
|
|
1987
|
+
this._initializePromise = undefined
|
|
1988
|
+
throw error
|
|
1940
1989
|
}
|
|
1941
1990
|
}
|
|
1942
1991
|
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
import runJobPayload from "./job-runner.js";
|
|
3
|
+
import setRunnerProcessTitle from "./runner-process-title.js";
|
|
3
4
|
// Name the process so `ps`/`top`/`htop` can identify forked job runners at a
|
|
4
5
|
// glance instead of a wall of generic "node" entries. Updated to the specific
|
|
5
6
|
// job name once one arrives (see runJobMessage), so operators can see exactly
|
|
6
7
|
// which jobs are running, how many of each, and which are eating resources.
|
|
7
|
-
|
|
8
|
+
setRunnerProcessTitle();
|
|
8
9
|
let finishing = false;
|
|
9
10
|
/**
|
|
10
11
|
* Runs is job message.
|
|
@@ -79,4 +80,4 @@ process.once("disconnect", () => {
|
|
|
79
80
|
process.once("message", (message) => {
|
|
80
81
|
void handleJobMessage(message);
|
|
81
82
|
});
|
|
82
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
83
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9ya2VkLXJ1bm5lci1jaGlsZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9iYWNrZ3JvdW5kLWpvYnMvZm9ya2VkLXJ1bm5lci1jaGlsZC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxZQUFZO0FBRVosT0FBTyxhQUFhLE1BQU0saUJBQWlCLENBQUE7QUFDM0MsT0FBTyxxQkFBcUIsTUFBTSwyQkFBMkIsQ0FBQTtBQUU3RCw2RUFBNkU7QUFDN0UsOEVBQThFO0FBQzlFLDhFQUE4RTtBQUM5RSw0RUFBNEU7QUFDNUUscUJBQXFCLEVBQUUsQ0FBQTtBQUV2QixJQUFJLFNBQVMsR0FBRyxLQUFLLENBQUE7QUFFckI7Ozs7R0FJRztBQUNILFNBQVMsWUFBWSxDQUFDLE9BQU87SUFDM0IsSUFBSSxDQUFDLE9BQU8sSUFBSSxPQUFPLE9BQU8sS0FBSyxRQUFRO1FBQUUsT0FBTyxLQUFLLENBQUE7SUFFekQsTUFBTSxhQUFhLEdBQUcsc0NBQXNDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQTtJQUV0RSxPQUFPLGFBQWEsQ0FBQyxJQUFJLEtBQUssS0FBSyxJQUFJLE1BQU0sQ0FBQyxNQUFNLENBQUMsYUFBYSxFQUFFLFNBQVMsQ0FBQyxDQUFBO0FBQ2hGLENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsU0FBUyxNQUFNLENBQUMsUUFBUTtJQUN0QixTQUFTLEdBQUcsSUFBSSxDQUFBO0lBQ2hCLE9BQU8sQ0FBQyxRQUFRLEdBQUcsUUFBUSxDQUFBO0lBRTNCLElBQUksT0FBTyxDQUFDLFNBQVMsSUFBSSxPQUFPLENBQUMsVUFBVSxFQUFFLENBQUM7UUFDNUMsT0FBTyxDQUFDLFVBQVUsRUFBRSxDQUFBO0lBQ3RCLENBQUM7SUFFRCxZQUFZLENBQUMsR0FBRyxFQUFFLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFBO0FBQzVDLENBQUM7QUFFRDs7O0dBR0c7QUFDSCxTQUFTLGlCQUFpQjtJQUN4QixJQUFJLE9BQU8sQ0FBQyxJQUFJO1FBQUUsT0FBTyxDQUFDLElBQUksQ0FBQyxFQUFDLElBQUksRUFBRSxjQUFjLEVBQUMsQ0FBQyxDQUFBO0FBQ3hELENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsS0FBSyxVQUFVLGFBQWEsQ0FBQyxPQUFPO0lBQ2xDLElBQUksQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztRQUMzQixNQUFNLElBQUksS0FBSyxDQUFDLHVEQUF1RCxDQUFDLENBQUE7SUFDMUUsQ0FBQztJQUVELDJFQUEyRTtJQUMzRSw2RUFBNkU7SUFDN0UsOEVBQThFO0lBQzlFLE1BQU0sYUFBYSxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsRUFBQyxnQkFBZ0IsRUFBRSxLQUFLLEVBQUMsQ0FBQyxDQUFBO0FBQ2pFLENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsS0FBSyxVQUFVLGdCQUFnQixDQUFDLE9BQU87SUFDckMsSUFBSSxDQUFDO1FBQ0gsTUFBTSxhQUFhLENBQUMsT0FBTyxDQUFDLENBQUE7UUFDNUIsaUJBQWlCLEVBQUUsQ0FBQTtRQUNuQixNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUE7SUFDWCxDQUFDO0lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztRQUNmLGlCQUFpQixFQUFFLENBQUE7UUFDbkIsT0FBTyxDQUFDLEtBQUssQ0FBQyxzQ0FBc0MsRUFBRSxLQUFLLENBQUMsQ0FBQTtRQUM1RCxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUE7SUFDWCxDQUFDO0FBQ0gsQ0FBQztBQUVELEtBQUssTUFBTSxNQUFNLElBQUksQ0FBQyxTQUFTLEVBQUUsUUFBUSxDQUFDLEVBQUUsQ0FBQztJQUMzQyxPQUFPLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxHQUFHLEVBQUUsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUE7QUFDN0MsQ0FBQztBQUVELE9BQU8sQ0FBQyxJQUFJLENBQUMsWUFBWSxFQUFFLEdBQUcsRUFBRTtJQUM5QixJQUFJLENBQUMsU0FBUztRQUFFLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUE7QUFDakMsQ0FBQyxDQUFDLENBQUE7QUFFRixPQUFPLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDLE9BQU8sRUFBRSxFQUFFO0lBQ2xDLEtBQUssZ0JBQWdCLENBQUMsT0FBTyxDQUFDLENBQUE7QUFDaEMsQ0FBQyxDQUFDLENBQUEiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBAdHMtY2hlY2tcblxuaW1wb3J0IHJ1bkpvYlBheWxvYWQgZnJvbSBcIi4vam9iLXJ1bm5lci5qc1wiXG5pbXBvcnQgc2V0UnVubmVyUHJvY2Vzc1RpdGxlIGZyb20gXCIuL3J1bm5lci1wcm9jZXNzLXRpdGxlLmpzXCJcblxuLy8gTmFtZSB0aGUgcHJvY2VzcyBzbyBgcHNgL2B0b3BgL2BodG9wYCBjYW4gaWRlbnRpZnkgZm9ya2VkIGpvYiBydW5uZXJzIGF0IGFcbi8vIGdsYW5jZSBpbnN0ZWFkIG9mIGEgd2FsbCBvZiBnZW5lcmljIFwibm9kZVwiIGVudHJpZXMuIFVwZGF0ZWQgdG8gdGhlIHNwZWNpZmljXG4vLyBqb2IgbmFtZSBvbmNlIG9uZSBhcnJpdmVzIChzZWUgcnVuSm9iTWVzc2FnZSksIHNvIG9wZXJhdG9ycyBjYW4gc2VlIGV4YWN0bHlcbi8vIHdoaWNoIGpvYnMgYXJlIHJ1bm5pbmcsIGhvdyBtYW55IG9mIGVhY2gsIGFuZCB3aGljaCBhcmUgZWF0aW5nIHJlc291cmNlcy5cbnNldFJ1bm5lclByb2Nlc3NUaXRsZSgpXG5cbmxldCBmaW5pc2hpbmcgPSBmYWxzZVxuXG4vKipcbiAqIFJ1bnMgaXMgam9iIG1lc3NhZ2UuXG4gKiBAcGFyYW0gez99IG1lc3NhZ2UgLSBJUEMgbWVzc2FnZS5cbiAqIEByZXR1cm5zIHttZXNzYWdlIGlzIHt0eXBlOiBcImpvYlwiLCBwYXlsb2FkOiBpbXBvcnQoXCIuL3R5cGVzLmpzXCIpLkJhY2tncm91bmRKb2JQYXlsb2FkfX0gLSBXaGV0aGVyIHRoaXMgaXMgYSBqb2IgbWVzc2FnZS5cbiAqL1xuZnVuY3Rpb24gaXNKb2JNZXNzYWdlKG1lc3NhZ2UpIHtcbiAgaWYgKCFtZXNzYWdlIHx8IHR5cGVvZiBtZXNzYWdlICE9PSBcIm9iamVjdFwiKSByZXR1cm4gZmFsc2VcblxuICBjb25zdCBtZXNzYWdlUmVjb3JkID0gLyoqIEB0eXBlIHt7dHlwZT86ID8sIHBheWxvYWQ/OiA/fX0gKi8gKG1lc3NhZ2UpXG5cbiAgcmV0dXJuIG1lc3NhZ2VSZWNvcmQudHlwZSA9PT0gXCJqb2JcIiAmJiBPYmplY3QuaGFzT3duKG1lc3NhZ2VSZWNvcmQsIFwicGF5bG9hZFwiKVxufVxuXG4vKipcbiAqIFJ1bnMgZmluaXNoLlxuICogQHBhcmFtIHtudW1iZXJ9IGV4aXRDb2RlIC0gUHJvY2VzcyBleGl0IGNvZGUuXG4gKiBAcmV0dXJucyB7dm9pZH1cbiAqL1xuZnVuY3Rpb24gZmluaXNoKGV4aXRDb2RlKSB7XG4gIGZpbmlzaGluZyA9IHRydWVcbiAgcHJvY2Vzcy5leGl0Q29kZSA9IGV4aXRDb2RlXG5cbiAgaWYgKHByb2Nlc3MuY29ubmVjdGVkICYmIHByb2Nlc3MuZGlzY29ubmVjdCkge1xuICAgIHByb2Nlc3MuZGlzY29ubmVjdCgpXG4gIH1cblxuICBzZXRJbW1lZGlhdGUoKCkgPT4gcHJvY2Vzcy5leGl0KGV4aXRDb2RlKSlcbn1cblxuLyoqXG4gKiBSdW5zIHJlcG9ydCBqb2IgZmluaXNoZWQuXG4gKiBAcmV0dXJucyB7dm9pZH1cbiAqL1xuZnVuY3Rpb24gcmVwb3J0Sm9iRmluaXNoZWQoKSB7XG4gIGlmIChwcm9jZXNzLnNlbmQpIHByb2Nlc3Muc2VuZCh7dHlwZTogXCJqb2ItcmVwb3J0ZWRcIn0pXG59XG5cbi8qKlxuICogUnVucyBydW4gam9iIG1lc3NhZ2UuXG4gKiBAcGFyYW0gez99IG1lc3NhZ2UgLSBJUEMgbWVzc2FnZS5cbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIGFmdGVyIHRoZSBwYXlsb2FkIGhhcyBydW4uXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHJ1bkpvYk1lc3NhZ2UobWVzc2FnZSkge1xuICBpZiAoIWlzSm9iTWVzc2FnZShtZXNzYWdlKSkge1xuICAgIHRocm93IG5ldyBFcnJvcihcIkZvcmtlZCBiYWNrZ3JvdW5kIGpvYiBydW5uZXIgcmVjZWl2ZWQgaW52YWxpZCBwYXlsb2FkXCIpXG4gIH1cblxuICAvLyBUaGUgcGVyLWpvYiBwcm9jZXNzIHRpdGxlIChhbmQgaXRzIHJlc3RvcmUpIGlzIHNldCBpbnNpZGUgcnVuSm9iUGF5bG9hZCxcbiAgLy8gd2hpY2ggcmVhZHMgdGhlIGpvYiBjbGFzcydzIGBzdGF0aWMgcHJvY2Vzc1RpdGxlYC4gVGhpcyBwcm9jZXNzIGJvb3RzIHdpdGhcbiAgLy8gdGhlIGJhc2UgXCJ2ZWxvY2lvdXMgYmFja2dyb3VuZC1qb2JzLXJ1bm5lclwiIHRpdGxlIHNldCBhdCBtb2R1bGUgbG9hZCBhYm92ZS5cbiAgYXdhaXQgcnVuSm9iUGF5bG9hZChtZXNzYWdlLnBheWxvYWQsIHtjbG9zZUNvbm5lY3Rpb25zOiBmYWxzZX0pXG59XG5cbi8qKlxuICogUnVucyBoYW5kbGUgam9iIG1lc3NhZ2UuXG4gKiBAcGFyYW0gez99IG1lc3NhZ2UgLSBJUEMgbWVzc2FnZS5cbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIGFmdGVyIGNvbXBsZXRpb24gaXMgcmVwb3J0ZWQuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGhhbmRsZUpvYk1lc3NhZ2UobWVzc2FnZSkge1xuICB0cnkge1xuICAgIGF3YWl0IHJ1bkpvYk1lc3NhZ2UobWVzc2FnZSlcbiAgICByZXBvcnRKb2JGaW5pc2hlZCgpXG4gICAgZmluaXNoKDApXG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgcmVwb3J0Sm9iRmluaXNoZWQoKVxuICAgIGNvbnNvbGUuZXJyb3IoXCJGb3JrZWQgYmFja2dyb3VuZCBqb2IgcnVubmVyIGZhaWxlZDpcIiwgZXJyb3IpXG4gICAgZmluaXNoKDEpXG4gIH1cbn1cblxuZm9yIChjb25zdCBzaWduYWwgb2YgW1wiU0lHVEVSTVwiLCBcIlNJR0lOVFwiXSkge1xuICBwcm9jZXNzLm9uY2Uoc2lnbmFsLCAoKSA9PiBwcm9jZXNzLmV4aXQoMSkpXG59XG5cbnByb2Nlc3Mub25jZShcImRpc2Nvbm5lY3RcIiwgKCkgPT4ge1xuICBpZiAoIWZpbmlzaGluZykgcHJvY2Vzcy5leGl0KDApXG59KVxuXG5wcm9jZXNzLm9uY2UoXCJtZXNzYWdlXCIsIChtZXNzYWdlKSA9PiB7XG4gIHZvaWQgaGFuZGxlSm9iTWVzc2FnZShtZXNzYWdlKVxufSlcbiJdfQ==
|
|
@@ -3,9 +3,18 @@
|
|
|
3
3
|
* @param {import("./types.js").BackgroundJobPayload} payload - Payload.
|
|
4
4
|
* @param {object} [options] - Runner options.
|
|
5
5
|
* @param {boolean} [options.closeConnections] - Whether to gracefully close framework connections after the job.
|
|
6
|
+
* @param {boolean} [options.manageProcessTitle] - Whether to set the per-job process title and restore it afterwards. Off for concurrent pooled runners, where interleaved snapshot/restore of the single process-wide `process.title` would corrupt it; the pooled child owns an aggregate title instead.
|
|
6
7
|
* @returns {Promise<void>} - Resolves when complete.
|
|
7
8
|
*/
|
|
8
|
-
export default function runJobPayload(payload: import("./types.js").BackgroundJobPayload, { closeConnections }?: {
|
|
9
|
+
export default function runJobPayload(payload: import("./types.js").BackgroundJobPayload, { closeConnections, manageProcessTitle }?: {
|
|
9
10
|
closeConnections?: boolean | undefined;
|
|
11
|
+
manageProcessTitle?: boolean | undefined;
|
|
10
12
|
}): Promise<void>;
|
|
13
|
+
export class BackgroundJobPerformedFailure extends Error {
|
|
14
|
+
/**
|
|
15
|
+
* Creates a performed-job failure after its terminal report is acknowledged.
|
|
16
|
+
* @param {Error} cause - A job perform error whose failed terminal report was acknowledged.
|
|
17
|
+
*/
|
|
18
|
+
constructor(cause: Error);
|
|
19
|
+
}
|
|
11
20
|
//# sourceMappingURL=job-runner.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"job-runner.d.ts","sourceRoot":"","sources":["../../../src/background-jobs/job-runner.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"job-runner.d.ts","sourceRoot":"","sources":["../../../src/background-jobs/job-runner.js"],"names":[],"mappings":"AA2EA;;;;;;;GAOG;AACH,+CANW,OAAO,YAAY,EAAE,oBAAoB,6CAEjD;IAA0B,gBAAgB;IAChB,kBAAkB;CAC5C,GAAU,OAAO,CAAC,IAAI,CAAC,CAoEzB;AA7ID;IACE;;;OAGG;IACH,mBAFW,KAAK,EAKf;CACF"}
|