velocious 1.0.627 → 1.0.628

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.
Files changed (37) hide show
  1. package/README.md +1 -1
  2. package/build/background-jobs/job-runner.js +9 -1
  3. package/build/background-jobs/local-dispatcher.js +23 -1
  4. package/build/background-jobs/main.js +6 -4
  5. package/build/background-jobs/perform-job.js +10 -1
  6. package/build/background-jobs/platform-job.js +62 -0
  7. package/build/background-jobs/runtime.js +6 -3
  8. package/build/background-jobs/types.js +8 -0
  9. package/build/background-jobs/worker.js +3 -1
  10. package/build/src/background-jobs/job-runner.d.ts.map +1 -1
  11. package/build/src/background-jobs/job-runner.js +10 -2
  12. package/build/src/background-jobs/local-dispatcher.d.ts.map +1 -1
  13. package/build/src/background-jobs/local-dispatcher.js +24 -2
  14. package/build/src/background-jobs/main.d.ts.map +1 -1
  15. package/build/src/background-jobs/main.js +7 -5
  16. package/build/src/background-jobs/perform-job.d.ts +5 -1
  17. package/build/src/background-jobs/perform-job.d.ts.map +1 -1
  18. package/build/src/background-jobs/perform-job.js +11 -2
  19. package/build/src/background-jobs/platform-job.d.ts +34 -0
  20. package/build/src/background-jobs/platform-job.d.ts.map +1 -1
  21. package/build/src/background-jobs/platform-job.js +56 -1
  22. package/build/src/background-jobs/runtime.d.ts.map +1 -1
  23. package/build/src/background-jobs/runtime.js +7 -4
  24. package/build/src/background-jobs/types.d.ts +30 -0
  25. package/build/src/background-jobs/types.d.ts.map +1 -1
  26. package/build/src/background-jobs/types.js +9 -1
  27. package/build/src/background-jobs/worker.d.ts.map +1 -1
  28. package/build/src/background-jobs/worker.js +4 -2
  29. package/package.json +1 -1
  30. package/src/background-jobs/job-runner.js +9 -1
  31. package/src/background-jobs/local-dispatcher.js +23 -1
  32. package/src/background-jobs/main.js +6 -4
  33. package/src/background-jobs/perform-job.js +10 -1
  34. package/src/background-jobs/platform-job.js +62 -0
  35. package/src/background-jobs/runtime.js +6 -3
  36. package/src/background-jobs/types.js +8 -0
  37. package/src/background-jobs/worker.js +3 -1
@@ -93,6 +93,14 @@ export default async function runJobPayload(payload, {closeConnections = true, m
93
93
  await registry.load()
94
94
  const JobClass = registry.getJobByName(payload.jobName)
95
95
  const jobInstance = new JobClass()
96
+ const jobArgs = payload.args || []
97
+ jobInstance._setBackgroundJobContext({
98
+ args: jobArgs,
99
+ jobClass: JobClass,
100
+ jobName: payload.jobName,
101
+ options: payload.options || {},
102
+ payload
103
+ })
96
104
  /**
97
105
  * Perform.
98
106
  * @type {(...args: Array<ReturnType<typeof JSON.parse>>) => Promise<void>} */
@@ -107,7 +115,7 @@ export default async function runJobPayload(payload, {closeConnections = true, m
107
115
  try {
108
116
  try {
109
117
  await configuration.withConnections({databaseIdentifiers: JobClass.databaseIdentifiers, name: `Background job runner: ${payload.jobName}`}, async () => {
110
- await perform.apply(jobInstance, payload.args || [])
118
+ await perform.apply(jobInstance, jobArgs)
111
119
  })
112
120
  } catch (error) {
113
121
  if (error instanceof BackgroundJobRescheduleSignal) {
@@ -184,7 +184,29 @@ export default class LocalBackgroundJobsDispatcher {
184
184
  configuration: this.configuration,
185
185
  JobClass,
186
186
  jobArgs: job.args,
187
- name: `Local background job: ${job.jobName}`
187
+ jobOptions: {
188
+ concurrencyKey: job.concurrencyKey || undefined,
189
+ executionMode: job.executionMode,
190
+ maxConcurrency: job.maxConcurrency ?? undefined,
191
+ maxRetries: job.maxRetries ?? undefined,
192
+ queue: job.queue,
193
+ scheduledAtMs: job.scheduledAtMs ?? undefined,
194
+ timeoutMs: job.timeoutMs ?? undefined
195
+ },
196
+ name: `Local background job: ${job.jobName}`,
197
+ payload: {
198
+ args: job.args,
199
+ handedOffAtMs: handoff.handedOffAtMs,
200
+ handoffId: handoff.handoffId,
201
+ id: job.id,
202
+ jobName: job.jobName,
203
+ options: {
204
+ concurrencyKey: job.concurrencyKey || undefined,
205
+ executionMode: job.executionMode,
206
+ maxConcurrency: job.maxConcurrency ?? undefined,
207
+ queue: job.queue
208
+ }
209
+ }
188
210
  })
189
211
  } catch (error) {
190
212
  if (error instanceof BackgroundJobRescheduleSignal) {
@@ -223,10 +223,7 @@ export default class BackgroundJobsMain {
223
223
  await this.store.enqueue({
224
224
  jobName: jobClass.jobName(),
225
225
  args,
226
- // Fold in the job class's static `queue` (as performLater* do) so a
227
- // scheduled job with `static queue = "..."` lands on its queue and
228
- // honors the configured cap without every schedule repeating it.
229
- options: jobClass._withQueue(options)
226
+ options: jobClass._withJobContext({jobArgs: args, jobOptions: options})
230
227
  })
231
228
  this._notifyEnqueued()
232
229
  // Persistence is the scheduler enqueue boundary. Dispatch remains
@@ -1400,7 +1397,12 @@ export default class BackgroundJobsMain {
1400
1397
  workerId: worker.workerId,
1401
1398
  handedOffAtMs: handoff.handedOffAtMs,
1402
1399
  options: {
1400
+ concurrencyKey: job.concurrencyKey || undefined,
1403
1401
  executionMode: job.executionMode,
1402
+ maxConcurrency: job.maxConcurrency ?? undefined,
1403
+ maxRetries: job.maxRetries ?? undefined,
1404
+ queue: job.queue,
1405
+ scheduledAtMs: job.scheduledAtMs ?? undefined,
1404
1406
  ...(job.timeoutMs === null ? {} : {timeoutMs: job.timeoutMs})
1405
1407
  }
1406
1408
  }
@@ -6,11 +6,20 @@
6
6
  * @param {import("../configuration.js").default} args.configuration - Active configuration.
7
7
  * @param {typeof import("./platform-job.js").default} args.JobClass - Job class.
8
8
  * @param {Array<ReturnType<typeof JSON.parse>>} args.jobArgs - Job arguments.
9
+ * @param {import("./types.js").BackgroundJobOptions} [args.jobOptions] - Resolved runtime options.
9
10
  * @param {string} args.name - Connection-scope label.
11
+ * @param {import("./types.js").BackgroundJobPayload} [args.payload] - Persisted runner payload.
10
12
  * @returns {Promise<void>} - Resolves after performance.
11
13
  */
12
- export default async function performBackgroundJob({configuration, JobClass, jobArgs, name}) {
14
+ export default async function performBackgroundJob({configuration, JobClass, jobArgs, jobOptions = {}, name, payload}) {
13
15
  const jobInstance = new JobClass()
16
+ jobInstance._setBackgroundJobContext({
17
+ args: jobArgs,
18
+ jobClass: JobClass,
19
+ jobName: JobClass.jobName(),
20
+ options: jobOptions,
21
+ ...(payload ? {payload} : {})
22
+ })
14
23
  /**
15
24
  * Narrows the generic subclass's runtime method to serialized job arguments.
16
25
  * @type {(...args: Array<ReturnType<typeof JSON.parse>>) => Promise<void>}
@@ -14,6 +14,11 @@ import {cancelScheduledBackgroundJob, enqueueBackgroundJob, replaceScheduledBack
14
14
  * @template {Array<ReturnType<typeof JSON.parse>>} [TArgs=[]]
15
15
  */
16
16
  export default class VelociousJob {
17
+ constructor() {
18
+ /** @type {import("./types.js").BackgroundJobContext | undefined} */
19
+ this._backgroundJobContext = undefined
20
+ }
21
+
17
22
  /**
18
23
  * Database identifiers checked out while this job performs. Set an explicit
19
24
  * list to avoid holding unrelated configured database connections, or `[]`
@@ -82,6 +87,63 @@ export default class VelociousJob {
82
87
  return merged
83
88
  }
84
89
 
90
+ /**
91
+ * Resolves class-derived enqueue options on a hydrated job instance. Explicit
92
+ * per-enqueue options take precedence over the instance concurrency key.
93
+ * @param {object} args - Job context.
94
+ * @param {Array<ReturnType<typeof JSON.parse>>} args.jobArgs - Job arguments.
95
+ * @param {import("./types.js").BackgroundJobOptions | undefined} args.jobOptions - Job options.
96
+ * @returns {import("./types.js").BackgroundJobOptions} - Resolved job options.
97
+ */
98
+ static _withJobContext({jobArgs, jobOptions}) {
99
+ const options = this._withQueue(jobOptions)
100
+
101
+ if (options.concurrencyKey !== undefined) return options
102
+
103
+ const jobInstance = new this()
104
+ jobInstance._setBackgroundJobContext({
105
+ args: jobArgs,
106
+ jobClass: this,
107
+ jobName: this.jobName(),
108
+ options
109
+ })
110
+ const concurrencyKey = jobInstance.concurrencyKey()
111
+
112
+ if (concurrencyKey !== undefined) options.concurrencyKey = concurrencyKey
113
+
114
+ return options
115
+ }
116
+
117
+ /**
118
+ * Sets the complete context available to this hydrated job instance.
119
+ * Framework enqueue/runner boundaries own this method.
120
+ * @param {import("./types.js").BackgroundJobContext} context - Job context.
121
+ * @returns {void}
122
+ */
123
+ _setBackgroundJobContext(context) {
124
+ this._backgroundJobContext = context
125
+ }
126
+
127
+ /**
128
+ * Returns this hydrated job's complete enqueue or runner context.
129
+ * @returns {import("./types.js").BackgroundJobContext} - Job context.
130
+ */
131
+ backgroundJobContext() {
132
+ if (!this._backgroundJobContext) throw new Error("Background job context is not hydrated")
133
+
134
+ return this._backgroundJobContext
135
+ }
136
+
137
+ /**
138
+ * Override to derive a durable concurrency key from `backgroundJobContext()`.
139
+ * Pair the derived key with `maxConcurrency` in enqueue options. An explicit
140
+ * per-enqueue `concurrencyKey` takes precedence and skips this method.
141
+ * @returns {string | undefined} - Derived concurrency key, or undefined for none.
142
+ */
143
+ concurrencyKey() {
144
+ return undefined
145
+ }
146
+
85
147
  /**
86
148
  * Runs perform later.
87
149
  * @param {...ReturnType<typeof JSON.parse>} args - Job args.
@@ -52,9 +52,10 @@ export async function enqueueBackgroundJob({JobClass, jobArgs, jobOptions}) {
52
52
  * @returns {Promise<string>} - Durable job id or ephemeral inline performance id.
53
53
  */
54
54
  export async function enqueueBackgroundJobForConfiguration({configuration, JobClass, jobArgs, jobOptions}) {
55
+ const resolvedJobOptions = JobClass._withJobContext({jobArgs, jobOptions})
55
56
 
56
57
  if (configuration.getBackgroundJobsConfig().mode === "inline") {
57
- validateInlineOptions(jobOptions)
58
+ validateInlineOptions(resolvedJobOptions)
58
59
  configuration.setCurrent()
59
60
  await configuration.initialize({type: "background-jobs-inline"})
60
61
 
@@ -63,6 +64,7 @@ export async function enqueueBackgroundJobForConfiguration({configuration, JobCl
63
64
  configuration,
64
65
  JobClass,
65
66
  jobArgs,
67
+ jobOptions: resolvedJobOptions,
66
68
  name: `Background job inline mode: ${JobClass.jobName()}`
67
69
  })
68
70
  } catch (error) {
@@ -81,7 +83,7 @@ export async function enqueueBackgroundJobForConfiguration({configuration, JobCl
81
83
  return await client.enqueue({
82
84
  jobName: JobClass.jobName(),
83
85
  args: jobArgs,
84
- options: JobClass._withQueue(jobOptions)
86
+ options: resolvedJobOptions
85
87
  })
86
88
  }
87
89
 
@@ -117,12 +119,13 @@ export async function replaceScheduledBackgroundJobForConfiguration({configurati
117
119
  }
118
120
 
119
121
  const client = configuration.getEnvironmentHandler().backgroundJobsClient({configuration})
122
+ const resolvedJobOptions = JobClass._withJobContext({jobArgs, jobOptions})
120
123
 
121
124
  return await client.replaceScheduled({
122
125
  scheduleKey,
123
126
  jobName: JobClass.jobName(),
124
127
  args: jobArgs,
125
- options: JobClass._withQueue(jobOptions)
128
+ options: resolvedJobOptions
126
129
  })
127
130
  }
128
131
 
@@ -71,6 +71,14 @@
71
71
  * @property {number} [handedOffAtMs] - Time handed to a worker in ms.
72
72
  * @property {BackgroundJobOptions} [options] - Runtime options.
73
73
  */
74
+ /**
75
+ * @typedef {object} BackgroundJobContext
76
+ * @property {typeof import("./platform-job.js").default} jobClass - Concrete job class.
77
+ * @property {string} jobName - Registered job name.
78
+ * @property {Array<ReturnType<typeof JSON.parse>>} args - Serialized job arguments.
79
+ * @property {BackgroundJobOptions} options - Resolved enqueue/runtime options.
80
+ * @property {BackgroundJobPayload} [payload] - Complete persisted runner payload when the job is performing.
81
+ */
74
82
  /**
75
83
  * @typedef {object} BackgroundJobRow
76
84
  * @property {string} id - Job id.
@@ -1054,7 +1054,9 @@ export default class BackgroundJobsWorker {
1054
1054
  configuration,
1055
1055
  JobClass,
1056
1056
  jobArgs: payload.args || [],
1057
- name: `Background job worker inline: ${payload.jobName}`
1057
+ jobOptions: payload.options || {},
1058
+ name: `Background job worker inline: ${payload.jobName}`,
1059
+ payload
1058
1060
  })
1059
1061
  }
1060
1062