@cedarjs/jobs 8.0.0-canary.3421 → 8.0.0-canary.3423
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/dist/adapters/BaseAdapter/BaseAdapter.d.ts +54 -0
- package/dist/adapters/BaseAdapter/BaseAdapter.d.ts.map +1 -1
- package/dist/adapters/BaseAdapter/BaseAdapter.js +6 -0
- package/dist/adapters/PrismaAdapter/PrismaAdapter.d.ts +36 -4
- package/dist/adapters/PrismaAdapter/PrismaAdapter.d.ts.map +1 -1
- package/dist/adapters/PrismaAdapter/PrismaAdapter.js +190 -22
- package/dist/adapters/PrismaAdapter/errors.d.ts +7 -0
- package/dist/adapters/PrismaAdapter/errors.d.ts.map +1 -1
- package/dist/adapters/PrismaAdapter/errors.js +8 -0
- package/dist/bins/cedar-jobs-worker.d.ts.map +1 -1
- package/dist/bins/cedar-jobs-worker.js +3 -0
- package/dist/consts.d.ts +9 -0
- package/dist/consts.d.ts.map +1 -1
- package/dist/consts.js +7 -1
- package/dist/core/Executor.d.ts.map +1 -1
- package/dist/core/Executor.js +11 -4
- package/dist/core/JobManager.d.ts +20 -1
- package/dist/core/JobManager.d.ts.map +1 -1
- package/dist/core/JobManager.js +122 -1
- package/dist/core/Scheduler.d.ts.map +1 -1
- package/dist/core/Scheduler.js +16 -3
- package/dist/errors.d.ts +29 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +30 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -2
- package/dist/loaders.d.ts +29 -0
- package/dist/loaders.d.ts.map +1 -1
- package/dist/loaders.js +48 -1
- package/dist/types.d.ts +101 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -4
|
@@ -7,6 +7,38 @@ export interface SchedulePayload {
|
|
|
7
7
|
runAt: Date;
|
|
8
8
|
queue: string;
|
|
9
9
|
priority: number;
|
|
10
|
+
/**
|
|
11
|
+
* The job's unique key, if it was scheduled with one. Only passed to
|
|
12
|
+
* adapters that set `supportsUniqueKeys`. While a job with this key is
|
|
13
|
+
* still queued, the adapter must not add another one (see
|
|
14
|
+
* `ScheduleJobOptions['key']`)
|
|
15
|
+
*/
|
|
16
|
+
key?: string | undefined;
|
|
17
|
+
}
|
|
18
|
+
/** A recurring schedule declared in code, as passed to `syncSchedules()` */
|
|
19
|
+
export interface ScheduleDefinition extends SchedulePayload {
|
|
20
|
+
cron: string;
|
|
21
|
+
/**
|
|
22
|
+
* The schedule's identity: `SCHEDULE_KEY_PREFIX`, the job's name and the
|
|
23
|
+
* schedule's own key, like `cedar:schedule:ReportJob:nightly`
|
|
24
|
+
*/
|
|
25
|
+
key: string;
|
|
26
|
+
}
|
|
27
|
+
export interface SyncSchedulesOptions {
|
|
28
|
+
/** Every schedule declared in the app's code */
|
|
29
|
+
schedules: ScheduleDefinition[];
|
|
30
|
+
/**
|
|
31
|
+
* Every schedule key starts with this prefix. Stored schedules with this
|
|
32
|
+
* prefix that are not in `schedules` must be removed
|
|
33
|
+
*/
|
|
34
|
+
keyPrefix: string;
|
|
35
|
+
}
|
|
36
|
+
/** The keys of the schedules `syncSchedules()` touched, by what it did */
|
|
37
|
+
export interface SyncSchedulesResult {
|
|
38
|
+
created: string[];
|
|
39
|
+
updated: string[];
|
|
40
|
+
removed: string[];
|
|
41
|
+
unchanged: string[];
|
|
10
42
|
}
|
|
11
43
|
export interface FindArgs {
|
|
12
44
|
processName: string;
|
|
@@ -108,6 +140,12 @@ export interface ListedJob {
|
|
|
108
140
|
export declare abstract class BaseAdapter<TOptions extends BaseAdapterOptions = BaseAdapterOptions, TScheduleReturn = unknown> {
|
|
109
141
|
options: TOptions;
|
|
110
142
|
logger: NonNullable<TOptions['logger']>;
|
|
143
|
+
/**
|
|
144
|
+
* Whether `schedule()` honors `payload.key` (see `SchedulePayload['key']`).
|
|
145
|
+
* Scheduling a job with a `key` through an adapter that doesn't throws a
|
|
146
|
+
* `UniqueKeysNotSupportedError`, so a key is never silently ignored
|
|
147
|
+
*/
|
|
148
|
+
readonly supportsUniqueKeys: boolean;
|
|
111
149
|
constructor(options: TOptions);
|
|
112
150
|
abstract schedule(payload: SchedulePayload): TScheduleReturn;
|
|
113
151
|
/**
|
|
@@ -151,6 +189,22 @@ export declare abstract class BaseAdapter<TOptions extends BaseAdapterOptions =
|
|
|
151
189
|
* cancellation and `later.cancel()` will throw a `CancelNotImplementedError`
|
|
152
190
|
*/
|
|
153
191
|
cancel?(options: CancelOptions): boolean | Promise<boolean>;
|
|
192
|
+
/**
|
|
193
|
+
* Makes the stored recurring schedules match `options.schedules`, the ones
|
|
194
|
+
* declared in code. Called by every job worker when it starts, so several
|
|
195
|
+
* calls can run at the same time and must not create duplicates:
|
|
196
|
+
* - a declared schedule without a stored job is created, with its `runAt`
|
|
197
|
+
* at the next match of its `cron`
|
|
198
|
+
* - a stored schedule whose job name, path, args, queue, priority or cron
|
|
199
|
+
* differ from the declaration is updated
|
|
200
|
+
* - a stored schedule (key starting with `options.keyPrefix`) that is not
|
|
201
|
+
* declared any more is removed
|
|
202
|
+
*
|
|
203
|
+
* This method is optional: declaring `schedules` on a job with an adapter
|
|
204
|
+
* that doesn't implement it makes the workers throw a
|
|
205
|
+
* `SchedulesNotSupportedError` when they start
|
|
206
|
+
*/
|
|
207
|
+
syncSchedules?(options: SyncSchedulesOptions): SyncSchedulesResult | Promise<SyncSchedulesResult>;
|
|
154
208
|
/**
|
|
155
209
|
* Pause a job, so that no worker picks it up until it's resumed. A run in
|
|
156
210
|
* progress finishes, and a recurring job's next run stays paused: `success()`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BaseAdapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/BaseAdapter/BaseAdapter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAG3E,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,OAAO,EAAE,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACzB,KAAK,EAAE,IAAI,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"BaseAdapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/BaseAdapter/BaseAdapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,12 @@ import { DEFAULT_LOGGER } from "../../consts.js";
|
|
|
2
2
|
class BaseAdapter {
|
|
3
3
|
options;
|
|
4
4
|
logger;
|
|
5
|
+
/**
|
|
6
|
+
* Whether `schedule()` honors `payload.key` (see `SchedulePayload['key']`).
|
|
7
|
+
* Scheduling a job with a `key` through an adapter that doesn't throws a
|
|
8
|
+
* `UniqueKeysNotSupportedError`, so a key is never silently ignored
|
|
9
|
+
*/
|
|
10
|
+
supportsUniqueKeys = false;
|
|
5
11
|
constructor(options) {
|
|
6
12
|
this.options = options;
|
|
7
13
|
this.logger = options?.logger ?? DEFAULT_LOGGER;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { BaseJob } from '../../types.js';
|
|
2
|
-
import type { BaseAdapterOptions, ListedJob, ListJobsOptions, PauseOptions, PauseResult, ResumeOptions, ResumeResult, SchedulePayload, FindArgs, SuccessOptions, ErrorOptions, FailureOptions, CancelOptions } from '../BaseAdapter/BaseAdapter.js';
|
|
2
|
+
import type { BaseAdapterOptions, ListedJob, ListJobsOptions, PauseOptions, PauseResult, ResumeOptions, ResumeResult, SchedulePayload, SyncSchedulesOptions, SyncSchedulesResult, FindArgs, SuccessOptions, ErrorOptions, FailureOptions, CancelOptions } from '../BaseAdapter/BaseAdapter.js';
|
|
3
3
|
import { BaseAdapter } from '../BaseAdapter/BaseAdapter.js';
|
|
4
4
|
export interface PrismaJob extends BaseJob {
|
|
5
5
|
id: number;
|
|
@@ -22,6 +22,20 @@ export interface PrismaJob extends BaseJob {
|
|
|
22
22
|
pausedAt?: Date | null;
|
|
23
23
|
createdAt: Date;
|
|
24
24
|
updatedAt: Date;
|
|
25
|
+
/**
|
|
26
|
+
* The job's unique key. Only queued jobs and active recurring jobs hold
|
|
27
|
+
* their key, it's null once a worker has picked up a non-recurring job.
|
|
28
|
+
* Undefined when the model has no `key` column
|
|
29
|
+
*/
|
|
30
|
+
key?: string | null;
|
|
31
|
+
}
|
|
32
|
+
/** What `schedule()` returns: the stored job */
|
|
33
|
+
export interface ScheduledPrismaJob extends PrismaJob {
|
|
34
|
+
/**
|
|
35
|
+
* `true` when the job was scheduled with a `key` and a job with that key
|
|
36
|
+
* was already queued. No new job was added, and this is the queued job
|
|
37
|
+
*/
|
|
38
|
+
alreadyQueued: boolean;
|
|
25
39
|
}
|
|
26
40
|
interface PrismaAdapterDelegate {
|
|
27
41
|
findFirst(args: Record<string, unknown>): Promise<any>;
|
|
@@ -32,7 +46,7 @@ interface PrismaAdapterDelegate {
|
|
|
32
46
|
update(args: Record<string, unknown>): Promise<unknown>;
|
|
33
47
|
create(args: Record<string, unknown>): Promise<unknown>;
|
|
34
48
|
deleteMany(args?: Record<string, unknown>): Promise<unknown>;
|
|
35
|
-
/** Every Prisma delegate has it. Only `list()`
|
|
49
|
+
/** Every Prisma delegate has it. Only `syncSchedules()` and `list()` use it */
|
|
36
50
|
findMany?(args: Record<string, unknown>): Promise<any[]>;
|
|
37
51
|
}
|
|
38
52
|
interface DelegateLike {
|
|
@@ -96,8 +110,9 @@ export interface PrismaAdapterOptions<TDb extends object = object> extends BaseA
|
|
|
96
110
|
* }
|
|
97
111
|
* ```
|
|
98
112
|
*/
|
|
99
|
-
export declare class PrismaAdapter<TDb extends object = object> extends BaseAdapter<PrismaAdapterOptions<TDb>, Promise<
|
|
113
|
+
export declare class PrismaAdapter<TDb extends object = object> extends BaseAdapter<PrismaAdapterOptions<TDb>, Promise<ScheduledPrismaJob>> {
|
|
100
114
|
#private;
|
|
115
|
+
readonly supportsUniqueKeys = true;
|
|
101
116
|
db: TDb;
|
|
102
117
|
model: DelegateKey<TDb> | string;
|
|
103
118
|
accessor: PrismaAdapterDelegate;
|
|
@@ -113,7 +128,24 @@ export declare class PrismaAdapter<TDb extends object = object> extends BaseAdap
|
|
|
113
128
|
success({ job, runAt, deleteJob }: SuccessOptions<PrismaJob>): Promise<void>;
|
|
114
129
|
error({ job, runAt, error }: ErrorOptions<PrismaJob>): Promise<void>;
|
|
115
130
|
failure({ job, deleteJob, error }: FailureOptions<PrismaJob>): Promise<void>;
|
|
116
|
-
|
|
131
|
+
/**
|
|
132
|
+
* Schedules a job by creating a new record in the background job table.
|
|
133
|
+
* Returns the created job so that callers get access to its `id` (to cancel
|
|
134
|
+
* it later, poll its status, etc.)
|
|
135
|
+
*
|
|
136
|
+
* With a `key`, the `key` column's unique constraint makes sure only one
|
|
137
|
+
* queued job holds the key, also when several processes schedule at once.
|
|
138
|
+
* If the insert hits the constraint, the job that holds the key is
|
|
139
|
+
* returned with `alreadyQueued: true` instead
|
|
140
|
+
*/
|
|
141
|
+
schedule({ name, path, args, runAt, cron, queue, priority, key, }: SchedulePayload): Promise<ScheduledPrismaJob>;
|
|
142
|
+
/**
|
|
143
|
+
* Makes the stored declared schedules match `schedules`. Each schedule is
|
|
144
|
+
* one row, identified by its unique `key`, so concurrent syncs can't create
|
|
145
|
+
* duplicates: an insert that hits the unique constraint compares against
|
|
146
|
+
* (and if needed updates) the row the other sync created instead
|
|
147
|
+
*/
|
|
148
|
+
syncSchedules({ schedules, keyPrefix, }: SyncSchedulesOptions): Promise<SyncSchedulesResult>;
|
|
117
149
|
/**
|
|
118
150
|
* Cancels a job by marking it as permanently failed so no worker will pick
|
|
119
151
|
* it up (or retry it, if it's currently being worked on).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PrismaAdapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/PrismaAdapter/PrismaAdapter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"PrismaAdapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/PrismaAdapter/PrismaAdapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,10 +4,19 @@ import {
|
|
|
4
4
|
DEFAULT_MODEL_NAME,
|
|
5
5
|
MAX_RUNTIME_GRACE_PERIOD
|
|
6
6
|
} from "../../consts.js";
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
CedarJSJobsError,
|
|
9
|
+
JobIdNotFoundError,
|
|
10
|
+
JobNotActiveError
|
|
11
|
+
} from "../../errors.js";
|
|
8
12
|
import { nextCronRunAt } from "../../util.js";
|
|
9
13
|
import { BaseAdapter } from "../BaseAdapter/BaseAdapter.js";
|
|
10
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
KeyColumnMissingError,
|
|
16
|
+
ModelNameError,
|
|
17
|
+
PausedAtColumnMissingError
|
|
18
|
+
} from "./errors.js";
|
|
19
|
+
const MAX_KEY_RETRIES = 5;
|
|
11
20
|
function isPrismaAdapterDelegate(value) {
|
|
12
21
|
const candidate = value;
|
|
13
22
|
return candidate !== null && typeof candidate === "object" && typeof candidate.findFirst === "function" && typeof candidate.updateMany === "function" && typeof candidate.delete === "function" && typeof candidate.update === "function" && typeof candidate.create === "function" && typeof candidate.deleteMany === "function";
|
|
@@ -29,10 +38,24 @@ function getActiveProvider(db) {
|
|
|
29
38
|
}
|
|
30
39
|
return provider;
|
|
31
40
|
}
|
|
41
|
+
function isUniqueViolation(e) {
|
|
42
|
+
return typeof e === "object" && e !== null && "code" in e && e.code === "P2002";
|
|
43
|
+
}
|
|
44
|
+
function isMissingKeyColumn(e) {
|
|
45
|
+
return e instanceof Error && e.name === "PrismaClientValidationError" && /Unknown (argument|field) `key`/.test(e.message);
|
|
46
|
+
}
|
|
47
|
+
function releaseKey(job) {
|
|
48
|
+
return job.key != null ? { key: null } : {};
|
|
49
|
+
}
|
|
50
|
+
function rowToJob(row) {
|
|
51
|
+
const { name, path, args } = JSON.parse(row.handler);
|
|
52
|
+
return { ...row, name, path, args };
|
|
53
|
+
}
|
|
32
54
|
function isMissingPausedAtColumn(e) {
|
|
33
55
|
return e instanceof Error && e.name === "PrismaClientValidationError" && /Unknown (argument|field) `pausedAt`/.test(e.message);
|
|
34
56
|
}
|
|
35
57
|
class PrismaAdapter extends BaseAdapter {
|
|
58
|
+
supportsUniqueKeys = true;
|
|
36
59
|
db;
|
|
37
60
|
model;
|
|
38
61
|
accessor;
|
|
@@ -93,7 +116,6 @@ class PrismaAdapter extends BaseAdapter {
|
|
|
93
116
|
...queues.length > 1 || queues[0] !== "*" ? [{ queue: { in: queues } }] : []
|
|
94
117
|
];
|
|
95
118
|
const findCandidate = (withPausedAt) => this.accessor.findFirst({
|
|
96
|
-
select: { id: true, attempts: true },
|
|
97
119
|
where: { AND: conditions(withPausedAt) },
|
|
98
120
|
orderBy: [{ priority: "asc" }, { runAt: "asc" }],
|
|
99
121
|
take: 1
|
|
@@ -122,13 +144,15 @@ class PrismaAdapter extends BaseAdapter {
|
|
|
122
144
|
data: {
|
|
123
145
|
lockedAt: /* @__PURE__ */ new Date(),
|
|
124
146
|
lockedBy: processName,
|
|
125
|
-
attempts: job.attempts + 1
|
|
147
|
+
attempts: job.attempts + 1,
|
|
148
|
+
...job.cron ? {} : releaseKey(job)
|
|
126
149
|
}
|
|
127
150
|
});
|
|
128
151
|
if (count) {
|
|
129
152
|
const data = await this.accessor.findFirst({ where: { id: job.id } });
|
|
130
|
-
|
|
131
|
-
|
|
153
|
+
if (data) {
|
|
154
|
+
return rowToJob(data);
|
|
155
|
+
}
|
|
132
156
|
}
|
|
133
157
|
}
|
|
134
158
|
return void 0;
|
|
@@ -216,7 +240,8 @@ ${error.stack}`,
|
|
|
216
240
|
} else {
|
|
217
241
|
const data = {
|
|
218
242
|
failedAt: /* @__PURE__ */ new Date(),
|
|
219
|
-
runAt: null
|
|
243
|
+
runAt: null,
|
|
244
|
+
...releaseKey(job)
|
|
220
245
|
};
|
|
221
246
|
if (error) {
|
|
222
247
|
data.lastError = `${error.message}
|
|
@@ -229,9 +254,16 @@ ${error.stack}`;
|
|
|
229
254
|
});
|
|
230
255
|
}
|
|
231
256
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
257
|
+
/**
|
|
258
|
+
* Schedules a job by creating a new record in the background job table.
|
|
259
|
+
* Returns the created job so that callers get access to its `id` (to cancel
|
|
260
|
+
* it later, poll its status, etc.)
|
|
261
|
+
*
|
|
262
|
+
* With a `key`, the `key` column's unique constraint makes sure only one
|
|
263
|
+
* queued job holds the key, also when several processes schedule at once.
|
|
264
|
+
* If the insert hits the constraint, the job that holds the key is
|
|
265
|
+
* returned with `alreadyQueued: true` instead
|
|
266
|
+
*/
|
|
235
267
|
async schedule({
|
|
236
268
|
name,
|
|
237
269
|
path,
|
|
@@ -239,19 +271,151 @@ ${error.stack}`;
|
|
|
239
271
|
runAt,
|
|
240
272
|
cron,
|
|
241
273
|
queue,
|
|
242
|
-
priority
|
|
274
|
+
priority,
|
|
275
|
+
key
|
|
243
276
|
}) {
|
|
244
|
-
const
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
277
|
+
const job = { name, path, args };
|
|
278
|
+
const data = {
|
|
279
|
+
handler: JSON.stringify(job),
|
|
280
|
+
runAt,
|
|
281
|
+
cron,
|
|
282
|
+
queue,
|
|
283
|
+
priority,
|
|
284
|
+
...key !== void 0 ? { key } : {}
|
|
285
|
+
};
|
|
286
|
+
if (key === void 0) {
|
|
287
|
+
return { ...await this.#create(data, job), alreadyQueued: false };
|
|
288
|
+
}
|
|
289
|
+
for (let attempt = 0; attempt <= MAX_KEY_RETRIES; attempt++) {
|
|
290
|
+
try {
|
|
291
|
+
return { ...await this.#create(data, job), alreadyQueued: false };
|
|
292
|
+
} catch (e) {
|
|
293
|
+
if (!isUniqueViolation(e)) {
|
|
294
|
+
throw e;
|
|
295
|
+
}
|
|
251
296
|
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
297
|
+
const queued = await this.accessor.findFirst({ where: { key } });
|
|
298
|
+
if (queued) {
|
|
299
|
+
return { ...rowToJob(queued), alreadyQueued: true };
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
throw new CedarJSJobsError(
|
|
303
|
+
`Could not schedule ${name} with the key \`${key}\`: the key was taken and released again ${MAX_KEY_RETRIES + 1} times in a row`
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
async #create(data, job) {
|
|
307
|
+
let row;
|
|
308
|
+
try {
|
|
309
|
+
row = await this.accessor.create({ data });
|
|
310
|
+
} catch (e) {
|
|
311
|
+
if (isMissingKeyColumn(e)) {
|
|
312
|
+
throw new KeyColumnMissingError(String(this.model));
|
|
313
|
+
}
|
|
314
|
+
throw e;
|
|
315
|
+
}
|
|
316
|
+
return { ...row, ...job };
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Makes the stored declared schedules match `schedules`. Each schedule is
|
|
320
|
+
* one row, identified by its unique `key`, so concurrent syncs can't create
|
|
321
|
+
* duplicates: an insert that hits the unique constraint compares against
|
|
322
|
+
* (and if needed updates) the row the other sync created instead
|
|
323
|
+
*/
|
|
324
|
+
async syncSchedules({
|
|
325
|
+
schedules,
|
|
326
|
+
keyPrefix
|
|
327
|
+
}) {
|
|
328
|
+
const result = {
|
|
329
|
+
created: [],
|
|
330
|
+
updated: [],
|
|
331
|
+
removed: [],
|
|
332
|
+
unchanged: []
|
|
333
|
+
};
|
|
334
|
+
if (!this.accessor.findMany) {
|
|
335
|
+
throw new ModelNameError(String(this.model));
|
|
336
|
+
}
|
|
337
|
+
let stored;
|
|
338
|
+
try {
|
|
339
|
+
stored = await this.accessor.findMany({
|
|
340
|
+
where: { key: { startsWith: keyPrefix } }
|
|
341
|
+
});
|
|
342
|
+
} catch (e) {
|
|
343
|
+
if (!isMissingKeyColumn(e)) {
|
|
344
|
+
throw e;
|
|
345
|
+
}
|
|
346
|
+
if (schedules.length === 0) {
|
|
347
|
+
return result;
|
|
348
|
+
}
|
|
349
|
+
throw new KeyColumnMissingError(String(this.model));
|
|
350
|
+
}
|
|
351
|
+
const storedByKey = new Map(stored.map((row) => [row.key, row]));
|
|
352
|
+
for (const schedule of schedules) {
|
|
353
|
+
const outcome = await this.#syncSchedule(
|
|
354
|
+
schedule,
|
|
355
|
+
storedByKey.get(schedule.key)
|
|
356
|
+
);
|
|
357
|
+
result[outcome].push(schedule.key);
|
|
358
|
+
}
|
|
359
|
+
const declared = new Set(schedules.map((schedule) => schedule.key));
|
|
360
|
+
const undeclared = stored.map((row) => row.key).filter((key) => !!key && !declared.has(key));
|
|
361
|
+
if (undeclared.length > 0) {
|
|
362
|
+
await this.accessor.deleteMany({ where: { key: { in: undeclared } } });
|
|
363
|
+
result.removed.push(...undeclared);
|
|
364
|
+
}
|
|
365
|
+
return result;
|
|
366
|
+
}
|
|
367
|
+
async #syncSchedule(schedule, stored) {
|
|
368
|
+
const { name, path, args, cron, runAt, queue, priority, key } = schedule;
|
|
369
|
+
const handler = JSON.stringify({ name, path, args });
|
|
370
|
+
let row = stored;
|
|
371
|
+
for (let attempt = 0; attempt <= MAX_KEY_RETRIES; attempt++) {
|
|
372
|
+
if (!row) {
|
|
373
|
+
try {
|
|
374
|
+
await this.accessor.create({
|
|
375
|
+
data: { handler, runAt, cron, queue, priority, key }
|
|
376
|
+
});
|
|
377
|
+
return "created";
|
|
378
|
+
} catch (e) {
|
|
379
|
+
if (!isUniqueViolation(e)) {
|
|
380
|
+
throw e;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
row = await this.accessor.findFirst({ where: { key } });
|
|
384
|
+
if (!row) {
|
|
385
|
+
continue;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
const changes = {};
|
|
389
|
+
if (row.handler !== handler) {
|
|
390
|
+
changes.handler = handler;
|
|
391
|
+
}
|
|
392
|
+
if (row.queue !== queue) {
|
|
393
|
+
changes.queue = queue;
|
|
394
|
+
}
|
|
395
|
+
if (row.priority !== priority) {
|
|
396
|
+
changes.priority = priority;
|
|
397
|
+
}
|
|
398
|
+
if (row.cron !== cron) {
|
|
399
|
+
changes.cron = cron;
|
|
400
|
+
if (!row.lockedAt) {
|
|
401
|
+
changes.runAt = runAt;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
if (Object.keys(changes).length === 0) {
|
|
405
|
+
return "unchanged";
|
|
406
|
+
}
|
|
407
|
+
const { count } = await this.accessor.updateMany({
|
|
408
|
+
where: { id: row.id },
|
|
409
|
+
data: changes
|
|
410
|
+
});
|
|
411
|
+
if (count > 0) {
|
|
412
|
+
return "updated";
|
|
413
|
+
}
|
|
414
|
+
row = void 0;
|
|
415
|
+
}
|
|
416
|
+
throw new CedarJSJobsError(
|
|
417
|
+
`Could not sync the schedule \`${key}\`: it was created and removed again ${MAX_KEY_RETRIES + 1} times in a row`
|
|
418
|
+
);
|
|
255
419
|
}
|
|
256
420
|
/**
|
|
257
421
|
* Cancels a job by marking it as permanently failed so no worker will pick
|
|
@@ -264,12 +428,16 @@ ${error.stack}`;
|
|
|
264
428
|
*/
|
|
265
429
|
async cancel({ jobId }) {
|
|
266
430
|
this.logger.debug(`[CedarJS Jobs] Cancelling job ${jobId}`);
|
|
431
|
+
const job = await this.accessor.findFirst({
|
|
432
|
+
where: { id: jobId }
|
|
433
|
+
});
|
|
267
434
|
const { count } = await this.accessor.updateMany({
|
|
268
435
|
where: { id: jobId, failedAt: null, runAt: { not: null } },
|
|
269
436
|
data: {
|
|
270
437
|
failedAt: /* @__PURE__ */ new Date(),
|
|
271
438
|
lastError: "Job cancelled by user",
|
|
272
|
-
runAt: null
|
|
439
|
+
runAt: null,
|
|
440
|
+
...releaseKey(job ?? {})
|
|
273
441
|
}
|
|
274
442
|
});
|
|
275
443
|
return count > 0;
|
|
@@ -5,6 +5,13 @@ import { CedarJSJobsError } from '../../errors.js';
|
|
|
5
5
|
export declare class ModelNameError extends CedarJSJobsError {
|
|
6
6
|
constructor(name: string);
|
|
7
7
|
}
|
|
8
|
+
/**
|
|
9
|
+
* Thrown when a job is scheduled with a unique `key`, or jobs declare
|
|
10
|
+
* `schedules`, but the jobs model has no `key` column to store the key in
|
|
11
|
+
*/
|
|
12
|
+
export declare class KeyColumnMissingError extends CedarJSJobsError {
|
|
13
|
+
constructor(model: string);
|
|
14
|
+
}
|
|
8
15
|
/**
|
|
9
16
|
* Thrown when a job is paused or resumed, but the jobs model has no
|
|
10
17
|
* `pausedAt` column to store the pause in
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/adapters/PrismaAdapter/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAElD;;GAEG;AACH,qBAAa,cAAe,SAAQ,gBAAgB;gBACtC,IAAI,EAAE,MAAM;CAGzB;AAED;;;GAGG;AACH,qBAAa,0BAA2B,SAAQ,gBAAgB;gBAClD,KAAK,EAAE,MAAM;CAO1B"}
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/adapters/PrismaAdapter/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAElD;;GAEG;AACH,qBAAa,cAAe,SAAQ,gBAAgB;gBACtC,IAAI,EAAE,MAAM;CAGzB;AAED;;;GAGG;AACH,qBAAa,qBAAsB,SAAQ,gBAAgB;gBAC7C,KAAK,EAAE,MAAM;CAQ1B;AAED;;;GAGG;AACH,qBAAa,0BAA2B,SAAQ,gBAAgB;gBAClD,KAAK,EAAE,MAAM;CAO1B"}
|
|
@@ -4,6 +4,13 @@ class ModelNameError extends CedarJSJobsError {
|
|
|
4
4
|
super(`Model \`${name}\` not found in PrismaClient`);
|
|
5
5
|
}
|
|
6
6
|
}
|
|
7
|
+
class KeyColumnMissingError extends CedarJSJobsError {
|
|
8
|
+
constructor(model) {
|
|
9
|
+
super(
|
|
10
|
+
`The \`${model}\` model has no \`key\` column, which unique job keys and declared schedules need. Add \`key String? @unique\` to the model in your Prisma schema and create a migration with \`yarn cedar prisma migrate dev\``
|
|
11
|
+
);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
7
14
|
class PausedAtColumnMissingError extends CedarJSJobsError {
|
|
8
15
|
constructor(model) {
|
|
9
16
|
super(
|
|
@@ -12,6 +19,7 @@ class PausedAtColumnMissingError extends CedarJSJobsError {
|
|
|
12
19
|
}
|
|
13
20
|
}
|
|
14
21
|
export {
|
|
22
|
+
KeyColumnMissingError,
|
|
15
23
|
ModelNameError,
|
|
16
24
|
PausedAtColumnMissingError
|
|
17
25
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cedar-jobs-worker.d.ts","sourceRoot":"","sources":["../../src/bins/cedar-jobs-worker.ts"],"names":[],"mappings":";AAWA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAwC/C,eAAO,MAAM,WAAW,GAAI,iBAGzB;IACD,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;CAC1B,WAEA,CAAA;AA0BD,eAAO,MAAM,SAAS,GAAU,gCAK7B;IACD,KAAK,EAAE,MAAM,CAAA;IACb,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,OAAO,CAAA;IACd,OAAO,EAAE,OAAO,CAAA;CACjB,
|
|
1
|
+
{"version":3,"file":"cedar-jobs-worker.d.ts","sourceRoot":"","sources":["../../src/bins/cedar-jobs-worker.ts"],"names":[],"mappings":";AAWA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAwC/C,eAAO,MAAM,WAAW,GAAI,iBAGzB;IACD,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;CAC1B,WAEA,CAAA;AA0BD,eAAO,MAAM,SAAS,GAAU,gCAK7B;IACD,KAAK,EAAE,MAAM,CAAA;IACb,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,OAAO,CAAA;IACd,OAAO,EAAE,OAAO,CAAA;CACjB,oBA+BA,CAAA"}
|
package/dist/consts.d.ts
CHANGED
|
@@ -30,6 +30,15 @@ export declare const DEFAULT_PRIORITY = 50;
|
|
|
30
30
|
export declare const DEFAULT_WAIT = 0;
|
|
31
31
|
export declare const DEFAULT_WAIT_UNTIL: null;
|
|
32
32
|
export declare const PROCESS_TITLE_PREFIX = "cedar-jobs-worker";
|
|
33
|
+
/** Job keys starting with this are reserved for keys Cedar creates itself */
|
|
34
|
+
export declare const RESERVED_KEY_PREFIX = "cedar:";
|
|
35
|
+
/**
|
|
36
|
+
* Keys of stored declared schedules start with this, followed by the job's
|
|
37
|
+
* name and the schedule's own key: `cedar:schedule:ReportJob:nightly`
|
|
38
|
+
*/
|
|
39
|
+
export declare const SCHEDULE_KEY_PREFIX = "cedar:schedule:";
|
|
40
|
+
/** The key of a job's schedule when the job has one and it has no `key` */
|
|
41
|
+
export declare const DEFAULT_SCHEDULE_KEY = "default";
|
|
33
42
|
export declare const DEFAULT_MODEL_NAME = "BackgroundJob";
|
|
34
43
|
/**
|
|
35
44
|
* The name of the exported variable from the jobs config file that contains
|
package/dist/consts.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"consts.d.ts","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,oBAAoB,KAAK,CAAA;AACtC,yBAAyB;AACzB,eAAO,MAAM,mBAAmB,QAAS,CAAA;AACzC;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,KAAK,CAAA;AAC1C,gBAAgB;AAChB,eAAO,MAAM,mBAAmB,IAAI,CAAA;AACpC;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,QAA0B,CAAA;AAErD,eAAO,MAAM,8BAA8B,OAAO,CAAA;AAClD,eAAO,MAAM,0BAA0B,QAAQ,CAAA;AAC/C,eAAO,MAAM,cAAc,SAAU,CAAA;AACrC,eAAO,MAAM,aAAa,YAAY,CAAA;AACtC,eAAO,MAAM,kBAAkB,MAAM,CAAA;AACrC,eAAO,MAAM,gBAAgB,KAAK,CAAA;AAClC,eAAO,MAAM,YAAY,IAAI,CAAA;AAC7B,eAAO,MAAM,kBAAkB,MAAO,CAAA;AACtC,eAAO,MAAM,oBAAoB,sBAAsB,CAAA;
|
|
1
|
+
{"version":3,"file":"consts.d.ts","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,oBAAoB,KAAK,CAAA;AACtC,yBAAyB;AACzB,eAAO,MAAM,mBAAmB,QAAS,CAAA;AACzC;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,KAAK,CAAA;AAC1C,gBAAgB;AAChB,eAAO,MAAM,mBAAmB,IAAI,CAAA;AACpC;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,QAA0B,CAAA;AAErD,eAAO,MAAM,8BAA8B,OAAO,CAAA;AAClD,eAAO,MAAM,0BAA0B,QAAQ,CAAA;AAC/C,eAAO,MAAM,cAAc,SAAU,CAAA;AACrC,eAAO,MAAM,aAAa,YAAY,CAAA;AACtC,eAAO,MAAM,kBAAkB,MAAM,CAAA;AACrC,eAAO,MAAM,gBAAgB,KAAK,CAAA;AAClC,eAAO,MAAM,YAAY,IAAI,CAAA;AAC7B,eAAO,MAAM,kBAAkB,MAAO,CAAA;AACtC,eAAO,MAAM,oBAAoB,sBAAsB,CAAA;AACvD,6EAA6E;AAC7E,eAAO,MAAM,mBAAmB,WAAW,CAAA;AAC3C;;;GAGG;AACH,eAAO,MAAM,mBAAmB,oBAAoC,CAAA;AACpE,2EAA2E;AAC3E,eAAO,MAAM,oBAAoB,YAAY,CAAA;AAE7C,eAAO,MAAM,kBAAkB,kBAAkB,CAAA;AAEjD;;;GAGG;AACH,eAAO,MAAM,oBAAoB,YAAY,CAAA;AAC7C;;;GAGG;AACH,eAAO,MAAM,mBAAmB,WAAW,CAAA"}
|
package/dist/consts.js
CHANGED
|
@@ -13,6 +13,9 @@ const DEFAULT_PRIORITY = 50;
|
|
|
13
13
|
const DEFAULT_WAIT = 0;
|
|
14
14
|
const DEFAULT_WAIT_UNTIL = null;
|
|
15
15
|
const PROCESS_TITLE_PREFIX = "cedar-jobs-worker";
|
|
16
|
+
const RESERVED_KEY_PREFIX = "cedar:";
|
|
17
|
+
const SCHEDULE_KEY_PREFIX = `${RESERVED_KEY_PREFIX}schedule:`;
|
|
18
|
+
const DEFAULT_SCHEDULE_KEY = "default";
|
|
16
19
|
const DEFAULT_MODEL_NAME = "BackgroundJob";
|
|
17
20
|
const DEFAULT_ADAPTER_NAME = "adapter";
|
|
18
21
|
const DEFAULT_LOGGER_NAME = "logger";
|
|
@@ -27,11 +30,14 @@ export {
|
|
|
27
30
|
DEFAULT_MODEL_NAME,
|
|
28
31
|
DEFAULT_PRIORITY,
|
|
29
32
|
DEFAULT_QUEUE,
|
|
33
|
+
DEFAULT_SCHEDULE_KEY,
|
|
30
34
|
DEFAULT_SLEEP_DELAY,
|
|
31
35
|
DEFAULT_WAIT,
|
|
32
36
|
DEFAULT_WAIT_UNTIL,
|
|
33
37
|
DEFAULT_WORK_QUEUE,
|
|
34
38
|
MAX_BACKOFF_MS,
|
|
35
39
|
MAX_RUNTIME_GRACE_PERIOD,
|
|
36
|
-
PROCESS_TITLE_PREFIX
|
|
40
|
+
PROCESS_TITLE_PREFIX,
|
|
41
|
+
RESERVED_KEY_PREFIX,
|
|
42
|
+
SCHEDULE_KEY_PREFIX
|
|
37
43
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Executor.d.ts","sourceRoot":"","sources":["../../src/core/Executor.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAA;
|
|
1
|
+
{"version":3,"file":"Executor.d.ts","sourceRoot":"","sources":["../../src/core/Executor.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAA;AAgBzE,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAKvD,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,WAAW,CAAA;IACpB,GAAG,EAAE,OAAO,CAAA;IACZ,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,uCAAuC;IACvC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,6CAA6C;IAC7C,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,iDAAiD;IACjD,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAC/B;AAED,eAAO,MAAM,QAAQ;;;;;;CAMpB,CAAA;AAED,qBAAa,QAAQ;;IACnB,OAAO,EAAE,QAAQ,CAAC,eAAe,CAAC,CAAA;IAClC,OAAO,EAAE,eAAe,CAAC,SAAS,CAAC,CAAA;IACnC,MAAM,EAAE,WAAW,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAA;IAC9C,GAAG,EAAE,OAAO,CAAA;IACZ,WAAW,EAAE,WAAW,CAAC,eAAe,CAAC,aAAa,CAAC,CAAC,CAAA;IACxD,UAAU,EAAE,WAAW,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC,CAAA;IACtD,gBAAgB,EAAE,WAAW,CAAC,eAAe,CAAC,kBAAkB,CAAC,CAAC,CAAA;IAClE,oBAAoB,EAAE,WAAW,CAAC,eAAe,CAAC,sBAAsB,CAAC,CAAC,CAAA;gBAE9D,OAAO,EAAE,eAAe;IAsBpC,IAAI,aAAa,WAEhB;IAED;;;;;;;OAOG;IACG,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;IAuKjC;;;;OAIG;IACH,mBAAmB,CAAC,QAAQ,EAAE,MAAM;CAGrC"}
|
package/dist/core/Executor.js
CHANGED
|
@@ -5,7 +5,8 @@ import {
|
|
|
5
5
|
DEFAULT_DELETE_FAILED_JOBS,
|
|
6
6
|
DEFAULT_DELETE_SUCCESSFUL_JOBS,
|
|
7
7
|
DEFAULT_LOGGER,
|
|
8
|
-
MAX_BACKOFF_MS
|
|
8
|
+
MAX_BACKOFF_MS,
|
|
9
|
+
SCHEDULE_KEY_PREFIX
|
|
9
10
|
} from "../consts.js";
|
|
10
11
|
import {
|
|
11
12
|
AdapterRequiredError,
|
|
@@ -134,12 +135,18 @@ class Executor {
|
|
|
134
135
|
* called only after `failure()` has recorded that (a throwing `failure()`
|
|
135
136
|
* is logged by `#adapterWrite()` instead). A permanently failed recurring
|
|
136
137
|
* (cron) job is not rescheduled, so its schedule stops until the job is
|
|
137
|
-
* scheduled again
|
|
138
|
-
* restart the
|
|
138
|
+
* scheduled again (a declared schedule: until the workers restart and sync
|
|
139
|
+
* it). That is logged at error level, together with how to restart the
|
|
140
|
+
* schedule
|
|
139
141
|
*/
|
|
140
142
|
#logPermanentFailure(reason) {
|
|
141
143
|
const message = `[CedarJS Jobs] Failed job ${this.jobIdentifier}: ${reason}`;
|
|
142
|
-
if (this.job.cron) {
|
|
144
|
+
if (this.job.cron && this.job.key?.startsWith(SCHEDULE_KEY_PREFIX)) {
|
|
145
|
+
this.logger.error(
|
|
146
|
+
this.job,
|
|
147
|
+
`${message}. Its declared schedule (cron: '${this.job.cron}') has stopped until the job workers restart, which recreates it`
|
|
148
|
+
);
|
|
149
|
+
} else if (this.job.cron) {
|
|
143
150
|
this.logger.error(
|
|
144
151
|
this.job,
|
|
145
152
|
`${message}. Its recurring schedule (cron: '${this.job.cron}') has stopped and the job will not run again. To restart it, schedule the job again with \`later(job, args, { cron: '${this.job.cron}' })\``
|