nmtjs 0.16.1 → 0.17.0-beta.2
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/LICENSE.md +1 -1
- package/README.md +41 -1
- package/dist/index.d.ts +22 -161
- package/dist/index.js +24 -53
- package/dist/index.js.map +1 -1
- package/package.json +11 -63
- package/src/index.ts +71 -91
- package/bin/cli.js +0 -2
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +0 -137
- package/dist/cli.js.map +0 -1
- package/dist/codegen.d.ts +0 -5
- package/dist/codegen.js +0 -18
- package/dist/codegen.js.map +0 -1
- package/dist/config.d.ts +0 -47
- package/dist/config.js +0 -16
- package/dist/config.js.map +0 -1
- package/dist/entrypoints/cli.d.ts +0 -1
- package/dist/entrypoints/cli.js +0 -12
- package/dist/entrypoints/cli.js.map +0 -1
- package/dist/entrypoints/main.d.ts +0 -5
- package/dist/entrypoints/main.js +0 -248
- package/dist/entrypoints/main.js.map +0 -1
- package/dist/entrypoints/thread.d.ts +0 -16
- package/dist/entrypoints/thread.js +0 -182
- package/dist/entrypoints/thread.js.map +0 -1
- package/dist/entrypoints/worker.d.ts +0 -9
- package/dist/entrypoints/worker.js +0 -143
- package/dist/entrypoints/worker.js.map +0 -1
- package/dist/resolver.d.ts +0 -2
- package/dist/resolver.js +0 -7
- package/dist/resolver.js.map +0 -1
- package/dist/runtime/application/index.d.ts +0 -1
- package/dist/runtime/application/index.js +0 -2
- package/dist/runtime/application/index.js.map +0 -1
- package/dist/runtime/constants.d.ts +0 -8
- package/dist/runtime/constants.js +0 -5
- package/dist/runtime/constants.js.map +0 -1
- package/dist/runtime/enums.d.ts +0 -10
- package/dist/runtime/enums.js +0 -13
- package/dist/runtime/enums.js.map +0 -1
- package/dist/runtime/hooks.d.ts +0 -1
- package/dist/runtime/hooks.js +0 -2
- package/dist/runtime/hooks.js.map +0 -1
- package/dist/runtime/index.d.ts +0 -28
- package/dist/runtime/index.js +0 -29
- package/dist/runtime/index.js.map +0 -1
- package/dist/runtime/injectables.d.ts +0 -69
- package/dist/runtime/injectables.js +0 -40
- package/dist/runtime/injectables.js.map +0 -1
- package/dist/runtime/jobs/job.d.ts +0 -146
- package/dist/runtime/jobs/job.js +0 -89
- package/dist/runtime/jobs/job.js.map +0 -1
- package/dist/runtime/jobs/manager.d.ts +0 -131
- package/dist/runtime/jobs/manager.js +0 -309
- package/dist/runtime/jobs/manager.js.map +0 -1
- package/dist/runtime/jobs/router.d.ts +0 -296
- package/dist/runtime/jobs/router.js +0 -458
- package/dist/runtime/jobs/router.js.map +0 -1
- package/dist/runtime/jobs/runner.d.ts +0 -103
- package/dist/runtime/jobs/runner.js +0 -425
- package/dist/runtime/jobs/runner.js.map +0 -1
- package/dist/runtime/jobs/step.d.ts +0 -26
- package/dist/runtime/jobs/step.js +0 -18
- package/dist/runtime/jobs/step.js.map +0 -1
- package/dist/runtime/jobs/types.d.ts +0 -86
- package/dist/runtime/jobs/types.js +0 -5
- package/dist/runtime/jobs/types.js.map +0 -1
- package/dist/runtime/metrics/metric.d.ts +0 -8
- package/dist/runtime/metrics/metric.js +0 -11
- package/dist/runtime/metrics/metric.js.map +0 -1
- package/dist/runtime/metrics/registry.d.ts +0 -3
- package/dist/runtime/metrics/registry.js +0 -5
- package/dist/runtime/metrics/registry.js.map +0 -1
- package/dist/runtime/metrics/server.d.ts +0 -7
- package/dist/runtime/metrics/server.js +0 -53
- package/dist/runtime/metrics/server.js.map +0 -1
- package/dist/runtime/plugin.d.ts +0 -2
- package/dist/runtime/plugin.js +0 -2
- package/dist/runtime/plugin.js.map +0 -1
- package/dist/runtime/runtime.d.ts +0 -27
- package/dist/runtime/runtime.js +0 -77
- package/dist/runtime/runtime.js.map +0 -1
- package/dist/runtime/scheduler/index.d.ts +0 -22
- package/dist/runtime/scheduler/index.js +0 -20
- package/dist/runtime/scheduler/index.js.map +0 -1
- package/dist/runtime/server/applications.d.ts +0 -91
- package/dist/runtime/server/applications.js +0 -171
- package/dist/runtime/server/applications.js.map +0 -1
- package/dist/runtime/server/config.d.ts +0 -148
- package/dist/runtime/server/config.js +0 -33
- package/dist/runtime/server/config.js.map +0 -1
- package/dist/runtime/server/environment.d.ts +0 -43
- package/dist/runtime/server/environment.js +0 -33
- package/dist/runtime/server/environment.js.map +0 -1
- package/dist/runtime/server/error-policy.d.ts +0 -62
- package/dist/runtime/server/error-policy.js +0 -73
- package/dist/runtime/server/error-policy.js.map +0 -1
- package/dist/runtime/server/hmr-coordinator.d.ts +0 -37
- package/dist/runtime/server/hmr-coordinator.js +0 -94
- package/dist/runtime/server/hmr-coordinator.js.map +0 -1
- package/dist/runtime/server/jobs.d.ts +0 -54
- package/dist/runtime/server/jobs.js +0 -176
- package/dist/runtime/server/jobs.js.map +0 -1
- package/dist/runtime/server/lifecycle.d.ts +0 -85
- package/dist/runtime/server/lifecycle.js +0 -177
- package/dist/runtime/server/lifecycle.js.map +0 -1
- package/dist/runtime/server/managed-worker.d.ts +0 -158
- package/dist/runtime/server/managed-worker.js +0 -420
- package/dist/runtime/server/managed-worker.js.map +0 -1
- package/dist/runtime/server/pool-manager.d.ts +0 -85
- package/dist/runtime/server/pool-manager.js +0 -129
- package/dist/runtime/server/pool-manager.js.map +0 -1
- package/dist/runtime/server/proxy.d.ts +0 -21
- package/dist/runtime/server/proxy.js +0 -76
- package/dist/runtime/server/proxy.js.map +0 -1
- package/dist/runtime/server/server.d.ts +0 -60
- package/dist/runtime/server/server.js +0 -163
- package/dist/runtime/server/server.js.map +0 -1
- package/dist/runtime/server/types.d.ts +0 -31
- package/dist/runtime/server/types.js +0 -2
- package/dist/runtime/server/types.js.map +0 -1
- package/dist/runtime/server/worker-pool.d.ts +0 -121
- package/dist/runtime/server/worker-pool.js +0 -171
- package/dist/runtime/server/worker-pool.js.map +0 -1
- package/dist/runtime/store/index.d.ts +0 -3
- package/dist/runtime/store/index.js +0 -23
- package/dist/runtime/store/index.js.map +0 -1
- package/dist/runtime/subscription/manager.d.ts +0 -49
- package/dist/runtime/subscription/manager.js +0 -170
- package/dist/runtime/subscription/manager.js.map +0 -1
- package/dist/runtime/subscription/redis.d.ts +0 -18
- package/dist/runtime/subscription/redis.js +0 -119
- package/dist/runtime/subscription/redis.js.map +0 -1
- package/dist/runtime/types.d.ts +0 -95
- package/dist/runtime/types.js +0 -2
- package/dist/runtime/types.js.map +0 -1
- package/dist/runtime/workers/application.d.ts +0 -29
- package/dist/runtime/workers/application.js +0 -77
- package/dist/runtime/workers/application.js.map +0 -1
- package/dist/runtime/workers/base.d.ts +0 -14
- package/dist/runtime/workers/base.js +0 -41
- package/dist/runtime/workers/base.js.map +0 -1
- package/dist/runtime/workers/cli.d.ts +0 -1
- package/dist/runtime/workers/cli.js +0 -2
- package/dist/runtime/workers/cli.js.map +0 -1
- package/dist/runtime/workers/job.d.ts +0 -20
- package/dist/runtime/workers/job.js +0 -170
- package/dist/runtime/workers/job.js.map +0 -1
- package/dist/vite/builder.d.ts +0 -5
- package/dist/vite/builder.js +0 -79
- package/dist/vite/builder.js.map +0 -1
- package/dist/vite/config.d.ts +0 -28
- package/dist/vite/config.js +0 -22
- package/dist/vite/config.js.map +0 -1
- package/dist/vite/plugins.d.ts +0 -2
- package/dist/vite/plugins.js +0 -43
- package/dist/vite/plugins.js.map +0 -1
- package/dist/vite/runners/worker.d.ts +0 -3
- package/dist/vite/runners/worker.js +0 -34
- package/dist/vite/runners/worker.js.map +0 -1
- package/dist/vite/server.d.ts +0 -3
- package/dist/vite/server.js +0 -36
- package/dist/vite/server.js.map +0 -1
- package/dist/vite/servers/main.d.ts +0 -8
- package/dist/vite/servers/main.js +0 -24
- package/dist/vite/servers/main.js.map +0 -1
- package/dist/vite/servers/worker.d.ts +0 -13
- package/dist/vite/servers/worker.js +0 -124
- package/dist/vite/servers/worker.js.map +0 -1
- package/src/cli.ts +0 -162
- package/src/codegen.ts +0 -30
- package/src/config.ts +0 -69
- package/src/entrypoints/cli.ts +0 -13
- package/src/entrypoints/main.ts +0 -317
- package/src/entrypoints/thread.ts +0 -223
- package/src/entrypoints/worker.ts +0 -174
- package/src/resolver.ts +0 -7
- package/src/runtime/application/index.ts +0 -1
- package/src/runtime/constants.ts +0 -13
- package/src/runtime/enums.ts +0 -12
- package/src/runtime/hooks.ts +0 -1
- package/src/runtime/index.ts +0 -29
- package/src/runtime/injectables.ts +0 -101
- package/src/runtime/jobs/job.ts +0 -467
- package/src/runtime/jobs/manager.ts +0 -454
- package/src/runtime/jobs/router.ts +0 -967
- package/src/runtime/jobs/runner.ts +0 -583
- package/src/runtime/jobs/step.ts +0 -66
- package/src/runtime/jobs/types.ts +0 -116
- package/src/runtime/metrics/metric.ts +0 -18
- package/src/runtime/metrics/registry.ts +0 -11
- package/src/runtime/metrics/server.ts +0 -69
- package/src/runtime/plugin.ts +0 -2
- package/src/runtime/runtime.ts +0 -103
- package/src/runtime/scheduler/index.ts +0 -39
- package/src/runtime/server/applications.ts +0 -264
- package/src/runtime/server/config.ts +0 -199
- package/src/runtime/server/environment.ts +0 -71
- package/src/runtime/server/error-policy.ts +0 -132
- package/src/runtime/server/hmr-coordinator.ts +0 -116
- package/src/runtime/server/jobs.ts +0 -266
- package/src/runtime/server/lifecycle.ts +0 -234
- package/src/runtime/server/managed-worker.ts +0 -546
- package/src/runtime/server/pool-manager.ts +0 -187
- package/src/runtime/server/proxy.ts +0 -119
- package/src/runtime/server/server.ts +0 -218
- package/src/runtime/server/types.ts +0 -32
- package/src/runtime/server/worker-pool.ts +0 -275
- package/src/runtime/store/index.ts +0 -30
- package/src/runtime/subscription/manager.ts +0 -307
- package/src/runtime/subscription/redis.ts +0 -159
- package/src/runtime/types.ts +0 -84
- package/src/runtime/workers/application.ts +0 -133
- package/src/runtime/workers/base.ts +0 -65
- package/src/runtime/workers/cli.ts +0 -0
- package/src/runtime/workers/job.ts +0 -142
- package/src/vite/builder.ts +0 -94
- package/src/vite/config.ts +0 -45
- package/src/vite/plugins.ts +0 -53
- package/src/vite/runners/worker.ts +0 -55
- package/src/vite/server.ts +0 -55
- package/src/vite/servers/main.ts +0 -41
- package/src/vite/servers/worker.ts +0 -177
|
@@ -1,583 +0,0 @@
|
|
|
1
|
-
import type { LifecycleHooks } from '@nmtjs/application'
|
|
2
|
-
import type { Container, Logger, LoggingOptions } from '@nmtjs/core'
|
|
3
|
-
import type { Job } from 'bullmq'
|
|
4
|
-
import { LifecycleHook } from '@nmtjs/application'
|
|
5
|
-
import { anyAbortSignal } from '@nmtjs/common'
|
|
6
|
-
import { Scope } from '@nmtjs/core'
|
|
7
|
-
import { UnrecoverableError } from 'bullmq'
|
|
8
|
-
|
|
9
|
-
import type { AnyJob } from './job.ts'
|
|
10
|
-
import type { AnyJobStep } from './step.ts'
|
|
11
|
-
import type {
|
|
12
|
-
JobExecutionContext,
|
|
13
|
-
JobProgressCheckpoint,
|
|
14
|
-
StepResultEntry,
|
|
15
|
-
} from './types.ts'
|
|
16
|
-
import {
|
|
17
|
-
currentJobInfo,
|
|
18
|
-
jobAbortSignal,
|
|
19
|
-
saveJobProgress,
|
|
20
|
-
} from '../injectables.ts'
|
|
21
|
-
|
|
22
|
-
export type JobRunnerOptions = { logging?: LoggingOptions }
|
|
23
|
-
|
|
24
|
-
export type { StepResultEntry } from './types.ts'
|
|
25
|
-
|
|
26
|
-
export interface JobRunnerRunOptions {
|
|
27
|
-
signal: AbortSignal
|
|
28
|
-
result: Record<string, unknown>
|
|
29
|
-
stepResults: StepResultEntry[]
|
|
30
|
-
currentStepIndex: number
|
|
31
|
-
progress: Record<string, unknown>
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export interface JobRunnerRunBeforeStepParams<
|
|
35
|
-
Options extends JobRunnerRunOptions,
|
|
36
|
-
> {
|
|
37
|
-
job: AnyJob
|
|
38
|
-
step: AnyJobStep
|
|
39
|
-
stepIndex: number
|
|
40
|
-
result: Record<string, unknown>
|
|
41
|
-
stepResults: StepResultEntry[]
|
|
42
|
-
options: Options
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export interface JobRunnerRunAfterStepParams<
|
|
46
|
-
Options extends JobRunnerRunOptions,
|
|
47
|
-
> extends JobRunnerRunBeforeStepParams<Options> {
|
|
48
|
-
stepResult: StepResultEntry
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/** Context for saveProgress function - contains mutable state references */
|
|
52
|
-
export interface SaveProgressContext<
|
|
53
|
-
Options extends JobRunnerRunOptions = JobRunnerRunOptions,
|
|
54
|
-
> {
|
|
55
|
-
job: AnyJob
|
|
56
|
-
progress: Record<string, unknown>
|
|
57
|
-
result: Record<string, unknown>
|
|
58
|
-
stepResults: StepResultEntry[] | null
|
|
59
|
-
currentStepIndex: number
|
|
60
|
-
options: Options | null
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export class JobRunner<
|
|
64
|
-
RunOptions extends JobRunnerRunOptions = JobRunnerRunOptions,
|
|
65
|
-
> {
|
|
66
|
-
logger: Logger
|
|
67
|
-
|
|
68
|
-
constructor(
|
|
69
|
-
protected runtime: {
|
|
70
|
-
logger: Logger
|
|
71
|
-
container: Container
|
|
72
|
-
lifecycleHooks: LifecycleHooks
|
|
73
|
-
},
|
|
74
|
-
) {
|
|
75
|
-
this.logger = runtime.logger.child({ $group: JobRunner.name })
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
get container() {
|
|
79
|
-
return this.runtime.container
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Creates a function that saves the current job progress state.
|
|
84
|
-
* Override in subclasses to implement actual persistence.
|
|
85
|
-
*/
|
|
86
|
-
protected createSaveProgressFn(
|
|
87
|
-
_context: SaveProgressContext<RunOptions>,
|
|
88
|
-
): () => Promise<void> {
|
|
89
|
-
// No-op in base runner - subclasses implement actual persistence
|
|
90
|
-
return async () => {}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Creates the current job info object.
|
|
95
|
-
* Override in subclasses to include additional info (e.g., BullMQ job ID).
|
|
96
|
-
*/
|
|
97
|
-
protected createJobInfo(
|
|
98
|
-
job: AnyJob,
|
|
99
|
-
_options: Partial<RunOptions>,
|
|
100
|
-
): JobExecutionContext {
|
|
101
|
-
return { name: job.options.name }
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
async runJob<T extends AnyJob>(
|
|
105
|
-
job: T,
|
|
106
|
-
data: any,
|
|
107
|
-
options: Partial<RunOptions> = {},
|
|
108
|
-
): Promise<T['_']['output']> {
|
|
109
|
-
const {
|
|
110
|
-
signal: runSignal,
|
|
111
|
-
result: runResult = {},
|
|
112
|
-
stepResults: runStepResults = [] as RunOptions['stepResults'],
|
|
113
|
-
progress: runProgress = {},
|
|
114
|
-
currentStepIndex = 0,
|
|
115
|
-
...rest
|
|
116
|
-
} = options
|
|
117
|
-
|
|
118
|
-
const { input, output, jobSteps: steps } = job
|
|
119
|
-
|
|
120
|
-
const result: Record<string, unknown> = { ...runResult }
|
|
121
|
-
const decodedInput = input.decode(data)
|
|
122
|
-
|
|
123
|
-
// Initialize progress: decode from checkpoint or start fresh
|
|
124
|
-
const progress: Record<string, unknown> = job.progress
|
|
125
|
-
? job.progress.decode(runProgress)
|
|
126
|
-
: { ...runProgress }
|
|
127
|
-
|
|
128
|
-
using stopListener = this.runtime.lifecycleHooks.once(
|
|
129
|
-
LifecycleHook.BeforeDispose,
|
|
130
|
-
)
|
|
131
|
-
const signal = anyAbortSignal(runSignal, stopListener.signal)
|
|
132
|
-
await using container = this.container.fork(Scope.Global)
|
|
133
|
-
container.provide(jobAbortSignal, signal)
|
|
134
|
-
container.provide(currentJobInfo, this.createJobInfo(job, options))
|
|
135
|
-
|
|
136
|
-
// Create mutable state context for saveProgress
|
|
137
|
-
const progressContext = {
|
|
138
|
-
job,
|
|
139
|
-
progress,
|
|
140
|
-
result,
|
|
141
|
-
stepResults: null as StepResultEntry[] | null, // Will be set below
|
|
142
|
-
currentStepIndex,
|
|
143
|
-
options: null as RunOptions | null, // Will be set below
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// Provide saveProgress injectable
|
|
147
|
-
container.provide(
|
|
148
|
-
saveJobProgress,
|
|
149
|
-
this.createSaveProgressFn(progressContext),
|
|
150
|
-
)
|
|
151
|
-
|
|
152
|
-
const jobDependencyContext = await container.createContext(job.dependencies)
|
|
153
|
-
const jobData = job.options.data
|
|
154
|
-
? await job.options.data(jobDependencyContext, decodedInput, progress)
|
|
155
|
-
: undefined
|
|
156
|
-
|
|
157
|
-
const stepResults: StepResultEntry[] = Array.from({ length: steps.length })
|
|
158
|
-
|
|
159
|
-
// Restore previous step results and reconstruct accumulated result
|
|
160
|
-
for (let stepIndex = 0; stepIndex < runStepResults.length; stepIndex++) {
|
|
161
|
-
const entry = runStepResults[stepIndex]
|
|
162
|
-
stepResults[stepIndex] = entry
|
|
163
|
-
if (entry?.data) Object.assign(result, entry.data)
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// @ts-expect-error
|
|
167
|
-
const runOptions: RunOptions = {
|
|
168
|
-
signal,
|
|
169
|
-
result,
|
|
170
|
-
stepResults,
|
|
171
|
-
currentStepIndex: currentStepIndex,
|
|
172
|
-
progress,
|
|
173
|
-
...rest,
|
|
174
|
-
} satisfies JobRunnerRunOptions
|
|
175
|
-
|
|
176
|
-
// Update mutable context references
|
|
177
|
-
progressContext.stepResults = stepResults
|
|
178
|
-
progressContext.options = runOptions
|
|
179
|
-
|
|
180
|
-
for (let stepIndex = currentStepIndex; stepIndex < steps.length; ) {
|
|
181
|
-
if (signal.aborted) {
|
|
182
|
-
const { reason } = signal
|
|
183
|
-
if (reason instanceof UnrecoverableError) throw reason
|
|
184
|
-
throw new UnrecoverableError('Job cancelled')
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
const groupStart = job.parallelGroupByStepIndex.get(stepIndex)
|
|
188
|
-
|
|
189
|
-
if (groupStart !== undefined) {
|
|
190
|
-
const groupEnd = job.parallelGroups.get(groupStart) ?? groupStart + 1
|
|
191
|
-
const resultSnapshot = Object.freeze(
|
|
192
|
-
Object.assign({}, decodedInput, result),
|
|
193
|
-
)
|
|
194
|
-
|
|
195
|
-
const pending = [] as number[]
|
|
196
|
-
for (let index = groupStart; index < groupEnd; index++) {
|
|
197
|
-
if (!stepResults[index]) pending.push(index)
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
if (pending.length > 0) {
|
|
201
|
-
const settled = await Promise.all(
|
|
202
|
-
pending.map(async (index) => {
|
|
203
|
-
const step = steps[index]
|
|
204
|
-
try {
|
|
205
|
-
const produced = await this.runStep({
|
|
206
|
-
job,
|
|
207
|
-
step,
|
|
208
|
-
stepIndex: index,
|
|
209
|
-
result,
|
|
210
|
-
resultSnapshot,
|
|
211
|
-
decodedInput,
|
|
212
|
-
progress,
|
|
213
|
-
stepResults,
|
|
214
|
-
options: runOptions,
|
|
215
|
-
jobDependencyContext,
|
|
216
|
-
jobData,
|
|
217
|
-
container,
|
|
218
|
-
applyResult: false,
|
|
219
|
-
})
|
|
220
|
-
return { index, produced }
|
|
221
|
-
} catch (error) {
|
|
222
|
-
return { index, error }
|
|
223
|
-
}
|
|
224
|
-
}),
|
|
225
|
-
)
|
|
226
|
-
|
|
227
|
-
const errors = settled.filter(
|
|
228
|
-
(entry): entry is { index: number; error: unknown } =>
|
|
229
|
-
'error' in entry,
|
|
230
|
-
)
|
|
231
|
-
|
|
232
|
-
if (errors.length > 0) {
|
|
233
|
-
throw new Error(
|
|
234
|
-
`Error during parallel step group [${groupStart}-${groupEnd - 1}]`,
|
|
235
|
-
{ cause: errors[0].error },
|
|
236
|
-
)
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
const keyOwners = new Map<string, number>()
|
|
240
|
-
for (const entry of settled) {
|
|
241
|
-
if (!('produced' in entry) || !entry.produced) continue
|
|
242
|
-
for (const key of Object.keys(entry.produced)) {
|
|
243
|
-
const owner = keyOwners.get(key)
|
|
244
|
-
if (owner !== undefined && owner !== entry.index) {
|
|
245
|
-
throw new Error(
|
|
246
|
-
`Parallel step key conflict for "${key}" between steps [${owner}] and [${entry.index}]`,
|
|
247
|
-
)
|
|
248
|
-
}
|
|
249
|
-
keyOwners.set(key, entry.index)
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
for (let index = groupStart; index < groupEnd; index++) {
|
|
254
|
-
const entry = settled.find(
|
|
255
|
-
(
|
|
256
|
-
item,
|
|
257
|
-
): item is {
|
|
258
|
-
index: number
|
|
259
|
-
produced: Record<string, unknown> | null
|
|
260
|
-
} => item.index === index && 'produced' in item,
|
|
261
|
-
)
|
|
262
|
-
if (entry?.produced) {
|
|
263
|
-
Object.assign(result, entry.produced)
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
stepIndex = groupEnd
|
|
269
|
-
continue
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
const step = steps[stepIndex]
|
|
273
|
-
const resultSnapshot = Object.freeze(
|
|
274
|
-
Object.assign({}, decodedInput, result),
|
|
275
|
-
)
|
|
276
|
-
|
|
277
|
-
await this.runStep({
|
|
278
|
-
job,
|
|
279
|
-
step,
|
|
280
|
-
stepIndex,
|
|
281
|
-
result,
|
|
282
|
-
resultSnapshot,
|
|
283
|
-
decodedInput,
|
|
284
|
-
progress,
|
|
285
|
-
stepResults,
|
|
286
|
-
options: runOptions,
|
|
287
|
-
jobDependencyContext,
|
|
288
|
-
jobData,
|
|
289
|
-
container,
|
|
290
|
-
applyResult: true,
|
|
291
|
-
})
|
|
292
|
-
|
|
293
|
-
stepIndex++
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
const finalPayload = await job.returnHandler!({
|
|
297
|
-
context: jobDependencyContext,
|
|
298
|
-
data: jobData,
|
|
299
|
-
input: decodedInput,
|
|
300
|
-
result,
|
|
301
|
-
progress,
|
|
302
|
-
})
|
|
303
|
-
|
|
304
|
-
return output.encode(finalPayload)
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
protected async runStep(params: {
|
|
308
|
-
job: AnyJob
|
|
309
|
-
step: AnyJobStep
|
|
310
|
-
stepIndex: number
|
|
311
|
-
result: Record<string, unknown>
|
|
312
|
-
resultSnapshot: Record<string, unknown>
|
|
313
|
-
decodedInput: Record<string, unknown>
|
|
314
|
-
progress: Record<string, unknown>
|
|
315
|
-
stepResults: StepResultEntry[]
|
|
316
|
-
options: RunOptions
|
|
317
|
-
jobDependencyContext: any
|
|
318
|
-
jobData: unknown
|
|
319
|
-
container: Container
|
|
320
|
-
applyResult: boolean
|
|
321
|
-
}): Promise<Record<string, unknown> | null> {
|
|
322
|
-
const {
|
|
323
|
-
job,
|
|
324
|
-
step,
|
|
325
|
-
stepIndex,
|
|
326
|
-
result,
|
|
327
|
-
resultSnapshot,
|
|
328
|
-
decodedInput,
|
|
329
|
-
progress,
|
|
330
|
-
stepResults,
|
|
331
|
-
options,
|
|
332
|
-
jobDependencyContext,
|
|
333
|
-
jobData,
|
|
334
|
-
container,
|
|
335
|
-
applyResult,
|
|
336
|
-
} = params
|
|
337
|
-
|
|
338
|
-
try {
|
|
339
|
-
const condition = job.conditions.get(stepIndex)
|
|
340
|
-
if (condition) {
|
|
341
|
-
const shouldRun = await condition({
|
|
342
|
-
context: jobDependencyContext,
|
|
343
|
-
data: jobData,
|
|
344
|
-
input: decodedInput,
|
|
345
|
-
result: resultSnapshot,
|
|
346
|
-
progress,
|
|
347
|
-
})
|
|
348
|
-
if (!shouldRun) {
|
|
349
|
-
const now = Date.now()
|
|
350
|
-
const skippedResult = {
|
|
351
|
-
data: null,
|
|
352
|
-
startedAt: now,
|
|
353
|
-
completedAt: now,
|
|
354
|
-
duration: 0,
|
|
355
|
-
}
|
|
356
|
-
stepResults[stepIndex] = skippedResult
|
|
357
|
-
await this.afterStep({
|
|
358
|
-
job,
|
|
359
|
-
step,
|
|
360
|
-
stepIndex,
|
|
361
|
-
result,
|
|
362
|
-
stepResult: skippedResult,
|
|
363
|
-
stepResults,
|
|
364
|
-
options,
|
|
365
|
-
})
|
|
366
|
-
return null
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
const stepStartedAt = Date.now()
|
|
371
|
-
|
|
372
|
-
await this.beforeStep({
|
|
373
|
-
job,
|
|
374
|
-
step,
|
|
375
|
-
stepIndex,
|
|
376
|
-
result,
|
|
377
|
-
options,
|
|
378
|
-
stepResults,
|
|
379
|
-
})
|
|
380
|
-
|
|
381
|
-
const stepContext = await container.createContext(step.dependencies)
|
|
382
|
-
const stepInput = step.input.decode(resultSnapshot)
|
|
383
|
-
|
|
384
|
-
await job.beforeEachHandler?.({
|
|
385
|
-
context: jobDependencyContext,
|
|
386
|
-
data: jobData,
|
|
387
|
-
input: decodedInput,
|
|
388
|
-
result: resultSnapshot,
|
|
389
|
-
progress,
|
|
390
|
-
step,
|
|
391
|
-
stepIndex,
|
|
392
|
-
})
|
|
393
|
-
|
|
394
|
-
const handlerReturn = await step.handler(stepContext, stepInput, jobData)
|
|
395
|
-
|
|
396
|
-
const produced = step.output.encode(handlerReturn ?? {})
|
|
397
|
-
const stepCompletedAt = Date.now()
|
|
398
|
-
const stepResult: StepResultEntry = {
|
|
399
|
-
data: produced,
|
|
400
|
-
startedAt: stepStartedAt,
|
|
401
|
-
completedAt: stepCompletedAt,
|
|
402
|
-
duration: stepCompletedAt - stepStartedAt,
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
stepResults[stepIndex] = stepResult
|
|
406
|
-
|
|
407
|
-
if (applyResult) {
|
|
408
|
-
Object.assign(result, produced)
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
await job.afterEachHandler?.({
|
|
412
|
-
context: jobDependencyContext,
|
|
413
|
-
data: jobData,
|
|
414
|
-
input: decodedInput,
|
|
415
|
-
result: applyResult ? result : Object.assign({}, result, produced),
|
|
416
|
-
progress,
|
|
417
|
-
step,
|
|
418
|
-
stepIndex,
|
|
419
|
-
})
|
|
420
|
-
|
|
421
|
-
await this.afterStep({
|
|
422
|
-
job,
|
|
423
|
-
step,
|
|
424
|
-
stepIndex,
|
|
425
|
-
result,
|
|
426
|
-
stepResult,
|
|
427
|
-
stepResults,
|
|
428
|
-
options,
|
|
429
|
-
})
|
|
430
|
-
|
|
431
|
-
return produced
|
|
432
|
-
} catch (error) {
|
|
433
|
-
const wrapped = new Error(`Error during step [${stepIndex}]`, {
|
|
434
|
-
cause: error,
|
|
435
|
-
})
|
|
436
|
-
this.logger.error(wrapped)
|
|
437
|
-
|
|
438
|
-
const allowRetry = await job.onErrorHandler?.({
|
|
439
|
-
context: jobDependencyContext,
|
|
440
|
-
data: jobData,
|
|
441
|
-
input: decodedInput,
|
|
442
|
-
result,
|
|
443
|
-
progress,
|
|
444
|
-
step,
|
|
445
|
-
stepIndex,
|
|
446
|
-
error,
|
|
447
|
-
})
|
|
448
|
-
|
|
449
|
-
if (allowRetry === false) {
|
|
450
|
-
throw new UnrecoverableError('Job failed (unrecoverable)')
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
throw wrapped
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
protected nextStepIndex(stepResults: StepResultEntry[]) {
|
|
458
|
-
const missingIndex = stepResults.findIndex((entry) => !entry)
|
|
459
|
-
return missingIndex === -1 ? stepResults.length : missingIndex
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
protected async beforeStep(
|
|
463
|
-
params: JobRunnerRunBeforeStepParams<RunOptions>,
|
|
464
|
-
): Promise<void> {
|
|
465
|
-
this.logger.debug(
|
|
466
|
-
{
|
|
467
|
-
job: params.job.name,
|
|
468
|
-
step: params.step.label || params.stepIndex + 1,
|
|
469
|
-
stepIndex: params.stepIndex,
|
|
470
|
-
},
|
|
471
|
-
'Executing job step',
|
|
472
|
-
)
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
protected async afterStep(
|
|
476
|
-
params: JobRunnerRunAfterStepParams<RunOptions>,
|
|
477
|
-
): Promise<void> {
|
|
478
|
-
this.logger.debug(
|
|
479
|
-
{
|
|
480
|
-
job: params.job.name,
|
|
481
|
-
step: params.step.label || params.stepIndex + 1,
|
|
482
|
-
stepIndex: params.stepIndex,
|
|
483
|
-
},
|
|
484
|
-
'Completed job step',
|
|
485
|
-
)
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
export class ApplicationWorkerJobRunner extends JobRunner<
|
|
490
|
-
JobRunnerRunOptions & { queueJob: Job }
|
|
491
|
-
> {
|
|
492
|
-
constructor(
|
|
493
|
-
protected runtime: {
|
|
494
|
-
logger: Logger
|
|
495
|
-
container: Container
|
|
496
|
-
lifecycleHooks: LifecycleHooks
|
|
497
|
-
},
|
|
498
|
-
) {
|
|
499
|
-
super(runtime)
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
protected createJobInfo(
|
|
503
|
-
job: AnyJob,
|
|
504
|
-
options: Partial<JobRunnerRunOptions & { queueJob: Job }>,
|
|
505
|
-
): JobExecutionContext {
|
|
506
|
-
const { queueJob } = options
|
|
507
|
-
return {
|
|
508
|
-
name: job.options.name,
|
|
509
|
-
id: queueJob?.id,
|
|
510
|
-
queue: queueJob?.queueName,
|
|
511
|
-
attempts: queueJob?.attemptsMade,
|
|
512
|
-
stepIndex: options.stepResults
|
|
513
|
-
? this.nextStepIndex(options.stepResults)
|
|
514
|
-
: options.currentStepIndex,
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
protected createSaveProgressFn(
|
|
519
|
-
context: SaveProgressContext<JobRunnerRunOptions & { queueJob: Job }>,
|
|
520
|
-
): () => Promise<void> {
|
|
521
|
-
return async () => {
|
|
522
|
-
const { job, progress, result, stepResults, options } = context
|
|
523
|
-
if (!options || !stepResults) return
|
|
524
|
-
|
|
525
|
-
const { queueJob } = options
|
|
526
|
-
|
|
527
|
-
const currentStepIndex = this.nextStepIndex(stepResults)
|
|
528
|
-
|
|
529
|
-
// Encode progress before persisting if schema is defined
|
|
530
|
-
const encodedProgress = job.progress
|
|
531
|
-
? job.progress.encode(progress)
|
|
532
|
-
: progress
|
|
533
|
-
|
|
534
|
-
const checkpoint: JobProgressCheckpoint = {
|
|
535
|
-
stepIndex: currentStepIndex,
|
|
536
|
-
stepLabel: job.jobSteps[currentStepIndex]?.label,
|
|
537
|
-
result,
|
|
538
|
-
stepResults,
|
|
539
|
-
progress: encodedProgress,
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
await queueJob.updateProgress(checkpoint)
|
|
543
|
-
}
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
protected async afterStep(
|
|
547
|
-
params: JobRunnerRunAfterStepParams<
|
|
548
|
-
JobRunnerRunOptions & { queueJob: Job }
|
|
549
|
-
>,
|
|
550
|
-
): Promise<void> {
|
|
551
|
-
await super.afterStep(params)
|
|
552
|
-
const {
|
|
553
|
-
job,
|
|
554
|
-
step,
|
|
555
|
-
result,
|
|
556
|
-
stepResult,
|
|
557
|
-
stepResults,
|
|
558
|
-
stepIndex,
|
|
559
|
-
options: { queueJob, progress },
|
|
560
|
-
} = params
|
|
561
|
-
const nextStepIndex = this.nextStepIndex(stepResults)
|
|
562
|
-
|
|
563
|
-
// Encode progress before persisting if schema is defined
|
|
564
|
-
const encodedProgress = job.progress
|
|
565
|
-
? job.progress.encode(progress)
|
|
566
|
-
: progress
|
|
567
|
-
|
|
568
|
-
const checkpoint: JobProgressCheckpoint = {
|
|
569
|
-
stepIndex: nextStepIndex,
|
|
570
|
-
stepLabel: job.jobSteps[nextStepIndex]?.label,
|
|
571
|
-
result,
|
|
572
|
-
stepResults,
|
|
573
|
-
progress: encodedProgress,
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
await Promise.all([
|
|
577
|
-
queueJob.log(
|
|
578
|
-
`Step ${step.label || stepIndex + 1} completed in ${(stepResult.duration / 1000).toFixed(3)}s`,
|
|
579
|
-
),
|
|
580
|
-
queueJob.updateProgress(checkpoint),
|
|
581
|
-
])
|
|
582
|
-
}
|
|
583
|
-
}
|
package/src/runtime/jobs/step.ts
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import type { MaybePromise } from '@nmtjs/common'
|
|
2
|
-
import type { Dependant, Dependencies, DependencyContext } from '@nmtjs/core'
|
|
3
|
-
import type { AnyObjectLikeType, ObjectType } from '@nmtjs/type/object'
|
|
4
|
-
import { tryCaptureStackTrace } from '@nmtjs/common'
|
|
5
|
-
import { t } from '@nmtjs/type'
|
|
6
|
-
|
|
7
|
-
import { kJobStepKey } from '../constants.ts'
|
|
8
|
-
|
|
9
|
-
export type AnyJobStep = JobStep<any, any, any, any, any>
|
|
10
|
-
|
|
11
|
-
export type JobStepHandler<
|
|
12
|
-
Deps extends Dependencies,
|
|
13
|
-
Input extends AnyObjectLikeType,
|
|
14
|
-
Output extends AnyObjectLikeType,
|
|
15
|
-
Data = any,
|
|
16
|
-
> = (
|
|
17
|
-
context: DependencyContext<Deps>,
|
|
18
|
-
input: t.infer.decode.output<Input>,
|
|
19
|
-
data: Data,
|
|
20
|
-
) => MaybePromise<t.infer.encode.input<Output>>
|
|
21
|
-
|
|
22
|
-
export interface JobStep<
|
|
23
|
-
Input extends AnyObjectLikeType = AnyObjectLikeType,
|
|
24
|
-
Output extends AnyObjectLikeType = AnyObjectLikeType,
|
|
25
|
-
Deps extends Dependencies = Dependencies,
|
|
26
|
-
Return = unknown,
|
|
27
|
-
Data = any,
|
|
28
|
-
> extends Dependant {
|
|
29
|
-
[kJobStepKey]: any
|
|
30
|
-
_?: { return: Return }
|
|
31
|
-
label?: string
|
|
32
|
-
input: Input
|
|
33
|
-
output: Output
|
|
34
|
-
dependencies: Deps
|
|
35
|
-
handler: JobStepHandler<Deps, Input, Output, Data>
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export function createStep<
|
|
39
|
-
Input extends AnyObjectLikeType,
|
|
40
|
-
Output extends AnyObjectLikeType = ObjectType<{}>,
|
|
41
|
-
Deps extends Dependencies = {},
|
|
42
|
-
Return = unknown,
|
|
43
|
-
Data = any,
|
|
44
|
-
>(step: {
|
|
45
|
-
label?: string
|
|
46
|
-
input: Input
|
|
47
|
-
output?: Output
|
|
48
|
-
dependencies?: Deps
|
|
49
|
-
handler: JobStepHandler<Deps, Input, Output, Data>
|
|
50
|
-
}): JobStep<Input, Output, Deps, Return, Data> {
|
|
51
|
-
return Object.freeze({
|
|
52
|
-
[kJobStepKey]: true,
|
|
53
|
-
output: t.object({}) as unknown as Output,
|
|
54
|
-
dependencies: {} as Deps,
|
|
55
|
-
stack: tryCaptureStackTrace(),
|
|
56
|
-
...step,
|
|
57
|
-
})
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export function isJobStep(value: unknown): value is AnyJobStep {
|
|
61
|
-
return (
|
|
62
|
-
typeof value === 'object' &&
|
|
63
|
-
value !== null &&
|
|
64
|
-
(value as AnyJobStep)[kJobStepKey] === true
|
|
65
|
-
)
|
|
66
|
-
}
|