duron 0.1.0
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 +7 -0
- package/README.md +140 -0
- package/dist/action-job.d.ts +24 -0
- package/dist/action-job.d.ts.map +1 -0
- package/dist/action-job.js +108 -0
- package/dist/action-manager.d.ts +21 -0
- package/dist/action-manager.d.ts.map +1 -0
- package/dist/action-manager.js +78 -0
- package/dist/action.d.ts +129 -0
- package/dist/action.d.ts.map +1 -0
- package/dist/action.js +87 -0
- package/dist/adapters/adapter.d.ts +92 -0
- package/dist/adapters/adapter.d.ts.map +1 -0
- package/dist/adapters/adapter.js +424 -0
- package/dist/adapters/postgres/drizzle.config.d.ts +3 -0
- package/dist/adapters/postgres/drizzle.config.d.ts.map +1 -0
- package/dist/adapters/postgres/drizzle.config.js +10 -0
- package/dist/adapters/postgres/pglite.d.ts +13 -0
- package/dist/adapters/postgres/pglite.d.ts.map +1 -0
- package/dist/adapters/postgres/pglite.js +36 -0
- package/dist/adapters/postgres/postgres.d.ts +51 -0
- package/dist/adapters/postgres/postgres.d.ts.map +1 -0
- package/dist/adapters/postgres/postgres.js +867 -0
- package/dist/adapters/postgres/schema.d.ts +581 -0
- package/dist/adapters/postgres/schema.d.ts.map +1 -0
- package/dist/adapters/postgres/schema.default.d.ts +577 -0
- package/dist/adapters/postgres/schema.default.d.ts.map +1 -0
- package/dist/adapters/postgres/schema.default.js +3 -0
- package/dist/adapters/postgres/schema.js +87 -0
- package/dist/adapters/schemas.d.ts +516 -0
- package/dist/adapters/schemas.d.ts.map +1 -0
- package/dist/adapters/schemas.js +184 -0
- package/dist/client.d.ts +85 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +416 -0
- package/dist/constants.d.ts +14 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +22 -0
- package/dist/errors.d.ts +43 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +75 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/server.d.ts +1193 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +516 -0
- package/dist/step-manager.d.ts +46 -0
- package/dist/step-manager.d.ts.map +1 -0
- package/dist/step-manager.js +216 -0
- package/dist/utils/checksum.d.ts +2 -0
- package/dist/utils/checksum.d.ts.map +1 -0
- package/dist/utils/checksum.js +6 -0
- package/dist/utils/p-retry.d.ts +19 -0
- package/dist/utils/p-retry.d.ts.map +1 -0
- package/dist/utils/p-retry.js +130 -0
- package/dist/utils/wait-for-abort.d.ts +5 -0
- package/dist/utils/wait-for-abort.d.ts.map +1 -0
- package/dist/utils/wait-for-abort.js +32 -0
- package/migrations/postgres/0000_lethal_speed_demon.sql +64 -0
- package/migrations/postgres/meta/0000_snapshot.json +606 -0
- package/migrations/postgres/meta/_journal.json +13 -0
- package/package.json +88 -0
- package/src/action-job.ts +201 -0
- package/src/action-manager.ts +166 -0
- package/src/action.ts +247 -0
- package/src/adapters/adapter.ts +969 -0
- package/src/adapters/postgres/drizzle.config.ts +11 -0
- package/src/adapters/postgres/pglite.ts +86 -0
- package/src/adapters/postgres/postgres.ts +1346 -0
- package/src/adapters/postgres/schema.default.ts +5 -0
- package/src/adapters/postgres/schema.ts +119 -0
- package/src/adapters/schemas.ts +320 -0
- package/src/client.ts +859 -0
- package/src/constants.ts +37 -0
- package/src/errors.ts +205 -0
- package/src/index.ts +14 -0
- package/src/server.ts +718 -0
- package/src/step-manager.ts +471 -0
- package/src/utils/checksum.ts +7 -0
- package/src/utils/p-retry.ts +213 -0
- package/src/utils/wait-for-abort.ts +40 -0
|
@@ -0,0 +1,969 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events'
|
|
2
|
+
|
|
3
|
+
import type { Logger } from 'pino'
|
|
4
|
+
import { z } from 'zod'
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
JOB_STATUS_CANCELLED,
|
|
8
|
+
JOB_STATUS_COMPLETED,
|
|
9
|
+
JOB_STATUS_FAILED,
|
|
10
|
+
type JobStatus,
|
|
11
|
+
STEP_STATUS_CANCELLED,
|
|
12
|
+
STEP_STATUS_COMPLETED,
|
|
13
|
+
STEP_STATUS_FAILED,
|
|
14
|
+
type StepStatus,
|
|
15
|
+
} from '../constants.js'
|
|
16
|
+
import type {
|
|
17
|
+
CancelJobOptions,
|
|
18
|
+
CancelJobStepOptions,
|
|
19
|
+
CompleteJobOptions,
|
|
20
|
+
CompleteJobStepOptions,
|
|
21
|
+
CreateJobOptions,
|
|
22
|
+
CreateOrRecoverJobStepOptions,
|
|
23
|
+
CreateOrRecoverJobStepResult,
|
|
24
|
+
DelayJobStepOptions,
|
|
25
|
+
DeleteJobOptions,
|
|
26
|
+
DeleteJobsOptions,
|
|
27
|
+
FailJobOptions,
|
|
28
|
+
FailJobStepOptions,
|
|
29
|
+
FetchOptions,
|
|
30
|
+
GetActionsResult,
|
|
31
|
+
GetJobStepsOptions,
|
|
32
|
+
GetJobStepsResult,
|
|
33
|
+
GetJobsOptions,
|
|
34
|
+
GetJobsResult,
|
|
35
|
+
Job,
|
|
36
|
+
JobStatusResult,
|
|
37
|
+
JobStep,
|
|
38
|
+
JobStepStatusResult,
|
|
39
|
+
RecoverJobsOptions,
|
|
40
|
+
RetryJobOptions,
|
|
41
|
+
} from './schemas.js'
|
|
42
|
+
import {
|
|
43
|
+
BooleanResultSchema,
|
|
44
|
+
CancelJobOptionsSchema,
|
|
45
|
+
CancelJobStepOptionsSchema,
|
|
46
|
+
CompleteJobOptionsSchema,
|
|
47
|
+
CompleteJobStepOptionsSchema,
|
|
48
|
+
CreateJobOptionsSchema,
|
|
49
|
+
CreateOrRecoverJobStepOptionsSchema,
|
|
50
|
+
CreateOrRecoverJobStepResultNullableSchema,
|
|
51
|
+
DelayJobStepOptionsSchema,
|
|
52
|
+
DeleteJobOptionsSchema,
|
|
53
|
+
DeleteJobsOptionsSchema,
|
|
54
|
+
FailJobOptionsSchema,
|
|
55
|
+
FailJobStepOptionsSchema,
|
|
56
|
+
FetchOptionsSchema,
|
|
57
|
+
GetActionsResultSchema,
|
|
58
|
+
GetJobStepsOptionsSchema,
|
|
59
|
+
GetJobStepsResultSchema,
|
|
60
|
+
GetJobsOptionsSchema,
|
|
61
|
+
GetJobsResultSchema,
|
|
62
|
+
JobIdResultSchema,
|
|
63
|
+
JobSchema,
|
|
64
|
+
JobStatusResultSchema,
|
|
65
|
+
JobStepSchema,
|
|
66
|
+
JobStepStatusResultSchema,
|
|
67
|
+
JobsArrayResultSchema,
|
|
68
|
+
NumberResultSchema,
|
|
69
|
+
RecoverJobsOptionsSchema,
|
|
70
|
+
RetryJobOptionsSchema,
|
|
71
|
+
} from './schemas.js'
|
|
72
|
+
|
|
73
|
+
// Re-export types from schemas for backward compatibility
|
|
74
|
+
export type {
|
|
75
|
+
ActionStats,
|
|
76
|
+
CancelJobOptions,
|
|
77
|
+
CancelJobStepOptions,
|
|
78
|
+
CompleteJobOptions,
|
|
79
|
+
CompleteJobStepOptions,
|
|
80
|
+
CreateJobOptions,
|
|
81
|
+
CreateOrRecoverJobStepOptions,
|
|
82
|
+
CreateOrRecoverJobStepResult,
|
|
83
|
+
DelayJobStepOptions,
|
|
84
|
+
DeleteJobOptions,
|
|
85
|
+
DeleteJobsOptions,
|
|
86
|
+
FailJobOptions,
|
|
87
|
+
FailJobStepOptions,
|
|
88
|
+
FetchOptions,
|
|
89
|
+
GetActionsResult,
|
|
90
|
+
GetJobStepsOptions,
|
|
91
|
+
GetJobStepsResult,
|
|
92
|
+
GetJobsOptions,
|
|
93
|
+
GetJobsResult,
|
|
94
|
+
Job,
|
|
95
|
+
JobFilters,
|
|
96
|
+
JobSort,
|
|
97
|
+
JobSortField,
|
|
98
|
+
JobStatusResult,
|
|
99
|
+
JobStep,
|
|
100
|
+
JobStepStatusResult,
|
|
101
|
+
RecoverJobsOptions,
|
|
102
|
+
RetryJobOptions,
|
|
103
|
+
SortOrder,
|
|
104
|
+
} from './schemas.js'
|
|
105
|
+
|
|
106
|
+
// ============================================================================
|
|
107
|
+
// Adapter Events
|
|
108
|
+
// ============================================================================
|
|
109
|
+
|
|
110
|
+
export interface AdapterEvents {
|
|
111
|
+
'job-status-changed': [
|
|
112
|
+
{
|
|
113
|
+
jobId: string
|
|
114
|
+
status: JobStatus | 'retried'
|
|
115
|
+
ownerId: string
|
|
116
|
+
},
|
|
117
|
+
]
|
|
118
|
+
'job-available': [
|
|
119
|
+
{
|
|
120
|
+
jobId: string
|
|
121
|
+
},
|
|
122
|
+
]
|
|
123
|
+
'step-status-changed': [
|
|
124
|
+
{
|
|
125
|
+
jobId: string
|
|
126
|
+
stepId: string
|
|
127
|
+
status: StepStatus
|
|
128
|
+
error: any | null
|
|
129
|
+
ownerId: string
|
|
130
|
+
},
|
|
131
|
+
]
|
|
132
|
+
'step-delayed': [
|
|
133
|
+
{
|
|
134
|
+
jobId: string
|
|
135
|
+
stepId: string
|
|
136
|
+
delayedMs: number
|
|
137
|
+
error: any
|
|
138
|
+
ownerId: string
|
|
139
|
+
},
|
|
140
|
+
]
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// ============================================================================
|
|
144
|
+
// Abstract Adapter Class
|
|
145
|
+
// ============================================================================
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Abstract base class for database adapters.
|
|
149
|
+
* All adapters must extend this class and implement its abstract methods.
|
|
150
|
+
*/
|
|
151
|
+
export abstract class Adapter extends EventEmitter<AdapterEvents> {
|
|
152
|
+
#id!: string
|
|
153
|
+
#started: boolean = false
|
|
154
|
+
#stopped: boolean = false
|
|
155
|
+
#starting: Promise<boolean> | null = null
|
|
156
|
+
#stopping: Promise<boolean> | null = null
|
|
157
|
+
#logger: Logger | null = null
|
|
158
|
+
|
|
159
|
+
// ============================================================================
|
|
160
|
+
// Lifecycle Methods
|
|
161
|
+
// ============================================================================
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Start the adapter.
|
|
165
|
+
* Performs any necessary initialization, such as running migrations or setting up listeners.
|
|
166
|
+
*
|
|
167
|
+
* @returns Promise resolving to `true` if started successfully, `false` otherwise
|
|
168
|
+
*/
|
|
169
|
+
async start() {
|
|
170
|
+
try {
|
|
171
|
+
if (!this.#id) {
|
|
172
|
+
throw new Error('Adapter ID is not set')
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (this.#stopping || this.#stopped) {
|
|
176
|
+
return false
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (this.#started) {
|
|
180
|
+
return true
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (this.#starting) {
|
|
184
|
+
return this.#starting
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
this.#starting = (async () => {
|
|
188
|
+
await this._start()
|
|
189
|
+
this.#started = true
|
|
190
|
+
this.#starting = null
|
|
191
|
+
return true
|
|
192
|
+
})()
|
|
193
|
+
|
|
194
|
+
return this.#starting
|
|
195
|
+
} catch (error) {
|
|
196
|
+
this.#logger?.error(error, 'Error in Adapter.start()')
|
|
197
|
+
throw error
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Stop the adapter.
|
|
203
|
+
* Performs cleanup, such as closing database connections.
|
|
204
|
+
*
|
|
205
|
+
* @returns Promise resolving to `true` if stopped successfully, `false` otherwise
|
|
206
|
+
*/
|
|
207
|
+
async stop() {
|
|
208
|
+
try {
|
|
209
|
+
if (this.#stopped) {
|
|
210
|
+
return true
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (this.#stopping) {
|
|
214
|
+
return this.#stopping
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
this.#stopping = (async () => {
|
|
218
|
+
await this._stop()
|
|
219
|
+
this.#stopped = true
|
|
220
|
+
this.#stopping = null
|
|
221
|
+
return true
|
|
222
|
+
})()
|
|
223
|
+
|
|
224
|
+
return this.#stopping
|
|
225
|
+
} catch (error) {
|
|
226
|
+
this.#logger?.error(error, 'Error in Adapter.stop()')
|
|
227
|
+
throw error
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// ============================================================================
|
|
232
|
+
// Configuration Methods
|
|
233
|
+
// ============================================================================
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Set the unique identifier for this adapter instance.
|
|
237
|
+
* Used for multi-process coordination and job ownership.
|
|
238
|
+
*
|
|
239
|
+
* @param id - The unique identifier for this adapter instance
|
|
240
|
+
*/
|
|
241
|
+
setId(id: string) {
|
|
242
|
+
try {
|
|
243
|
+
this.#id = id
|
|
244
|
+
} catch (error) {
|
|
245
|
+
this.#logger?.error(error, 'Error in Adapter.setId()')
|
|
246
|
+
throw error
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Set the logger instance for this adapter.
|
|
252
|
+
*
|
|
253
|
+
* @param logger - The logger instance to use for logging
|
|
254
|
+
*/
|
|
255
|
+
setLogger(logger: Logger) {
|
|
256
|
+
try {
|
|
257
|
+
this.#logger = logger
|
|
258
|
+
} catch (error) {
|
|
259
|
+
this.#logger?.error(error, 'Error in Adapter.setLogger()')
|
|
260
|
+
throw error
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Get the unique identifier for this adapter instance.
|
|
266
|
+
*
|
|
267
|
+
* @returns The unique identifier for this adapter instance
|
|
268
|
+
*/
|
|
269
|
+
get id(): string {
|
|
270
|
+
return this.#id
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Get the logger instance for this adapter.
|
|
275
|
+
*
|
|
276
|
+
* @returns The logger instance, or `null` if not set
|
|
277
|
+
*/
|
|
278
|
+
get logger(): Logger | null {
|
|
279
|
+
return this.#logger
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// ============================================================================
|
|
283
|
+
// Job Methods
|
|
284
|
+
// ============================================================================
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Create a new job in the database.
|
|
288
|
+
*
|
|
289
|
+
* @returns Promise resolving to the job ID, or `null` if creation failed
|
|
290
|
+
*/
|
|
291
|
+
async createJob(options: CreateJobOptions): Promise<string | null> {
|
|
292
|
+
try {
|
|
293
|
+
await this.start()
|
|
294
|
+
const parsedOptions = CreateJobOptionsSchema.parse(options)
|
|
295
|
+
const result = await this._createJob(parsedOptions)
|
|
296
|
+
const jobId = JobIdResultSchema.parse(result)
|
|
297
|
+
if (jobId !== null) {
|
|
298
|
+
await this._notify('job-available', { jobId })
|
|
299
|
+
}
|
|
300
|
+
return jobId
|
|
301
|
+
} catch (error) {
|
|
302
|
+
this.#logger?.error(error, 'Error in Adapter.createJob()')
|
|
303
|
+
throw error
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Mark a job as completed.
|
|
309
|
+
*
|
|
310
|
+
* @returns Promise resolving to `true` if completed, `false` otherwise
|
|
311
|
+
*/
|
|
312
|
+
async completeJob(options: CompleteJobOptions): Promise<boolean> {
|
|
313
|
+
try {
|
|
314
|
+
await this.start()
|
|
315
|
+
const parsedOptions = CompleteJobOptionsSchema.parse(options)
|
|
316
|
+
const result = await this._completeJob(parsedOptions)
|
|
317
|
+
const success = BooleanResultSchema.parse(result)
|
|
318
|
+
if (success) {
|
|
319
|
+
await this._notify('job-status-changed', {
|
|
320
|
+
jobId: parsedOptions.jobId,
|
|
321
|
+
status: JOB_STATUS_COMPLETED,
|
|
322
|
+
ownerId: this.id,
|
|
323
|
+
})
|
|
324
|
+
}
|
|
325
|
+
return success
|
|
326
|
+
} catch (error) {
|
|
327
|
+
this.#logger?.error(error, 'Error in Adapter.completeJob()')
|
|
328
|
+
throw error
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Mark a job as failed.
|
|
334
|
+
*
|
|
335
|
+
* @returns Promise resolving to `true` if failed, `false` otherwise
|
|
336
|
+
*/
|
|
337
|
+
async failJob(options: FailJobOptions): Promise<boolean> {
|
|
338
|
+
try {
|
|
339
|
+
await this.start()
|
|
340
|
+
const parsedOptions = FailJobOptionsSchema.parse(options)
|
|
341
|
+
const result = await this._failJob(parsedOptions)
|
|
342
|
+
const success = BooleanResultSchema.parse(result)
|
|
343
|
+
if (success) {
|
|
344
|
+
await this._notify('job-status-changed', {
|
|
345
|
+
jobId: parsedOptions.jobId,
|
|
346
|
+
status: JOB_STATUS_FAILED,
|
|
347
|
+
ownerId: this.id,
|
|
348
|
+
})
|
|
349
|
+
}
|
|
350
|
+
return success
|
|
351
|
+
} catch (error) {
|
|
352
|
+
this.#logger?.error(error, 'Error in Adapter.failJob()')
|
|
353
|
+
throw error
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Cancel a job.
|
|
359
|
+
*
|
|
360
|
+
* @returns Promise resolving to `true` if cancelled, `false` otherwise
|
|
361
|
+
*/
|
|
362
|
+
async cancelJob(options: CancelJobOptions): Promise<boolean> {
|
|
363
|
+
try {
|
|
364
|
+
await this.start()
|
|
365
|
+
const parsedOptions = CancelJobOptionsSchema.parse(options)
|
|
366
|
+
const result = await this._cancelJob(parsedOptions)
|
|
367
|
+
const success = BooleanResultSchema.parse(result)
|
|
368
|
+
if (success) {
|
|
369
|
+
await this._notify('job-status-changed', {
|
|
370
|
+
jobId: parsedOptions.jobId,
|
|
371
|
+
status: JOB_STATUS_CANCELLED,
|
|
372
|
+
ownerId: this.id,
|
|
373
|
+
})
|
|
374
|
+
}
|
|
375
|
+
return success
|
|
376
|
+
} catch (error) {
|
|
377
|
+
this.#logger?.error(error, 'Error in Adapter.cancelJob()')
|
|
378
|
+
throw error
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Retry a failed job by creating a copy of it with status 'created' and cleared output/error.
|
|
384
|
+
*
|
|
385
|
+
* @returns Promise resolving to the job ID, or `null` if creation failed
|
|
386
|
+
*/
|
|
387
|
+
async retryJob(options: RetryJobOptions): Promise<string | null> {
|
|
388
|
+
try {
|
|
389
|
+
await this.start()
|
|
390
|
+
const parsedOptions = RetryJobOptionsSchema.parse(options)
|
|
391
|
+
const result = await this._retryJob(parsedOptions)
|
|
392
|
+
const jobId = JobIdResultSchema.parse(result)
|
|
393
|
+
if (jobId !== null) {
|
|
394
|
+
await this._notify('job-available', { jobId })
|
|
395
|
+
}
|
|
396
|
+
return jobId
|
|
397
|
+
} catch (error) {
|
|
398
|
+
this.#logger?.error(error, 'Error in Adapter.retryJob()')
|
|
399
|
+
throw error
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Delete a job by its ID.
|
|
405
|
+
* Active jobs cannot be deleted.
|
|
406
|
+
*
|
|
407
|
+
* @returns Promise resolving to `true` if deleted, `false` otherwise
|
|
408
|
+
*/
|
|
409
|
+
async deleteJob(options: DeleteJobOptions): Promise<boolean> {
|
|
410
|
+
try {
|
|
411
|
+
await this.start()
|
|
412
|
+
const parsedOptions = DeleteJobOptionsSchema.parse(options)
|
|
413
|
+
const result = await this._deleteJob(parsedOptions)
|
|
414
|
+
return BooleanResultSchema.parse(result)
|
|
415
|
+
} catch (error) {
|
|
416
|
+
this.#logger?.error(error, 'Error in Adapter.deleteJob()')
|
|
417
|
+
throw error
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* Delete multiple jobs using the same filters as getJobs.
|
|
423
|
+
* Active jobs cannot be deleted and will be excluded from deletion.
|
|
424
|
+
*
|
|
425
|
+
* @returns Promise resolving to the number of jobs deleted
|
|
426
|
+
*/
|
|
427
|
+
async deleteJobs(options?: DeleteJobsOptions): Promise<number> {
|
|
428
|
+
try {
|
|
429
|
+
await this.start()
|
|
430
|
+
const parsedOptions = options ? DeleteJobsOptionsSchema.parse(options) : undefined
|
|
431
|
+
const result = await this._deleteJobs(parsedOptions)
|
|
432
|
+
return NumberResultSchema.parse(result)
|
|
433
|
+
} catch (error) {
|
|
434
|
+
this.#logger?.error(error, 'Error in Adapter.deleteJobs()')
|
|
435
|
+
throw error
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Fetch jobs from the database respecting concurrency limits per group.
|
|
441
|
+
*
|
|
442
|
+
* @returns Promise resolving to an array of fetched jobs
|
|
443
|
+
*/
|
|
444
|
+
async fetch(options: FetchOptions): Promise<Job[]> {
|
|
445
|
+
try {
|
|
446
|
+
await this.start()
|
|
447
|
+
const parsedOptions = FetchOptionsSchema.parse(options)
|
|
448
|
+
const result = await this._fetch(parsedOptions)
|
|
449
|
+
return JobsArrayResultSchema.parse(result)
|
|
450
|
+
} catch (error) {
|
|
451
|
+
this.#logger?.error(error, 'Error in Adapter.fetch()')
|
|
452
|
+
throw error
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* Recover stuck jobs (jobs that were active but the process that owned them is no longer running).
|
|
458
|
+
*
|
|
459
|
+
* @returns Promise resolving to the number of jobs recovered
|
|
460
|
+
*/
|
|
461
|
+
async recoverJobs(options: RecoverJobsOptions): Promise<number> {
|
|
462
|
+
try {
|
|
463
|
+
await this.start()
|
|
464
|
+
const parsedOptions = RecoverJobsOptionsSchema.parse(options)
|
|
465
|
+
const result = await this._recoverJobs(parsedOptions)
|
|
466
|
+
return NumberResultSchema.parse(result)
|
|
467
|
+
} catch (error) {
|
|
468
|
+
this.#logger?.error(error, 'Error in Adapter.recoverJobs()')
|
|
469
|
+
throw error
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// ============================================================================
|
|
474
|
+
// Step Methods
|
|
475
|
+
// ============================================================================
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
* Create or recover a job step by creating or resetting a step record in the database.
|
|
479
|
+
*
|
|
480
|
+
* @returns Promise resolving to the step, or `null` if creation failed
|
|
481
|
+
*/
|
|
482
|
+
async createOrRecoverJobStep(options: CreateOrRecoverJobStepOptions): Promise<CreateOrRecoverJobStepResult | null> {
|
|
483
|
+
try {
|
|
484
|
+
await this.start()
|
|
485
|
+
const parsedOptions = CreateOrRecoverJobStepOptionsSchema.parse(options)
|
|
486
|
+
const result = await this._createOrRecoverJobStep(parsedOptions)
|
|
487
|
+
return CreateOrRecoverJobStepResultNullableSchema.parse(result)
|
|
488
|
+
} catch (error) {
|
|
489
|
+
this.#logger?.error(error, 'Error in Adapter.createOrRecoverJobStep()')
|
|
490
|
+
throw error
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* Mark a job step as completed.
|
|
496
|
+
*
|
|
497
|
+
* @returns Promise resolving to `true` if completed, `false` otherwise
|
|
498
|
+
*/
|
|
499
|
+
async completeJobStep(options: CompleteJobStepOptions): Promise<boolean> {
|
|
500
|
+
try {
|
|
501
|
+
await this.start()
|
|
502
|
+
const parsedOptions = CompleteJobStepOptionsSchema.parse(options)
|
|
503
|
+
const result = await this._completeJobStep(parsedOptions)
|
|
504
|
+
const success = BooleanResultSchema.parse(result)
|
|
505
|
+
if (success) {
|
|
506
|
+
// Fetch jobId for notification
|
|
507
|
+
const step = await this._getJobStepById(parsedOptions.stepId)
|
|
508
|
+
if (step) {
|
|
509
|
+
await this._notify('step-status-changed', {
|
|
510
|
+
jobId: step.jobId,
|
|
511
|
+
stepId: parsedOptions.stepId,
|
|
512
|
+
status: STEP_STATUS_COMPLETED,
|
|
513
|
+
error: null,
|
|
514
|
+
ownerId: this.id,
|
|
515
|
+
})
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
return success
|
|
519
|
+
} catch (error) {
|
|
520
|
+
this.#logger?.error(error, 'Error in Adapter.completeJobStep()')
|
|
521
|
+
throw error
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* Mark a job step as failed.
|
|
527
|
+
*
|
|
528
|
+
* @returns Promise resolving to `true` if failed, `false` otherwise
|
|
529
|
+
*/
|
|
530
|
+
async failJobStep(options: FailJobStepOptions): Promise<boolean> {
|
|
531
|
+
try {
|
|
532
|
+
await this.start()
|
|
533
|
+
const parsedOptions = FailJobStepOptionsSchema.parse(options)
|
|
534
|
+
const result = await this._failJobStep(parsedOptions)
|
|
535
|
+
const success = BooleanResultSchema.parse(result)
|
|
536
|
+
if (success) {
|
|
537
|
+
// Fetch jobId for notification
|
|
538
|
+
const step = await this._getJobStepById(parsedOptions.stepId)
|
|
539
|
+
if (step) {
|
|
540
|
+
await this._notify('step-status-changed', {
|
|
541
|
+
jobId: step.jobId,
|
|
542
|
+
stepId: parsedOptions.stepId,
|
|
543
|
+
status: STEP_STATUS_FAILED,
|
|
544
|
+
error: parsedOptions.error,
|
|
545
|
+
ownerId: this.id,
|
|
546
|
+
})
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
return success
|
|
550
|
+
} catch (error) {
|
|
551
|
+
this.#logger?.error(error, 'Error in Adapter.failJobStep()')
|
|
552
|
+
throw error
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
/**
|
|
557
|
+
* Delay a job step.
|
|
558
|
+
*
|
|
559
|
+
* @returns Promise resolving to `true` if delayed, `false` otherwise
|
|
560
|
+
*/
|
|
561
|
+
async delayJobStep(options: DelayJobStepOptions): Promise<boolean> {
|
|
562
|
+
try {
|
|
563
|
+
await this.start()
|
|
564
|
+
const parsedOptions = DelayJobStepOptionsSchema.parse(options)
|
|
565
|
+
const result = await this._delayJobStep(parsedOptions)
|
|
566
|
+
const success = BooleanResultSchema.parse(result)
|
|
567
|
+
if (success) {
|
|
568
|
+
// Fetch jobId for notification
|
|
569
|
+
const step = await this._getJobStepById(parsedOptions.stepId)
|
|
570
|
+
if (step) {
|
|
571
|
+
await this._notify('step-delayed', {
|
|
572
|
+
jobId: step.jobId,
|
|
573
|
+
stepId: parsedOptions.stepId,
|
|
574
|
+
delayedMs: parsedOptions.delayMs,
|
|
575
|
+
error: parsedOptions.error,
|
|
576
|
+
ownerId: this.id,
|
|
577
|
+
})
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
return success
|
|
581
|
+
} catch (error) {
|
|
582
|
+
this.#logger?.error(error, 'Error in Adapter.delayJobStep()')
|
|
583
|
+
throw error
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* Cancel a job step.
|
|
589
|
+
*
|
|
590
|
+
* @returns Promise resolving to `true` if cancelled, `false` otherwise
|
|
591
|
+
*/
|
|
592
|
+
async cancelJobStep(options: CancelJobStepOptions): Promise<boolean> {
|
|
593
|
+
try {
|
|
594
|
+
await this.start()
|
|
595
|
+
const parsedOptions = CancelJobStepOptionsSchema.parse(options)
|
|
596
|
+
const result = await this._cancelJobStep(parsedOptions)
|
|
597
|
+
const success = BooleanResultSchema.parse(result)
|
|
598
|
+
if (success) {
|
|
599
|
+
// Fetch jobId for notification
|
|
600
|
+
const step = await this._getJobStepById(parsedOptions.stepId)
|
|
601
|
+
if (step) {
|
|
602
|
+
await this._notify('step-status-changed', {
|
|
603
|
+
jobId: step.jobId,
|
|
604
|
+
stepId: parsedOptions.stepId,
|
|
605
|
+
status: STEP_STATUS_CANCELLED,
|
|
606
|
+
error: null,
|
|
607
|
+
ownerId: this.id,
|
|
608
|
+
})
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
return success
|
|
612
|
+
} catch (error) {
|
|
613
|
+
this.#logger?.error(error, 'Error in Adapter.cancelJobStep()')
|
|
614
|
+
throw error
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
// ============================================================================
|
|
619
|
+
// Private Job Methods (to be implemented by adapters)
|
|
620
|
+
// ============================================================================
|
|
621
|
+
|
|
622
|
+
/**
|
|
623
|
+
* Internal method to create a new job in the database.
|
|
624
|
+
*
|
|
625
|
+
* @param options - Validated job creation options
|
|
626
|
+
* @returns Promise resolving to the job ID, or `null` if creation failed
|
|
627
|
+
*/
|
|
628
|
+
protected abstract _createJob(options: CreateJobOptions): Promise<string | null>
|
|
629
|
+
|
|
630
|
+
/**
|
|
631
|
+
* Internal method to mark a job as completed.
|
|
632
|
+
*
|
|
633
|
+
* @param options - Validated job completion options
|
|
634
|
+
* @returns Promise resolving to `true` if completed, `false` otherwise
|
|
635
|
+
*/
|
|
636
|
+
protected abstract _completeJob(options: CompleteJobOptions): Promise<boolean>
|
|
637
|
+
|
|
638
|
+
/**
|
|
639
|
+
* Internal method to mark a job as failed.
|
|
640
|
+
*
|
|
641
|
+
* @param options - Validated job failure options
|
|
642
|
+
* @returns Promise resolving to `true` if failed, `false` otherwise
|
|
643
|
+
*/
|
|
644
|
+
protected abstract _failJob(options: FailJobOptions): Promise<boolean>
|
|
645
|
+
|
|
646
|
+
/**
|
|
647
|
+
* Internal method to cancel a job.
|
|
648
|
+
*
|
|
649
|
+
* @param options - Validated job cancellation options
|
|
650
|
+
* @returns Promise resolving to `true` if cancelled, `false` otherwise
|
|
651
|
+
*/
|
|
652
|
+
protected abstract _cancelJob(options: CancelJobOptions): Promise<boolean>
|
|
653
|
+
|
|
654
|
+
/**
|
|
655
|
+
* Internal method to retry a failed job by creating a copy of it with status 'created' and cleared output/error.
|
|
656
|
+
*
|
|
657
|
+
* @param options - Validated job retry options
|
|
658
|
+
* @returns Promise resolving to the job ID, or `null` if creation failed
|
|
659
|
+
*/
|
|
660
|
+
protected abstract _retryJob(options: RetryJobOptions): Promise<string | null>
|
|
661
|
+
|
|
662
|
+
/**
|
|
663
|
+
* Internal method to delete a job by its ID.
|
|
664
|
+
* Active jobs cannot be deleted.
|
|
665
|
+
*
|
|
666
|
+
* @param options - Validated job deletion options
|
|
667
|
+
* @returns Promise resolving to `true` if deleted, `false` otherwise
|
|
668
|
+
*/
|
|
669
|
+
protected abstract _deleteJob(options: DeleteJobOptions): Promise<boolean>
|
|
670
|
+
|
|
671
|
+
/**
|
|
672
|
+
* Internal method to delete multiple jobs using the same filters as getJobs.
|
|
673
|
+
* Active jobs cannot be deleted and will be excluded from deletion.
|
|
674
|
+
*
|
|
675
|
+
* @param options - Validated deletion options (same as GetJobsOptions)
|
|
676
|
+
* @returns Promise resolving to the number of jobs deleted
|
|
677
|
+
*/
|
|
678
|
+
protected abstract _deleteJobs(options?: DeleteJobsOptions): Promise<number>
|
|
679
|
+
|
|
680
|
+
/**
|
|
681
|
+
* Internal method to fetch jobs from the database respecting concurrency limits per group.
|
|
682
|
+
*
|
|
683
|
+
* @param options - Validated fetch options
|
|
684
|
+
* @returns Promise resolving to an array of fetched jobs
|
|
685
|
+
*/
|
|
686
|
+
protected abstract _fetch(options: FetchOptions): Promise<Job[]>
|
|
687
|
+
|
|
688
|
+
/**
|
|
689
|
+
* Internal method to recover stuck jobs (jobs that were active but the process that owned them is no longer running).
|
|
690
|
+
*
|
|
691
|
+
* @param options - Validated recovery options
|
|
692
|
+
* @returns Promise resolving to the number of jobs recovered
|
|
693
|
+
*/
|
|
694
|
+
protected abstract _recoverJobs(options: RecoverJobsOptions): Promise<number>
|
|
695
|
+
|
|
696
|
+
// ============================================================================
|
|
697
|
+
// Private Step Methods (to be implemented by adapters)
|
|
698
|
+
// ============================================================================
|
|
699
|
+
|
|
700
|
+
/**
|
|
701
|
+
* Internal method to create or recover a job step by creating or resetting a step record in the database.
|
|
702
|
+
*
|
|
703
|
+
* @param options - Validated step creation options
|
|
704
|
+
* @returns Promise resolving to the step, or `null` if creation failed
|
|
705
|
+
*/
|
|
706
|
+
protected abstract _createOrRecoverJobStep(
|
|
707
|
+
options: CreateOrRecoverJobStepOptions,
|
|
708
|
+
): Promise<CreateOrRecoverJobStepResult | null>
|
|
709
|
+
|
|
710
|
+
/**
|
|
711
|
+
* Internal method to mark a job step as completed.
|
|
712
|
+
*
|
|
713
|
+
* @param options - Validated step completion options
|
|
714
|
+
* @returns Promise resolving to `true` if completed, `false` otherwise
|
|
715
|
+
*/
|
|
716
|
+
protected abstract _completeJobStep(options: CompleteJobStepOptions): Promise<boolean>
|
|
717
|
+
|
|
718
|
+
/**
|
|
719
|
+
* Internal method to mark a job step as failed.
|
|
720
|
+
*
|
|
721
|
+
* @param options - Validated step failure options
|
|
722
|
+
* @returns Promise resolving to `true` if failed, `false` otherwise
|
|
723
|
+
*/
|
|
724
|
+
protected abstract _failJobStep(options: FailJobStepOptions): Promise<boolean>
|
|
725
|
+
|
|
726
|
+
/**
|
|
727
|
+
* Internal method to delay a job step.
|
|
728
|
+
*
|
|
729
|
+
* @param options - Validated step delay options
|
|
730
|
+
* @returns Promise resolving to `true` if delayed, `false` otherwise
|
|
731
|
+
*/
|
|
732
|
+
protected abstract _delayJobStep(options: DelayJobStepOptions): Promise<boolean>
|
|
733
|
+
|
|
734
|
+
/**
|
|
735
|
+
* Internal method to cancel a job step.
|
|
736
|
+
*
|
|
737
|
+
* @param options - Validated step cancellation options
|
|
738
|
+
* @returns Promise resolving to `true` if cancelled, `false` otherwise
|
|
739
|
+
*/
|
|
740
|
+
protected abstract _cancelJobStep(options: CancelJobStepOptions): Promise<boolean>
|
|
741
|
+
|
|
742
|
+
// ============================================================================
|
|
743
|
+
// Query Methods
|
|
744
|
+
// ============================================================================
|
|
745
|
+
|
|
746
|
+
/**
|
|
747
|
+
* Get a job by its ID. Does not include step information.
|
|
748
|
+
*
|
|
749
|
+
* @param jobId - The ID of the job to retrieve
|
|
750
|
+
* @returns Promise resolving to the job, or `null` if not found
|
|
751
|
+
*/
|
|
752
|
+
async getJobById(jobId: string): Promise<Job | null> {
|
|
753
|
+
try {
|
|
754
|
+
const parsedJobId = z.string().parse(jobId)
|
|
755
|
+
const result = await this._getJobById(parsedJobId)
|
|
756
|
+
if (result === null) {
|
|
757
|
+
return null
|
|
758
|
+
}
|
|
759
|
+
return JobSchema.parse(result)
|
|
760
|
+
} catch (error) {
|
|
761
|
+
this.#logger?.error(error, 'Error in Adapter.getJobById()')
|
|
762
|
+
throw error
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
/**
|
|
767
|
+
* Get steps for a job with pagination and fuzzy search.
|
|
768
|
+
* Steps are always ordered by created_at ASC.
|
|
769
|
+
* Steps do not include output data.
|
|
770
|
+
*
|
|
771
|
+
* @param options - Query options including jobId, pagination, and search
|
|
772
|
+
* @returns Promise resolving to steps result with pagination info
|
|
773
|
+
*/
|
|
774
|
+
async getJobSteps(options: GetJobStepsOptions): Promise<GetJobStepsResult> {
|
|
775
|
+
try {
|
|
776
|
+
const parsedOptions = GetJobStepsOptionsSchema.parse(options)
|
|
777
|
+
const result = await this._getJobSteps(parsedOptions)
|
|
778
|
+
return GetJobStepsResultSchema.parse(result)
|
|
779
|
+
} catch (error) {
|
|
780
|
+
this.#logger?.error(error, 'Error in Adapter.getJobSteps()')
|
|
781
|
+
throw error
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
/**
|
|
786
|
+
* Get jobs with pagination, filtering, and sorting.
|
|
787
|
+
* Does not include step information or job output.
|
|
788
|
+
*
|
|
789
|
+
* @param options - Query options including pagination, filters, and sort
|
|
790
|
+
* @returns Promise resolving to jobs result with pagination info
|
|
791
|
+
*/
|
|
792
|
+
async getJobs(options?: GetJobsOptions): Promise<GetJobsResult> {
|
|
793
|
+
try {
|
|
794
|
+
const parsedOptions = options ? GetJobsOptionsSchema.parse(options) : undefined
|
|
795
|
+
const result = await this._getJobs(parsedOptions)
|
|
796
|
+
return GetJobsResultSchema.parse(result)
|
|
797
|
+
} catch (error) {
|
|
798
|
+
this.#logger?.error(error, 'Error in Adapter.getJobs()')
|
|
799
|
+
throw error
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
/**
|
|
804
|
+
* Get a step by its ID with all information.
|
|
805
|
+
*
|
|
806
|
+
* @param stepId - The ID of the step to retrieve
|
|
807
|
+
* @returns Promise resolving to the step, or `null` if not found
|
|
808
|
+
*/
|
|
809
|
+
async getJobStepById(stepId: string): Promise<JobStep | null> {
|
|
810
|
+
try {
|
|
811
|
+
const parsedStepId = z.string().parse(stepId)
|
|
812
|
+
const result = await this._getJobStepById(parsedStepId)
|
|
813
|
+
if (result === null) {
|
|
814
|
+
return null
|
|
815
|
+
}
|
|
816
|
+
return JobStepSchema.parse(result)
|
|
817
|
+
} catch (error) {
|
|
818
|
+
this.#logger?.error(error, 'Error in Adapter.getJobStepById()')
|
|
819
|
+
throw error
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
/**
|
|
824
|
+
* Get job status and updatedAt timestamp.
|
|
825
|
+
*
|
|
826
|
+
* @param jobId - The ID of the job
|
|
827
|
+
* @returns Promise resolving to job status result, or `null` if not found
|
|
828
|
+
*/
|
|
829
|
+
async getJobStatus(jobId: string): Promise<JobStatusResult | null> {
|
|
830
|
+
try {
|
|
831
|
+
const parsedJobId = z.string().parse(jobId)
|
|
832
|
+
const result = await this._getJobStatus(parsedJobId)
|
|
833
|
+
if (result === null) {
|
|
834
|
+
return null
|
|
835
|
+
}
|
|
836
|
+
return JobStatusResultSchema.parse(result)
|
|
837
|
+
} catch (error) {
|
|
838
|
+
this.#logger?.error(error, 'Error in Adapter.getJobStatus()')
|
|
839
|
+
throw error
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
/**
|
|
844
|
+
* Get job step status and updatedAt timestamp.
|
|
845
|
+
*
|
|
846
|
+
* @param stepId - The ID of the step
|
|
847
|
+
* @returns Promise resolving to step status result, or `null` if not found
|
|
848
|
+
*/
|
|
849
|
+
async getJobStepStatus(stepId: string): Promise<JobStepStatusResult | null> {
|
|
850
|
+
try {
|
|
851
|
+
const parsedStepId = z.string().parse(stepId)
|
|
852
|
+
const result = await this._getJobStepStatus(parsedStepId)
|
|
853
|
+
if (result === null) {
|
|
854
|
+
return null
|
|
855
|
+
}
|
|
856
|
+
return JobStepStatusResultSchema.parse(result)
|
|
857
|
+
} catch (error) {
|
|
858
|
+
this.#logger?.error(error, 'Error in Adapter.getJobStepStatus()')
|
|
859
|
+
throw error
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
/**
|
|
864
|
+
* Get action statistics including counts and last job created date.
|
|
865
|
+
*
|
|
866
|
+
* @returns Promise resolving to action statistics
|
|
867
|
+
*/
|
|
868
|
+
async getActions(): Promise<GetActionsResult> {
|
|
869
|
+
try {
|
|
870
|
+
const result = await this._getActions()
|
|
871
|
+
return GetActionsResultSchema.parse(result)
|
|
872
|
+
} catch (error) {
|
|
873
|
+
this.#logger?.error(error, 'Error in Adapter.getActions()')
|
|
874
|
+
throw error
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
// ============================================================================
|
|
879
|
+
// Private Query Methods (to be implemented by adapters)
|
|
880
|
+
// ============================================================================
|
|
881
|
+
|
|
882
|
+
/**
|
|
883
|
+
* Internal method to get a job by its ID. Does not include step information.
|
|
884
|
+
*
|
|
885
|
+
* @param jobId - The validated ID of the job to retrieve
|
|
886
|
+
* @returns Promise resolving to the job, or `null` if not found
|
|
887
|
+
*/
|
|
888
|
+
protected abstract _getJobById(jobId: string): Promise<Job | null>
|
|
889
|
+
|
|
890
|
+
/**
|
|
891
|
+
* Internal method to get steps for a job with pagination and fuzzy search.
|
|
892
|
+
* Steps are always ordered by created_at ASC.
|
|
893
|
+
* Steps do not include output data.
|
|
894
|
+
*
|
|
895
|
+
* @param options - Validated query options including jobId, pagination, and search
|
|
896
|
+
* @returns Promise resolving to steps result with pagination info
|
|
897
|
+
*/
|
|
898
|
+
protected abstract _getJobSteps(options: GetJobStepsOptions): Promise<GetJobStepsResult>
|
|
899
|
+
|
|
900
|
+
/**
|
|
901
|
+
* Internal method to get jobs with pagination, filtering, and sorting.
|
|
902
|
+
* Does not include step information or job output.
|
|
903
|
+
*
|
|
904
|
+
* @param options - Validated query options including pagination, filters, and sort
|
|
905
|
+
* @returns Promise resolving to jobs result with pagination info
|
|
906
|
+
*/
|
|
907
|
+
protected abstract _getJobs(options?: GetJobsOptions): Promise<GetJobsResult>
|
|
908
|
+
|
|
909
|
+
/**
|
|
910
|
+
* Internal method to get a step by its ID with all information.
|
|
911
|
+
*
|
|
912
|
+
* @param stepId - The validated ID of the step to retrieve
|
|
913
|
+
* @returns Promise resolving to the step, or `null` if not found
|
|
914
|
+
*/
|
|
915
|
+
protected abstract _getJobStepById(stepId: string): Promise<JobStep | null>
|
|
916
|
+
|
|
917
|
+
/**
|
|
918
|
+
* Internal method to get job status and updatedAt timestamp.
|
|
919
|
+
*
|
|
920
|
+
* @param jobId - The validated ID of the job
|
|
921
|
+
* @returns Promise resolving to job status result, or `null` if not found
|
|
922
|
+
*/
|
|
923
|
+
protected abstract _getJobStatus(jobId: string): Promise<JobStatusResult | null>
|
|
924
|
+
|
|
925
|
+
/**
|
|
926
|
+
* Internal method to get job step status and updatedAt timestamp.
|
|
927
|
+
*
|
|
928
|
+
* @param stepId - The validated ID of the step
|
|
929
|
+
* @returns Promise resolving to step status result, or `null` if not found
|
|
930
|
+
*/
|
|
931
|
+
protected abstract _getJobStepStatus(stepId: string): Promise<JobStepStatusResult | null>
|
|
932
|
+
|
|
933
|
+
/**
|
|
934
|
+
* Internal method to get action statistics including counts and last job created date.
|
|
935
|
+
*
|
|
936
|
+
* @returns Promise resolving to action statistics
|
|
937
|
+
*/
|
|
938
|
+
protected abstract _getActions(): Promise<GetActionsResult>
|
|
939
|
+
|
|
940
|
+
// ============================================================================
|
|
941
|
+
// Protected Abstract Methods (to be implemented by adapters)
|
|
942
|
+
// ============================================================================
|
|
943
|
+
|
|
944
|
+
/**
|
|
945
|
+
* Start the adapter.
|
|
946
|
+
* Performs any necessary initialization, such as running migrations or setting up listeners.
|
|
947
|
+
*
|
|
948
|
+
* @returns Promise resolving to `void`
|
|
949
|
+
*/
|
|
950
|
+
protected abstract _start(): Promise<void>
|
|
951
|
+
|
|
952
|
+
/**
|
|
953
|
+
* Stop the adapter.
|
|
954
|
+
* Performs cleanup, such as closing database connections.
|
|
955
|
+
*
|
|
956
|
+
* @returns Promise resolving to `void`
|
|
957
|
+
*/
|
|
958
|
+
protected abstract _stop(): Promise<void>
|
|
959
|
+
|
|
960
|
+
/**
|
|
961
|
+
* Send a notification event.
|
|
962
|
+
* This is adapter-specific (e.g., PostgreSQL NOTIFY).
|
|
963
|
+
*
|
|
964
|
+
* @param event - The event name
|
|
965
|
+
* @param data - The data to send
|
|
966
|
+
* @returns Promise resolving to `void`
|
|
967
|
+
*/
|
|
968
|
+
protected abstract _notify(event: string, data: any): Promise<void>
|
|
969
|
+
}
|