velocious 1.0.598 → 1.0.600
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/adapter-client.js +45 -0
- package/build/background-jobs/adapter.js +139 -0
- package/build/background-jobs/job-registry.js +1 -1
- package/build/background-jobs/job.js +20 -129
- package/build/background-jobs/main.js +71 -28
- package/build/background-jobs/perform-job.js +23 -0
- package/build/background-jobs/platform-job.js +156 -0
- package/build/background-jobs/runtime.js +156 -0
- package/build/background-jobs/sql-adapter.js +20 -0
- package/build/background-jobs/store.js +3 -1
- package/build/background-jobs/types.js +10 -0
- package/build/background-jobs/web/controller.js +5 -2
- package/build/background-jobs/worker.js +6 -8
- package/build/configuration-types.js +5 -0
- package/build/configuration.js +217 -40
- package/build/environment-handlers/base.js +20 -0
- package/build/environment-handlers/node.js +27 -20
- package/build/jobs/prune-terminal-background-jobs.js +2 -3
- package/build/src/background-jobs/adapter-client.d.ts +41 -0
- package/build/src/background-jobs/adapter-client.d.ts.map +1 -0
- package/build/src/background-jobs/adapter-client.js +39 -0
- package/build/src/background-jobs/adapter.d.ts +165 -0
- package/build/src/background-jobs/adapter.d.ts.map +1 -0
- package/build/src/background-jobs/adapter.js +121 -0
- package/build/src/background-jobs/job-registry.d.ts +1 -1
- package/build/src/background-jobs/job-registry.d.ts.map +1 -1
- package/build/src/background-jobs/job-registry.js +2 -2
- package/build/src/background-jobs/job.d.ts +6 -69
- package/build/src/background-jobs/job.d.ts.map +1 -1
- package/build/src/background-jobs/job.js +17 -116
- package/build/src/background-jobs/main.d.ts +13 -3
- package/build/src/background-jobs/main.d.ts.map +1 -1
- package/build/src/background-jobs/main.js +66 -30
- package/build/src/background-jobs/perform-job.d.ts +16 -0
- package/build/src/background-jobs/perform-job.d.ts.map +1 -0
- package/build/src/background-jobs/perform-job.js +22 -0
- package/build/src/background-jobs/platform-job.d.ts +110 -0
- package/build/src/background-jobs/platform-job.d.ts.map +1 -0
- package/build/src/background-jobs/platform-job.js +138 -0
- package/build/src/background-jobs/runtime.d.ts +78 -0
- package/build/src/background-jobs/runtime.d.ts.map +1 -0
- package/build/src/background-jobs/runtime.js +132 -0
- package/build/src/background-jobs/sql-adapter.d.ts +13 -0
- package/build/src/background-jobs/sql-adapter.d.ts.map +1 -0
- package/build/src/background-jobs/sql-adapter.js +18 -0
- package/build/src/background-jobs/store.d.ts +2 -1
- package/build/src/background-jobs/store.d.ts.map +1 -1
- package/build/src/background-jobs/store.js +4 -2
- package/build/src/background-jobs/types.d.ts +41 -0
- package/build/src/background-jobs/types.d.ts.map +1 -1
- package/build/src/background-jobs/types.js +11 -1
- package/build/src/background-jobs/web/controller.d.ts.map +1 -1
- package/build/src/background-jobs/web/controller.js +5 -3
- package/build/src/background-jobs/worker.d.ts.map +1 -1
- package/build/src/background-jobs/worker.js +7 -8
- package/build/src/configuration-types.d.ts +16 -0
- package/build/src/configuration-types.d.ts.map +1 -1
- package/build/src/configuration-types.js +5 -1
- package/build/src/configuration.d.ts +51 -2
- package/build/src/configuration.d.ts.map +1 -1
- package/build/src/configuration.js +202 -39
- package/build/src/environment-handlers/base.d.ts +17 -0
- package/build/src/environment-handlers/base.d.ts.map +1 -1
- package/build/src/environment-handlers/base.js +19 -1
- package/build/src/environment-handlers/node.d.ts +18 -0
- package/build/src/environment-handlers/node.d.ts.map +1 -1
- package/build/src/environment-handlers/node.js +25 -20
- package/build/src/jobs/prune-terminal-background-jobs.d.ts.map +1 -1
- package/build/src/jobs/prune-terminal-background-jobs.js +3 -4
- package/build/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/background-jobs/adapter-client.js +45 -0
- package/src/background-jobs/adapter.js +139 -0
- package/src/background-jobs/job-registry.js +1 -1
- package/src/background-jobs/job.js +20 -129
- package/src/background-jobs/main.js +71 -28
- package/src/background-jobs/perform-job.js +23 -0
- package/src/background-jobs/platform-job.js +156 -0
- package/src/background-jobs/runtime.js +156 -0
- package/src/background-jobs/sql-adapter.js +20 -0
- package/src/background-jobs/store.js +3 -1
- package/src/background-jobs/types.js +10 -0
- package/src/background-jobs/web/controller.js +5 -2
- package/src/background-jobs/worker.js +6 -8
- package/src/configuration-types.js +5 -0
- package/src/configuration.js +217 -40
- package/src/environment-handlers/base.js +20 -0
- package/src/environment-handlers/node.js +27 -20
- package/src/jobs/prune-terminal-background-jobs.js +2 -3
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import BackgroundJobRescheduleSignal from "./reschedule-signal.js"
|
|
4
|
+
import {cancelScheduledBackgroundJob, enqueueBackgroundJob, replaceScheduledBackgroundJob} from "./runtime.js"
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Base class for background jobs.
|
|
8
|
+
*
|
|
9
|
+
* `TArgs` is the tuple of arguments the subclass's `perform` accepts, so a job that
|
|
10
|
+
* needs arguments declares them as required and typed — for example
|
|
11
|
+
* `class RunBuildJob extends VelociousJob<[string]>` with `async perform(buildId)`.
|
|
12
|
+
* The default empty tuple keeps argument-less jobs (`extends VelociousJob`,
|
|
13
|
+
* `async perform()`) working unchanged.
|
|
14
|
+
* @template {Array<ReturnType<typeof JSON.parse>>} [TArgs=[]]
|
|
15
|
+
*/
|
|
16
|
+
export default class VelociousJob {
|
|
17
|
+
/**
|
|
18
|
+
* Database identifiers checked out while this job performs. Set an explicit
|
|
19
|
+
* list to avoid holding unrelated configured database connections, or `[]`
|
|
20
|
+
* when the job establishes any connections it needs itself. Left undefined,
|
|
21
|
+
* jobs retain the existing behavior of checking out every active database.
|
|
22
|
+
* @type {string[] | undefined}
|
|
23
|
+
*/
|
|
24
|
+
static databaseIdentifiers = undefined
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Queue this job class runs on. Subclasses set e.g. `static queue = "builds"`
|
|
28
|
+
* to route onto a queue with its own cluster-wide concurrency cap (configured
|
|
29
|
+
* via `backgroundJobs.queues`). The `{queue}` enqueue option overrides it.
|
|
30
|
+
* Left undefined, jobs run on the `"default"` queue.
|
|
31
|
+
* @type {string | undefined}
|
|
32
|
+
*/
|
|
33
|
+
static queue = undefined
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Optional process title shown for the runner while this job executes.
|
|
37
|
+
* Velocious sets `process.title` to this for the duration of the job — so
|
|
38
|
+
* `ps`/`top`/`htop` identify what a runner is doing — and restores the
|
|
39
|
+
* runner's base title when the job finishes. Left undefined, the runner falls
|
|
40
|
+
* back to `velocious job-runner: <JobName>`. Set e.g.
|
|
41
|
+
* `static processTitle = "velocious media transcoder"` to give a job a
|
|
42
|
+
* custom, human-readable title.
|
|
43
|
+
* @type {string | undefined}
|
|
44
|
+
*/
|
|
45
|
+
static processTitle = undefined
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Stops this performance and reschedules the same logical job row. This is
|
|
49
|
+
* normal control flow: it does not count as a failure or consume a retry.
|
|
50
|
+
* @param {number} delayMs - Non-negative safe-integer delay in milliseconds.
|
|
51
|
+
* @returns {never} - This method never returns.
|
|
52
|
+
*/
|
|
53
|
+
rescheduleIn(delayMs) {
|
|
54
|
+
if (!Number.isSafeInteger(delayMs) || delayMs < 0) {
|
|
55
|
+
throw new TypeError("background job reschedule delayMs must be a non-negative safe integer")
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
throw new BackgroundJobRescheduleSignal(delayMs)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Runs job name.
|
|
63
|
+
* @returns {string} - Job name.
|
|
64
|
+
*/
|
|
65
|
+
static jobName() {
|
|
66
|
+
return this.name
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Folds this job class's static `queue` into the enqueue options unless the
|
|
71
|
+
* caller already specified one.
|
|
72
|
+
* @param {import("./types.js").BackgroundJobOptions | undefined} options - Job options.
|
|
73
|
+
* @returns {import("./types.js").BackgroundJobOptions} - Options including the resolved queue.
|
|
74
|
+
*/
|
|
75
|
+
static _withQueue(options) {
|
|
76
|
+
const merged = options ? {...options} : {}
|
|
77
|
+
|
|
78
|
+
if (merged.queue === undefined && typeof this.queue === "string" && this.queue.length > 0) {
|
|
79
|
+
merged.queue = this.queue
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return merged
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Runs perform later.
|
|
87
|
+
* @param {...ReturnType<typeof JSON.parse>} args - Job args.
|
|
88
|
+
* @returns {Promise<string>} - Job id.
|
|
89
|
+
*/
|
|
90
|
+
static async performLater(...args) {
|
|
91
|
+
const {jobArgs, jobOptions} = this._splitArgsAndOptions(args)
|
|
92
|
+
return await enqueueBackgroundJob({JobClass: this, jobArgs, jobOptions})
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Runs perform later with options.
|
|
97
|
+
* @param {object} args - Options.
|
|
98
|
+
* @param {Array<ReturnType<typeof JSON.parse>>} args.args - Job args.
|
|
99
|
+
* @param {import("./types.js").BackgroundJobOptions} [args.options] - Job options.
|
|
100
|
+
* @returns {Promise<string>} - Job id.
|
|
101
|
+
*/
|
|
102
|
+
static async performLaterWithOptions({args, options}) {
|
|
103
|
+
return await enqueueBackgroundJob({JobClass: this, jobArgs: args, jobOptions: options})
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Atomically replaces this job class's queued owner for a stable schedule key.
|
|
108
|
+
* @param {object} args - Options.
|
|
109
|
+
* @param {string} args.scheduleKey - Stable logical schedule key.
|
|
110
|
+
* @param {Array<ReturnType<typeof JSON.parse>>} args.args - Job args.
|
|
111
|
+
* @param {import("./types.js").BackgroundJobOptions} [args.options] - Job options.
|
|
112
|
+
* @returns {Promise<import("./types.js").BackgroundJobReplacementResult>} - Replacement result.
|
|
113
|
+
*/
|
|
114
|
+
static async replaceScheduled({scheduleKey, args, options}) {
|
|
115
|
+
return await replaceScheduledBackgroundJob({JobClass: this, scheduleKey, jobArgs: args, jobOptions: options})
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Cancels or detaches the current owner of a stable schedule key.
|
|
120
|
+
* @param {string} scheduleKey - Stable logical schedule key.
|
|
121
|
+
* @returns {Promise<import("./types.js").BackgroundJobCancellationResult>} - Cancellation result.
|
|
122
|
+
*/
|
|
123
|
+
static async cancelScheduled(scheduleKey) {
|
|
124
|
+
return await cancelScheduledBackgroundJob(scheduleKey)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Runs split args and options.
|
|
129
|
+
* @param {Array<ReturnType<typeof JSON.parse>>} args - Job args.
|
|
130
|
+
* @returns {{jobArgs: Array<ReturnType<typeof JSON.parse>>, jobOptions: import("./types.js").BackgroundJobOptions}} - Split args and options.
|
|
131
|
+
*/
|
|
132
|
+
static _splitArgsAndOptions(args) {
|
|
133
|
+
if (args.length === 0) {
|
|
134
|
+
return {jobArgs: [], jobOptions: {}}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const lastArg = args[args.length - 1]
|
|
138
|
+
const isOptionsArg = lastArg && typeof lastArg === "object" && !Array.isArray(lastArg) && "jobOptions" in lastArg
|
|
139
|
+
|
|
140
|
+
if (isOptionsArg) {
|
|
141
|
+
const {jobOptions} = /** @type {{jobOptions: import("./types.js").BackgroundJobOptions}} */ (lastArg)
|
|
142
|
+
return {jobArgs: args.slice(0, -1), jobOptions: jobOptions || {}}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return {jobArgs: args, jobOptions: {}}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Override in subclasses.
|
|
150
|
+
* @param {TArgs} _args - Job args (the tuple this job class was parameterized with).
|
|
151
|
+
* @returns {Promise<void>} - Resolves when complete.
|
|
152
|
+
*/
|
|
153
|
+
async perform(..._args) {
|
|
154
|
+
throw new Error("perform not implemented")
|
|
155
|
+
}
|
|
156
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import {currentConfiguration} from "../current-configuration.js"
|
|
4
|
+
import performBackgroundJob from "./perform-job.js"
|
|
5
|
+
import BackgroundJobRescheduleSignal from "./reschedule-signal.js"
|
|
6
|
+
|
|
7
|
+
let inlinePerformanceSequence = 0
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Rejects options whose semantics require durable queue state.
|
|
11
|
+
* @param {import("./types.js").BackgroundJobOptions | undefined} options - Requested options.
|
|
12
|
+
* @returns {void}
|
|
13
|
+
*/
|
|
14
|
+
function validateInlineOptions(options) {
|
|
15
|
+
const optionNames = Object.keys(options || {})
|
|
16
|
+
|
|
17
|
+
if (optionNames.length > 0) {
|
|
18
|
+
throw new Error(`Background job option ${optionNames[0]} is not supported in inline mode`)
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Builds an ephemeral inline performance id.
|
|
24
|
+
* @returns {string} - Performance id.
|
|
25
|
+
*/
|
|
26
|
+
function inlineJobId() {
|
|
27
|
+
inlinePerformanceSequence++
|
|
28
|
+
return `inline-${Date.now()}-${inlinePerformanceSequence}`
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Enqueues durably in background mode or performs immediately in inline mode.
|
|
33
|
+
* @param {object} args - Enqueue request.
|
|
34
|
+
* @param {typeof import("./platform-job.js").default} args.JobClass - Job class.
|
|
35
|
+
* @param {Array<ReturnType<typeof JSON.parse>>} args.jobArgs - Job arguments.
|
|
36
|
+
* @param {import("./types.js").BackgroundJobOptions | undefined} args.jobOptions - Job options.
|
|
37
|
+
* @returns {Promise<string>} - Durable job id or ephemeral inline performance id.
|
|
38
|
+
*/
|
|
39
|
+
export async function enqueueBackgroundJob({JobClass, jobArgs, jobOptions}) {
|
|
40
|
+
const configuration = currentConfiguration()
|
|
41
|
+
|
|
42
|
+
return await enqueueBackgroundJobForConfiguration({configuration, JobClass, jobArgs, jobOptions})
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Enqueues using an explicitly resolved configuration.
|
|
47
|
+
* @param {object} args - Enqueue request.
|
|
48
|
+
* @param {import("../configuration.js").default} args.configuration - Configuration.
|
|
49
|
+
* @param {typeof import("./platform-job.js").default} args.JobClass - Job class.
|
|
50
|
+
* @param {Array<ReturnType<typeof JSON.parse>>} args.jobArgs - Job arguments.
|
|
51
|
+
* @param {import("./types.js").BackgroundJobOptions | undefined} args.jobOptions - Job options.
|
|
52
|
+
* @returns {Promise<string>} - Durable job id or ephemeral inline performance id.
|
|
53
|
+
*/
|
|
54
|
+
export async function enqueueBackgroundJobForConfiguration({configuration, JobClass, jobArgs, jobOptions}) {
|
|
55
|
+
|
|
56
|
+
if (configuration.getBackgroundJobsConfig().mode === "inline") {
|
|
57
|
+
validateInlineOptions(jobOptions)
|
|
58
|
+
configuration.setCurrent()
|
|
59
|
+
await configuration.initialize({type: "background-jobs-inline"})
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
await performBackgroundJob({
|
|
63
|
+
configuration,
|
|
64
|
+
JobClass,
|
|
65
|
+
jobArgs,
|
|
66
|
+
name: `Background job inline mode: ${JobClass.jobName()}`
|
|
67
|
+
})
|
|
68
|
+
} catch (error) {
|
|
69
|
+
if (error instanceof BackgroundJobRescheduleSignal) {
|
|
70
|
+
throw new Error("rescheduleIn is not supported in inline mode", {cause: error})
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
throw error
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return inlineJobId()
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const client = configuration.getEnvironmentHandler().backgroundJobsClient({configuration})
|
|
80
|
+
|
|
81
|
+
return await client.enqueue({
|
|
82
|
+
jobName: JobClass.jobName(),
|
|
83
|
+
args: jobArgs,
|
|
84
|
+
options: JobClass._withQueue(jobOptions)
|
|
85
|
+
})
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Replaces a stable durable schedule in background mode.
|
|
90
|
+
* @param {object} args - Replacement request.
|
|
91
|
+
* @param {typeof import("./platform-job.js").default} args.JobClass - Job class.
|
|
92
|
+
* @param {string} args.scheduleKey - Stable schedule key.
|
|
93
|
+
* @param {Array<ReturnType<typeof JSON.parse>>} args.jobArgs - Job arguments.
|
|
94
|
+
* @param {import("./types.js").BackgroundJobOptions | undefined} args.jobOptions - Job options.
|
|
95
|
+
* @returns {Promise<import("./types.js").BackgroundJobReplacementResult>} - Replacement result.
|
|
96
|
+
*/
|
|
97
|
+
export async function replaceScheduledBackgroundJob({JobClass, scheduleKey, jobArgs, jobOptions}) {
|
|
98
|
+
const configuration = currentConfiguration()
|
|
99
|
+
|
|
100
|
+
return await replaceScheduledBackgroundJobForConfiguration({configuration, JobClass, scheduleKey, jobArgs, jobOptions})
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Replaces a stable schedule using an explicitly resolved configuration.
|
|
105
|
+
* @param {object} args - Replacement request.
|
|
106
|
+
* @param {import("../configuration.js").default} args.configuration - Configuration.
|
|
107
|
+
* @param {typeof import("./platform-job.js").default} args.JobClass - Job class.
|
|
108
|
+
* @param {string} args.scheduleKey - Stable schedule key.
|
|
109
|
+
* @param {Array<ReturnType<typeof JSON.parse>>} args.jobArgs - Job arguments.
|
|
110
|
+
* @param {import("./types.js").BackgroundJobOptions | undefined} args.jobOptions - Job options.
|
|
111
|
+
* @returns {Promise<import("./types.js").BackgroundJobReplacementResult>} - Replacement result.
|
|
112
|
+
*/
|
|
113
|
+
export async function replaceScheduledBackgroundJobForConfiguration({configuration, JobClass, scheduleKey, jobArgs, jobOptions}) {
|
|
114
|
+
|
|
115
|
+
if (configuration.getBackgroundJobsConfig().mode === "inline") {
|
|
116
|
+
throw new Error("replaceScheduled is not supported in inline mode")
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const client = configuration.getEnvironmentHandler().backgroundJobsClient({configuration})
|
|
120
|
+
|
|
121
|
+
return await client.replaceScheduled({
|
|
122
|
+
scheduleKey,
|
|
123
|
+
jobName: JobClass.jobName(),
|
|
124
|
+
args: jobArgs,
|
|
125
|
+
options: JobClass._withQueue(jobOptions)
|
|
126
|
+
})
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Cancels a stable durable schedule in background mode.
|
|
131
|
+
* @param {string} scheduleKey - Stable schedule key.
|
|
132
|
+
* @returns {Promise<import("./types.js").BackgroundJobCancellationResult>} - Cancellation result.
|
|
133
|
+
*/
|
|
134
|
+
export async function cancelScheduledBackgroundJob(scheduleKey) {
|
|
135
|
+
const configuration = currentConfiguration()
|
|
136
|
+
|
|
137
|
+
return await cancelScheduledBackgroundJobForConfiguration({configuration, scheduleKey})
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Cancels a stable schedule using an explicitly resolved configuration.
|
|
142
|
+
* @param {object} args - Cancellation request.
|
|
143
|
+
* @param {import("../configuration.js").default} args.configuration - Configuration.
|
|
144
|
+
* @param {string} args.scheduleKey - Stable logical schedule key.
|
|
145
|
+
* @returns {Promise<import("./types.js").BackgroundJobCancellationResult>} - Cancellation result.
|
|
146
|
+
*/
|
|
147
|
+
export async function cancelScheduledBackgroundJobForConfiguration({configuration, scheduleKey}) {
|
|
148
|
+
|
|
149
|
+
if (configuration.getBackgroundJobsConfig().mode === "inline") {
|
|
150
|
+
throw new Error("cancelScheduled is not supported in inline mode")
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const client = configuration.getEnvironmentHandler().backgroundJobsClient({configuration})
|
|
154
|
+
|
|
155
|
+
return await client.cancelScheduled({scheduleKey})
|
|
156
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import BackgroundJobsStore from "./store.js"
|
|
4
|
+
|
|
5
|
+
/** Built-in SQL adapter preserving the existing durable store implementation. */
|
|
6
|
+
export default class SqlBackgroundJobsAdapter extends BackgroundJobsStore {
|
|
7
|
+
/**
|
|
8
|
+
* Ensures the built-in SQL schema during migration.
|
|
9
|
+
* @param {{dbs: Record<string, import("../database/drivers/base.js").default>}} args - Migrated databases.
|
|
10
|
+
* @returns {Promise<void>} - Resolves when the SQL schema is present.
|
|
11
|
+
*/
|
|
12
|
+
async ensureFrameworkSchema({dbs}) {
|
|
13
|
+
const databaseIdentifier = this.getDatabaseIdentifier() || "default"
|
|
14
|
+
const frameworkDb = dbs[databaseIdentifier]
|
|
15
|
+
|
|
16
|
+
if (!frameworkDb) return
|
|
17
|
+
|
|
18
|
+
await this.ensureSchema(frameworkDb)
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
3
|
import {createHash, randomUUID} from "crypto"
|
|
4
|
+
import BackgroundJobsAdapter from "./adapter.js"
|
|
4
5
|
import Logger from "../logger.js"
|
|
5
6
|
import TableData from "../database/table-data/index.js"
|
|
6
7
|
import VelociousError from "../velocious-error.js"
|
|
@@ -100,7 +101,7 @@ const schemaApplyChains = new Map()
|
|
|
100
101
|
/** @type {Map<string, Promise<void>>} */
|
|
101
102
|
const transactionMutationChains = new Map()
|
|
102
103
|
|
|
103
|
-
export default class BackgroundJobsStore {
|
|
104
|
+
export default class BackgroundJobsStore extends BackgroundJobsAdapter {
|
|
104
105
|
/**
|
|
105
106
|
* Runs constructor.
|
|
106
107
|
* @param {object} args - Options.
|
|
@@ -108,6 +109,7 @@ export default class BackgroundJobsStore {
|
|
|
108
109
|
* @param {string} [args.databaseIdentifier] - Database identifier.
|
|
109
110
|
*/
|
|
110
111
|
constructor({configuration, databaseIdentifier}) {
|
|
112
|
+
super()
|
|
111
113
|
this.configuration = configuration
|
|
112
114
|
this.databaseIdentifier = databaseIdentifier
|
|
113
115
|
this.logger = new Logger(this)
|
|
@@ -3,6 +3,16 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* @typedef {"inline" | "forked" | "pooled" | "spawned"} BackgroundJobExecutionMode
|
|
5
5
|
*/
|
|
6
|
+
/**
|
|
7
|
+
* @typedef {object} BackgroundJobsHealth
|
|
8
|
+
* @property {boolean} ready - Whether the adapter can accept and process work.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* @typedef {object} BackgroundJobsProducer
|
|
12
|
+
* @property {(args: {jobName: string, args: Array<ReturnType<typeof JSON.parse>>, options?: BackgroundJobOptions}) => Promise<string>} enqueue - Enqueues a job.
|
|
13
|
+
* @property {(args: {scheduleKey: string, jobName: string, args: Array<ReturnType<typeof JSON.parse>>, options?: BackgroundJobOptions}) => Promise<BackgroundJobReplacementResult>} replaceScheduled - Replaces a stable schedule.
|
|
14
|
+
* @property {(args: {scheduleKey: string}) => Promise<BackgroundJobCancellationResult>} cancelScheduled - Cancels a stable schedule.
|
|
15
|
+
*/
|
|
6
16
|
/**
|
|
7
17
|
* @typedef {object} BackgroundJobHandoff
|
|
8
18
|
* @property {string} handoffId - Unique handoff lease id.
|
|
@@ -99,11 +99,14 @@ export default class VelociousBackgroundJobsWebController extends Controller {
|
|
|
99
99
|
*/
|
|
100
100
|
async health() {
|
|
101
101
|
await this._respond(async () => {
|
|
102
|
+
const health = await this.getConfiguration().backgroundJobsHealth()
|
|
103
|
+
|
|
102
104
|
await this.render({json: {
|
|
103
105
|
capabilities: {backgroundJobCountDeltas: 1},
|
|
104
|
-
ok:
|
|
106
|
+
ok: health.ready,
|
|
107
|
+
ready: health.ready,
|
|
105
108
|
service: "velocious-background-jobs"
|
|
106
|
-
}})
|
|
109
|
+
}, status: health.ready ? 200 : 503})
|
|
107
110
|
})
|
|
108
111
|
}
|
|
109
112
|
|
|
@@ -10,6 +10,7 @@ import {randomUUID} from "crypto"
|
|
|
10
10
|
import {fileURLToPath} from "node:url"
|
|
11
11
|
import shutdownLifecycle from "../utils/shutdown-lifecycle.js"
|
|
12
12
|
import BackgroundJobRescheduleSignal from "./reschedule-signal.js"
|
|
13
|
+
import performBackgroundJob from "./perform-job.js"
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Per-forked-child timeout bookkeeping.
|
|
@@ -958,14 +959,11 @@ export default class BackgroundJobsWorker {
|
|
|
958
959
|
const registry = new BackgroundJobRegistry({configuration})
|
|
959
960
|
await registry.load()
|
|
960
961
|
const JobClass = registry.getJobByName(payload.jobName)
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
await configuration.withConnections({databaseIdentifiers: JobClass.databaseIdentifiers, name: `Background job worker inline: ${payload.jobName}`}, async () => {
|
|
968
|
-
await perform.apply(jobInstance, payload.args || [])
|
|
962
|
+
await performBackgroundJob({
|
|
963
|
+
configuration,
|
|
964
|
+
JobClass,
|
|
965
|
+
jobArgs: payload.args || [],
|
|
966
|
+
name: `Background job worker inline: ${payload.jobName}`
|
|
969
967
|
})
|
|
970
968
|
}
|
|
971
969
|
|
|
@@ -156,8 +156,13 @@
|
|
|
156
156
|
* `background_jobs` table (see `pollIntervalMs`).
|
|
157
157
|
*/
|
|
158
158
|
|
|
159
|
+
/** @typedef {"background" | "inline"} BackgroundJobsMode */
|
|
160
|
+
/** @typedef {(args: {configuration: import("./configuration.js").default}) => import("./background-jobs/adapter.js").default} BackgroundJobsAdapterFactory */
|
|
161
|
+
|
|
159
162
|
/**
|
|
160
163
|
* @typedef {object} BackgroundJobsConfiguration
|
|
164
|
+
* @property {import("./background-jobs/adapter.js").default | BackgroundJobsAdapterFactory} [adapter] - Adapter instance or synchronous factory. A factory creates one adapter per configuration lifecycle; the framework closes adapters it resolves.
|
|
165
|
+
* @property {BackgroundJobsMode} [mode] - `"background"` uses the configured adapter/transport and durable queue semantics; `"inline"` performs immediately without durable queue state. Defaults to `"background"`.
|
|
161
166
|
* @property {string} [host] - Hostname for the background jobs main process.
|
|
162
167
|
* @property {number} [port] - Port for the background jobs main process.
|
|
163
168
|
* @property {string} [databaseIdentifier] - Database identifier used to store background jobs.
|