@cedarjs/jobs 7.0.1-next.312 → 7.0.1-next.333
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 +1 -1
- package/dist/adapters/BaseAdapter/BaseAdapter.d.ts.map +1 -1
- package/dist/consts.d.ts +9 -0
- package/dist/consts.d.ts.map +1 -1
- package/dist/consts.js +2 -0
- package/dist/core/Executor.d.ts +15 -1
- package/dist/core/Executor.d.ts.map +1 -1
- package/dist/core/Executor.js +79 -32
- package/dist/core/JobManager.d.ts +1 -1
- package/dist/core/Scheduler.d.ts +1 -1
- package/dist/core/Scheduler.d.ts.map +1 -1
- package/dist/core/Scheduler.js +6 -2
- package/dist/core/Worker.d.ts.map +1 -1
- package/dist/core/Worker.js +3 -2
- package/dist/util.d.ts +6 -0
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +6 -1
- package/package.json +4 -4
|
@@ -49,7 +49,7 @@ export interface CancelOptions {
|
|
|
49
49
|
* be used to configure your custom adapter. If `options.logger` is included
|
|
50
50
|
* you can access it via `this.logger`
|
|
51
51
|
*/
|
|
52
|
-
export declare abstract class BaseAdapter<TOptions extends BaseAdapterOptions = BaseAdapterOptions, TScheduleReturn =
|
|
52
|
+
export declare abstract class BaseAdapter<TOptions extends BaseAdapterOptions = BaseAdapterOptions, TScheduleReturn = unknown> {
|
|
53
53
|
options: TOptions;
|
|
54
54
|
logger: NonNullable<TOptions['logger']>;
|
|
55
55
|
constructor(options: TOptions);
|
|
@@ -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;CACjB;AAED,MAAM,WAAW,QAAQ;IACvB,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,MAAM,EAAE,CAAA;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB;AAED,MAAM,WAAW,cAAc,CAAC,IAAI,SAAS,OAAO,GAAG,OAAO;IAC5D,GAAG,EAAE,IAAI,CAAA;IACT,KAAK,EAAE,IAAI,GAAG,SAAS,CAAA;IACvB,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAED,MAAM,WAAW,YAAY,CAAC,IAAI,SAAS,OAAO,GAAG,OAAO;IAC1D,GAAG,EAAE,IAAI,CAAA;IACT,KAAK,EAAE,IAAI,CAAA;IACX,KAAK,EAAE,KAAK,CAAA;CACb;AAED,MAAM,WAAW,cAAc,CAAC,IAAI,SAAS,OAAO,GAAG,OAAO;IAC5D,GAAG,EAAE,IAAI,CAAA;IACT,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,KAAK,CAAA;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,+DAA+D;IAC/D,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;CACvB;AAED;;;;;;;GAOG;AACH,8BAAsB,WAAW,CAC/B,QAAQ,SAAS,kBAAkB,GAAG,kBAAkB,EACxD,eAAe,GAAG,
|
|
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;CACjB;AAED,MAAM,WAAW,QAAQ;IACvB,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,MAAM,EAAE,CAAA;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB;AAED,MAAM,WAAW,cAAc,CAAC,IAAI,SAAS,OAAO,GAAG,OAAO;IAC5D,GAAG,EAAE,IAAI,CAAA;IACT,KAAK,EAAE,IAAI,GAAG,SAAS,CAAA;IACvB,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAED,MAAM,WAAW,YAAY,CAAC,IAAI,SAAS,OAAO,GAAG,OAAO;IAC1D,GAAG,EAAE,IAAI,CAAA;IACT,KAAK,EAAE,IAAI,CAAA;IACX,KAAK,EAAE,KAAK,CAAA;CACb;AAED,MAAM,WAAW,cAAc,CAAC,IAAI,SAAS,OAAO,GAAG,OAAO;IAC5D,GAAG,EAAE,IAAI,CAAA;IACT,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,KAAK,CAAA;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,+DAA+D;IAC/D,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;CACvB;AAED;;;;;;;GAOG;AACH,8BAAsB,WAAW,CAC/B,QAAQ,SAAS,kBAAkB,GAAG,kBAAkB,EACxD,eAAe,GAAG,OAAO;IAEzB,OAAO,EAAE,QAAQ,CAAA;IACjB,MAAM,EAAE,WAAW,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAA;gBAE3B,OAAO,EAAE,QAAQ;IAY7B,QAAQ,CAAC,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,eAAe;IAE5D;;OAEG;IACH,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,GAAG,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC;IAEzE;;OAEG;IACH,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAE/D;;;;OAIG;IACH,QAAQ,CAAC,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAE3D;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAE/D;;OAEG;IACH,QAAQ,CAAC,KAAK,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAEtC;;;;;;;;OAQG;IACH,MAAM,CAAC,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;CAC5D"}
|
package/dist/consts.d.ts
CHANGED
|
@@ -12,6 +12,15 @@ export declare const DEFAULT_MAX_RUNTIME = 14400;
|
|
|
12
12
|
export declare const MAX_RUNTIME_GRACE_PERIOD = 60;
|
|
13
13
|
/** 5 seconds */
|
|
14
14
|
export declare const DEFAULT_SLEEP_DELAY = 5;
|
|
15
|
+
/**
|
|
16
|
+
* Upper bound, in milliseconds, for the delay before a failed job is retried
|
|
17
|
+
* (7 days). The backoff grows with the fourth power of the number of attempts,
|
|
18
|
+
* so without a cap a job with a very high `maxAttempts` would get a `runAt` so
|
|
19
|
+
* far in the future that it can't be represented as a `Date`. The cap is above
|
|
20
|
+
* the longest delay reached with the default `maxAttempts` (23 ** 4 seconds,
|
|
21
|
+
* about 3.2 days), so it only affects jobs with a higher `maxAttempts`
|
|
22
|
+
*/
|
|
23
|
+
export declare const MAX_BACKOFF_MS: number;
|
|
15
24
|
export declare const DEFAULT_DELETE_SUCCESSFUL_JOBS = true;
|
|
16
25
|
export declare const DEFAULT_DELETE_FAILED_JOBS = false;
|
|
17
26
|
export declare const DEFAULT_LOGGER: Console;
|
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;
|
|
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;AAEvD,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
|
@@ -3,6 +3,7 @@ const DEFAULT_MAX_ATTEMPTS = 24;
|
|
|
3
3
|
const DEFAULT_MAX_RUNTIME = 14400;
|
|
4
4
|
const MAX_RUNTIME_GRACE_PERIOD = 60;
|
|
5
5
|
const DEFAULT_SLEEP_DELAY = 5;
|
|
6
|
+
const MAX_BACKOFF_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
6
7
|
const DEFAULT_DELETE_SUCCESSFUL_JOBS = true;
|
|
7
8
|
const DEFAULT_DELETE_FAILED_JOBS = false;
|
|
8
9
|
const DEFAULT_LOGGER = console;
|
|
@@ -30,6 +31,7 @@ export {
|
|
|
30
31
|
DEFAULT_WAIT,
|
|
31
32
|
DEFAULT_WAIT_UNTIL,
|
|
32
33
|
DEFAULT_WORK_QUEUE,
|
|
34
|
+
MAX_BACKOFF_MS,
|
|
33
35
|
MAX_RUNTIME_GRACE_PERIOD,
|
|
34
36
|
PROCESS_TITLE_PREFIX
|
|
35
37
|
};
|
package/dist/core/Executor.d.ts
CHANGED
|
@@ -24,6 +24,7 @@ export declare const DEFAULTS: {
|
|
|
24
24
|
deleteSuccessfulJobs: boolean;
|
|
25
25
|
};
|
|
26
26
|
export declare class Executor {
|
|
27
|
+
#private;
|
|
27
28
|
options: Required<ExecutorOptions>;
|
|
28
29
|
adapter: ExecutorOptions['adapter'];
|
|
29
30
|
logger: NonNullable<ExecutorOptions['logger']>;
|
|
@@ -34,7 +35,20 @@ export declare class Executor {
|
|
|
34
35
|
deleteSuccessfulJobs: NonNullable<ExecutorOptions['deleteSuccessfulJobs']>;
|
|
35
36
|
constructor(options: ExecutorOptions);
|
|
36
37
|
get jobIdentifier(): string;
|
|
37
|
-
|
|
38
|
+
/**
|
|
39
|
+
* Runs the job and records its outcome with the adapter.
|
|
40
|
+
*
|
|
41
|
+
* Resolves to `false` if the adapter threw while recording the outcome of a
|
|
42
|
+
* failed attempt. The job can then still be locked by this worker, and the
|
|
43
|
+
* adapter may hand the same job straight back, so the caller should wait
|
|
44
|
+
* before looking for its next job
|
|
45
|
+
*/
|
|
46
|
+
perform(): Promise<boolean>;
|
|
47
|
+
/**
|
|
48
|
+
* The number of milliseconds to wait before retrying a job that has been
|
|
49
|
+
* attempted `attempts` times: `attempts ** 4` seconds, capped at
|
|
50
|
+
* `MAX_BACKOFF_MS`
|
|
51
|
+
*/
|
|
38
52
|
backoffMilliseconds(attempts: number): number;
|
|
39
53
|
}
|
|
40
54
|
//# sourceMappingURL=Executor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Executor.d.ts","sourceRoot":"","sources":["../../src/core/Executor.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Executor.d.ts","sourceRoot":"","sources":["../../src/core/Executor.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAA;AAezE,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;IAqJjC;;;;OAIG;IACH,mBAAmB,CAAC,QAAQ,EAAE,MAAM;CAGrC"}
|
package/dist/core/Executor.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { setTimeout, clearTimeout } from "node:timers";
|
|
2
|
-
import { CronExpressionParser } from "cron-parser";
|
|
3
2
|
import {
|
|
4
3
|
DEFAULT_MAX_ATTEMPTS,
|
|
5
4
|
DEFAULT_MAX_RUNTIME,
|
|
6
5
|
DEFAULT_DELETE_FAILED_JOBS,
|
|
7
6
|
DEFAULT_DELETE_SUCCESSFUL_JOBS,
|
|
8
|
-
DEFAULT_LOGGER
|
|
7
|
+
DEFAULT_LOGGER,
|
|
8
|
+
MAX_BACKOFF_MS
|
|
9
9
|
} from "../consts.js";
|
|
10
10
|
import {
|
|
11
11
|
AdapterRequiredError,
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
JobTimeoutError
|
|
14
14
|
} from "../errors.js";
|
|
15
15
|
import { loadJob } from "../loaders.js";
|
|
16
|
+
import { nextCronRunAt } from "../util.js";
|
|
16
17
|
import { executionContext } from "./executionContext.js";
|
|
17
18
|
const DEFAULTS = {
|
|
18
19
|
logger: DEFAULT_LOGGER,
|
|
@@ -49,6 +50,14 @@ class Executor {
|
|
|
49
50
|
get jobIdentifier() {
|
|
50
51
|
return `${this.job.id} (${this.job.path}:${this.job.name})`;
|
|
51
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* Runs the job and records its outcome with the adapter.
|
|
55
|
+
*
|
|
56
|
+
* Resolves to `false` if the adapter threw while recording the outcome of a
|
|
57
|
+
* failed attempt. The job can then still be locked by this worker, and the
|
|
58
|
+
* adapter may hand the same job straight back, so the caller should wait
|
|
59
|
+
* before looking for its next job
|
|
60
|
+
*/
|
|
52
61
|
async perform() {
|
|
53
62
|
this.logger.info(`[CedarJS Jobs] Started job ${this.jobIdentifier}`);
|
|
54
63
|
const abortController = new AbortController();
|
|
@@ -68,12 +77,13 @@ class Executor {
|
|
|
68
77
|
);
|
|
69
78
|
})();
|
|
70
79
|
await Promise.race([performPromise, timeoutPromise]);
|
|
71
|
-
const runAt = this.job.cron ?
|
|
80
|
+
const runAt = this.job.cron ? nextCronRunAt(this.job.cron) : void 0;
|
|
72
81
|
await this.adapter.success({
|
|
73
82
|
job: this.job,
|
|
74
83
|
runAt,
|
|
75
84
|
deleteJob: !runAt && this.deleteSuccessfulJobs
|
|
76
85
|
});
|
|
86
|
+
return true;
|
|
77
87
|
} catch (rawError) {
|
|
78
88
|
const error = rawError instanceof Error ? rawError : new Error(String(rawError));
|
|
79
89
|
const timedOut = error instanceof JobTimeoutError;
|
|
@@ -85,41 +95,78 @@ class Executor {
|
|
|
85
95
|
const errorMessage = `[CedarJS Jobs] Error in job ${this.jobIdentifier}: ${error.message}`;
|
|
86
96
|
this.logger.error(errorMessage);
|
|
87
97
|
this.logger.error(error.stack);
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
98
|
+
return await this.#recordError(error, timedOut);
|
|
99
|
+
} finally {
|
|
100
|
+
clearTimeout(timeoutId);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Records the outcome of a failed attempt with the adapter. Resolves to
|
|
105
|
+
* `false` if any of the adapter calls threw
|
|
106
|
+
*/
|
|
107
|
+
async #recordError(error, timedOut) {
|
|
108
|
+
if (timedOut) {
|
|
109
|
+
this.logger.warn(
|
|
110
|
+
this.job,
|
|
111
|
+
`[CedarJS Jobs] Failed job ${this.jobIdentifier}: exceeded max runtime (${this.maxRuntime} seconds)`
|
|
112
|
+
);
|
|
113
|
+
return this.#adapterWrite(
|
|
114
|
+
() => this.adapter.failure({
|
|
94
115
|
job: this.job,
|
|
95
116
|
deleteJob: this.deleteFailedJobs,
|
|
96
117
|
error
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
118
|
+
})
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
const errorRecorded = await this.#adapterWrite(
|
|
122
|
+
() => this.adapter.error({
|
|
123
|
+
job: this.job,
|
|
124
|
+
runAt: new Date(
|
|
125
|
+
(/* @__PURE__ */ new Date()).getTime() + this.backoffMilliseconds(this.job.attempts)
|
|
126
|
+
),
|
|
127
|
+
error
|
|
128
|
+
})
|
|
129
|
+
);
|
|
130
|
+
if (this.job.attempts < this.maxAttempts) {
|
|
131
|
+
return errorRecorded;
|
|
132
|
+
}
|
|
133
|
+
this.logger.warn(
|
|
134
|
+
this.job,
|
|
135
|
+
`[CedarJS Jobs] Failed job ${this.jobIdentifier}: reached max attempts (${this.maxAttempts})`
|
|
136
|
+
);
|
|
137
|
+
const failureRecorded = await this.#adapterWrite(
|
|
138
|
+
() => this.adapter.failure({
|
|
139
|
+
job: this.job,
|
|
140
|
+
deleteJob: this.deleteFailedJobs
|
|
141
|
+
})
|
|
142
|
+
);
|
|
143
|
+
return errorRecorded && failureRecorded;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Runs a single adapter write. An error thrown by the write is logged
|
|
147
|
+
* rather than rethrown, so a failing write can't crash the worker. Resolves
|
|
148
|
+
* to `false` if the write threw
|
|
149
|
+
*/
|
|
150
|
+
async #adapterWrite(write) {
|
|
151
|
+
try {
|
|
152
|
+
await write();
|
|
153
|
+
return true;
|
|
154
|
+
} catch (rawAdapterError) {
|
|
155
|
+
const adapterError = rawAdapterError instanceof Error ? rawAdapterError : new Error(String(rawAdapterError));
|
|
156
|
+
this.logger.error(
|
|
157
|
+
`[CedarJS Jobs] Could not record the error for job ${this.jobIdentifier}: ${adapterError.message}`
|
|
158
|
+
);
|
|
159
|
+
this.logger.error(adapterError.stack);
|
|
160
|
+
return false;
|
|
119
161
|
}
|
|
120
162
|
}
|
|
163
|
+
/**
|
|
164
|
+
* The number of milliseconds to wait before retrying a job that has been
|
|
165
|
+
* attempted `attempts` times: `attempts ** 4` seconds, capped at
|
|
166
|
+
* `MAX_BACKOFF_MS`
|
|
167
|
+
*/
|
|
121
168
|
backoffMilliseconds(attempts) {
|
|
122
|
-
return 1e3 * attempts ** 4;
|
|
169
|
+
return Math.min(1e3 * attempts ** 4, MAX_BACKOFF_MS);
|
|
123
170
|
}
|
|
124
171
|
}
|
|
125
172
|
export {
|
|
@@ -13,7 +13,7 @@ export declare class JobManager<TAdapters extends Adapters, TQueues extends Queu
|
|
|
13
13
|
logger: TLogger;
|
|
14
14
|
workers: WorkerConfig<TAdapters, TQueues>[];
|
|
15
15
|
constructor(config: JobManagerConfig<TAdapters, TQueues extends string[] ? never : TQueues, TLogger>);
|
|
16
|
-
createScheduler<TAdapterName extends keyof TAdapters>(schedulerConfig: CreateSchedulerConfig<TAdapters, TAdapterName>): (<TJob extends Job<TQueues, any[]>>(job: TJob, ...argsAndOptions: CreateSchedulerArgs<TJob>) => Promise<
|
|
16
|
+
createScheduler<TAdapterName extends keyof TAdapters>(schedulerConfig: CreateSchedulerConfig<TAdapters, TAdapterName>): (<TJob extends Job<TQueues, any[]>>(job: TJob, ...argsAndOptions: CreateSchedulerArgs<TJob>) => Promise<Awaited<ReturnType<TAdapters[TAdapterName]["schedule"]>>>) & {
|
|
17
17
|
cancel: (jobId: string | number) => Promise<boolean>;
|
|
18
18
|
};
|
|
19
19
|
createJob<TArgs extends unknown[]>(jobDefinition: JobDefinition<TQueues, TArgs>): Job<TQueues, TArgs>;
|
package/dist/core/Scheduler.d.ts
CHANGED
|
@@ -21,7 +21,7 @@ export declare class Scheduler<TAdapter extends BaseAdapter> {
|
|
|
21
21
|
job: TJob;
|
|
22
22
|
args: Parameters<TJob['perform']> | never[];
|
|
23
23
|
options?: ScheduleJobOptions;
|
|
24
|
-
}): Promise<
|
|
24
|
+
}): Promise<Awaited<ReturnType<TAdapter['schedule']>>>;
|
|
25
25
|
/**
|
|
26
26
|
* Cancel a scheduled job so that it will not be run (if it's still queued)
|
|
27
27
|
* or not be retried (if it's currently running). Requires an adapter that
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Scheduler.d.ts","sourceRoot":"","sources":["../../src/core/Scheduler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,eAAe,EAChB,MAAM,wCAAwC,CAAA;AAa/C,OAAO,KAAK,EACV,WAAW,EACX,GAAG,EACH,UAAU,EACV,kBAAkB,EACnB,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"Scheduler.d.ts","sourceRoot":"","sources":["../../src/core/Scheduler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,eAAe,EAChB,MAAM,wCAAwC,CAAA;AAa/C,OAAO,KAAK,EACV,WAAW,EACX,GAAG,EACH,UAAU,EACV,kBAAkB,EACnB,MAAM,aAAa,CAAA;AAGpB,UAAU,eAAe,CAAC,QAAQ,SAAS,WAAW;IACpD,OAAO,EAAE,QAAQ,CAAA;IACjB,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB;AAED,qBAAa,SAAS,CAAC,QAAQ,SAAS,WAAW;IACjD,OAAO,EAAE,QAAQ,CAAA;IACjB,MAAM,EAAE,WAAW,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;gBAE5C,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,eAAe,CAAC,QAAQ,CAAC;IAS1D,YAAY,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,IAAI,GAAG,IAAI,CAAA;KAAE;IAU1E,YAAY,CAAC,IAAI,SAAS,GAAG,CAAC,UAAU,EAAE,OAAO,EAAE,CAAC,EAAE,EACpD,GAAG,EACH,IAAI,EACJ,OAAO,GACR,EAAE;QACD,GAAG,EAAE,IAAI,CAAA;QACT,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,KAAK,EAAE,CAAA;QAC3C,OAAO,CAAC,EAAE,kBAAkB,CAAA;KAC7B,GAAG,eAAe;IAgCb,QAAQ,CAAC,IAAI,SAAS,GAAG,CAAC,UAAU,EAAE,OAAO,EAAE,CAAC,EAAE,EACtD,GAAG,EACH,IAAI,EACJ,OAAO,GACR,EAAE;QACD,GAAG,EAAE,IAAI,CAAA;QACT,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,KAAK,EAAE,CAAA;QAC3C,OAAO,CAAC,EAAE,kBAAkB,CAAA;KAC7B,GAAG,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IA+BtD;;;;;;;;OAQG;IACG,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;CASpC"}
|
package/dist/core/Scheduler.js
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
QueueNotDefinedError,
|
|
11
11
|
SchedulingError
|
|
12
12
|
} from "../errors.js";
|
|
13
|
+
import { nextCronRunAt } from "../util.js";
|
|
13
14
|
class Scheduler {
|
|
14
15
|
adapter;
|
|
15
16
|
logger;
|
|
@@ -52,7 +53,9 @@ class Scheduler {
|
|
|
52
53
|
path: job.path,
|
|
53
54
|
args: args ?? [],
|
|
54
55
|
cron,
|
|
55
|
-
|
|
56
|
+
// A recurring job's first run happens the next time its cron schedule
|
|
57
|
+
// matches, just like all following runs
|
|
58
|
+
runAt: cron ? nextCronRunAt(cron) : this.computeRunAt({ wait, waitUntil }),
|
|
56
59
|
queue,
|
|
57
60
|
priority
|
|
58
61
|
};
|
|
@@ -69,7 +72,8 @@ class Scheduler {
|
|
|
69
72
|
});
|
|
70
73
|
this.logger.info(payload, `[CedarJS Jobs] Scheduling ${job.name}`);
|
|
71
74
|
try {
|
|
72
|
-
|
|
75
|
+
const scheduled = this.adapter.schedule(payload);
|
|
76
|
+
return await Promise.resolve(scheduled);
|
|
73
77
|
} catch (e) {
|
|
74
78
|
const error = e instanceof Error ? e : new Error(String(e));
|
|
75
79
|
throw new SchedulingError(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Worker.d.ts","sourceRoot":"","sources":["../../src/core/Worker.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAA;AAUzE,OAAO,KAAK,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA;AAInE,MAAM,WAAW,aAAc,SAAQ,mBAAmB;IAGxD,OAAO,EAAE,WAAW,CAAA;IACpB,uDAAuD;IACvD,WAAW,EAAE,MAAM,CAAA;IACnB,oEAAoE;IACpE,MAAM,EAAE,MAAM,EAAE,CAAA;IAIhB,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,8DAA8D;IAC9D,KAAK,CAAC,EAAE,OAAO,CAAA;IAEf;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IAEjB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,KAAK,eAAe,GAAG,QAAQ,CAAC,aAAa,CAAC,CAAA;AAc9C,qBAAa,MAAM;;IACjB,OAAO,EAAE,eAAe,CAAA;IACxB,OAAO,EAAE,eAAe,CAAC,SAAS,CAAC,CAAA;IACnC,MAAM,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAA;IACjC,KAAK,EAAE,eAAe,CAAC,OAAO,CAAC,CAAA;IAC/B,WAAW,EAAE,eAAe,CAAC,aAAa,CAAC,CAAA;IAC3C,MAAM,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAA;IACjC,WAAW,EAAE,eAAe,CAAC,aAAa,CAAC,CAAA;IAC3C,UAAU,EAAE,eAAe,CAAC,YAAY,CAAC,CAAA;IACzC,oBAAoB,EAAE,eAAe,CAAC,sBAAsB,CAAC,CAAA;IAC7D,gBAAgB,EAAE,eAAe,CAAC,kBAAkB,CAAC,CAAA;IACrD,UAAU,EAAE,eAAe,CAAC,YAAY,CAAC,CAAA;IACzC,OAAO,EAAE,eAAe,CAAC,SAAS,CAAC,CAAA;IACnC,OAAO,EAAE,eAAe,CAAC,SAAS,CAAC,CAAA;IACnC,aAAa,EAAE,IAAI,CAAA;gBAEP,OAAO,EAAE,aAAa;IA2ElC,GAAG;IAQH,IAAI,UAAU,WAMb;
|
|
1
|
+
{"version":3,"file":"Worker.d.ts","sourceRoot":"","sources":["../../src/core/Worker.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAA;AAUzE,OAAO,KAAK,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA;AAInE,MAAM,WAAW,aAAc,SAAQ,mBAAmB;IAGxD,OAAO,EAAE,WAAW,CAAA;IACpB,uDAAuD;IACvD,WAAW,EAAE,MAAM,CAAA;IACnB,oEAAoE;IACpE,MAAM,EAAE,MAAM,EAAE,CAAA;IAIhB,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,8DAA8D;IAC9D,KAAK,CAAC,EAAE,OAAO,CAAA;IAEf;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IAEjB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,KAAK,eAAe,GAAG,QAAQ,CAAC,aAAa,CAAC,CAAA;AAc9C,qBAAa,MAAM;;IACjB,OAAO,EAAE,eAAe,CAAA;IACxB,OAAO,EAAE,eAAe,CAAC,SAAS,CAAC,CAAA;IACnC,MAAM,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAA;IACjC,KAAK,EAAE,eAAe,CAAC,OAAO,CAAC,CAAA;IAC/B,WAAW,EAAE,eAAe,CAAC,aAAa,CAAC,CAAA;IAC3C,MAAM,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAA;IACjC,WAAW,EAAE,eAAe,CAAC,aAAa,CAAC,CAAA;IAC3C,UAAU,EAAE,eAAe,CAAC,YAAY,CAAC,CAAA;IACzC,oBAAoB,EAAE,eAAe,CAAC,sBAAsB,CAAC,CAAA;IAC7D,gBAAgB,EAAE,eAAe,CAAC,kBAAkB,CAAC,CAAA;IACrD,UAAU,EAAE,eAAe,CAAC,YAAY,CAAC,CAAA;IACzC,OAAO,EAAE,eAAe,CAAC,SAAS,CAAC,CAAA;IACnC,OAAO,EAAE,eAAe,CAAC,SAAS,CAAC,CAAA;IACnC,aAAa,EAAE,IAAI,CAAA;gBAEP,OAAO,EAAE,aAAa;IA2ElC,GAAG;IAQH,IAAI,UAAU,WAMb;CAyDF"}
|
package/dist/core/Worker.js
CHANGED
|
@@ -97,8 +97,9 @@ class Worker {
|
|
|
97
97
|
maxRuntime: this.maxRuntime,
|
|
98
98
|
queues: this.queues
|
|
99
99
|
});
|
|
100
|
+
let outcomeRecorded = true;
|
|
100
101
|
if (job) {
|
|
101
|
-
await new Executor({
|
|
102
|
+
outcomeRecorded = await new Executor({
|
|
102
103
|
adapter: this.adapter,
|
|
103
104
|
logger: this.logger,
|
|
104
105
|
job,
|
|
@@ -110,7 +111,7 @@ class Worker {
|
|
|
110
111
|
} else if (this.workoff) {
|
|
111
112
|
break;
|
|
112
113
|
}
|
|
113
|
-
if (!job && this.forever) {
|
|
114
|
+
if ((!job || !outcomeRecorded) && this.forever) {
|
|
114
115
|
const millsSinceLastCheck = (/* @__PURE__ */ new Date()).getTime() - this.lastCheckTime.getTime();
|
|
115
116
|
if (millsSinceLastCheck < this.sleepDelay) {
|
|
116
117
|
await this.#wait(this.sleepDelay - millsSinceLastCheck);
|
package/dist/util.d.ts
CHANGED
|
@@ -1,2 +1,8 @@
|
|
|
1
1
|
export declare function makeFilePath(path: string): string;
|
|
2
|
+
/**
|
|
3
|
+
* Returns the next time after now that the given cron expression matches.
|
|
4
|
+
* Used both when a recurring job is first scheduled and when it's rescheduled
|
|
5
|
+
* after a successful run, so that both line up with its cron schedule.
|
|
6
|
+
*/
|
|
7
|
+
export declare function nextCronRunAt(cron: string): Date;
|
|
2
8
|
//# sourceMappingURL=util.d.ts.map
|
package/dist/util.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAKA,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,UAExC;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,QAEzC"}
|
package/dist/util.js
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { pathToFileURL } from "node:url";
|
|
2
|
+
import { CronExpressionParser } from "cron-parser";
|
|
2
3
|
function makeFilePath(path) {
|
|
3
4
|
return pathToFileURL(path).href;
|
|
4
5
|
}
|
|
6
|
+
function nextCronRunAt(cron) {
|
|
7
|
+
return CronExpressionParser.parse(cron).next().toDate();
|
|
8
|
+
}
|
|
5
9
|
export {
|
|
6
|
-
makeFilePath
|
|
10
|
+
makeFilePath,
|
|
11
|
+
nextCronRunAt
|
|
7
12
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cedarjs/jobs",
|
|
3
|
-
"version": "7.0.1-next.
|
|
3
|
+
"version": "7.0.1-next.333",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/cedarjs/cedar.git",
|
|
@@ -37,13 +37,13 @@
|
|
|
37
37
|
"test:watch": "vitest"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@cedarjs/cli-helpers": "7.0.1-next.
|
|
41
|
-
"@cedarjs/project-config": "7.0.1-next.
|
|
40
|
+
"@cedarjs/cli-helpers": "7.0.1-next.333",
|
|
41
|
+
"@cedarjs/project-config": "7.0.1-next.333",
|
|
42
42
|
"cron-parser": "5.10.1",
|
|
43
43
|
"type-fest": "5.10.0"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"@cedarjs/framework-tools": "7.0.1-next.
|
|
46
|
+
"@cedarjs/framework-tools": "7.0.1-next.333",
|
|
47
47
|
"@prisma/client": "7.10.0",
|
|
48
48
|
"concurrently": "9.2.4",
|
|
49
49
|
"publint": "0.3.24",
|