@boringnode/queue 0.4.0 → 0.5.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/README.md +19 -0
- package/build/{chunk-H6WOFLPJ.js → chunk-OVYXMSSU.js} +148 -61
- package/build/chunk-OVYXMSSU.js.map +1 -0
- package/build/chunk-WOUYSNK2.js +128 -0
- package/build/chunk-WOUYSNK2.js.map +1 -0
- package/build/{chunk-3BIR4IQD.js → chunk-ZZFSQY36.js} +2 -2
- package/build/chunk-ZZFSQY36.js.map +1 -0
- package/build/{index-CoubP-c4.d.ts → index-B1XdqWpN.d.ts} +21 -13
- package/build/index.d.ts +61 -38
- package/build/index.js +34 -56
- package/build/index.js.map +1 -1
- package/build/src/contracts/adapter.d.ts +1 -1
- package/build/src/drivers/fake_adapter.d.ts +6 -2
- package/build/src/drivers/fake_adapter.js +2 -2
- package/build/src/drivers/knex_adapter.d.ts +5 -1
- package/build/src/drivers/knex_adapter.js +11 -5
- package/build/src/drivers/knex_adapter.js.map +1 -1
- package/build/src/drivers/redis_adapter.d.ts +5 -1
- package/build/src/drivers/redis_adapter.js +42 -21
- package/build/src/drivers/redis_adapter.js.map +1 -1
- package/build/src/drivers/sync_adapter.d.ts +6 -2
- package/build/src/drivers/sync_adapter.js +61 -20
- package/build/src/drivers/sync_adapter.js.map +1 -1
- package/build/src/types/index.d.ts +1 -1
- package/build/src/types/main.d.ts +1 -1
- package/package.json +30 -22
- package/build/chunk-3BIR4IQD.js.map +0 -1
- package/build/chunk-H6WOFLPJ.js.map +0 -1
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import {
|
|
2
|
+
E_JOB_MAX_ATTEMPTS_REACHED,
|
|
3
|
+
E_JOB_TIMEOUT,
|
|
4
|
+
parse
|
|
5
|
+
} from "./chunk-ZZFSQY36.js";
|
|
6
|
+
|
|
7
|
+
// src/job_runtime.ts
|
|
8
|
+
var JobExecutionRuntime = class _JobExecutionRuntime {
|
|
9
|
+
#jobName;
|
|
10
|
+
#options;
|
|
11
|
+
#retryConfig;
|
|
12
|
+
#timeout;
|
|
13
|
+
/**
|
|
14
|
+
* Build a runtime from already-resolved queue/job execution config.
|
|
15
|
+
*/
|
|
16
|
+
static from({
|
|
17
|
+
jobName,
|
|
18
|
+
options,
|
|
19
|
+
retryConfig,
|
|
20
|
+
defaultTimeout
|
|
21
|
+
}) {
|
|
22
|
+
return new _JobExecutionRuntime({
|
|
23
|
+
jobName,
|
|
24
|
+
options,
|
|
25
|
+
retryConfig,
|
|
26
|
+
defaultTimeout
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
get maxRetries() {
|
|
30
|
+
return this.#retryConfig.maxRetries;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Create a runtime with fully resolved retry and timeout settings.
|
|
34
|
+
*/
|
|
35
|
+
constructor({ jobName, options, retryConfig, defaultTimeout }) {
|
|
36
|
+
this.#jobName = jobName;
|
|
37
|
+
this.#options = options || {};
|
|
38
|
+
this.#retryConfig = retryConfig;
|
|
39
|
+
const timeout = this.#options.timeout ?? defaultTimeout;
|
|
40
|
+
this.#timeout = timeout === void 0 ? void 0 : parse(timeout);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Execute a hydrated job instance and enforce the configured timeout.
|
|
44
|
+
*/
|
|
45
|
+
async execute(instance, payload, context) {
|
|
46
|
+
if (this.#timeout === void 0) {
|
|
47
|
+
instance.$hydrate(payload, context);
|
|
48
|
+
return instance.execute();
|
|
49
|
+
}
|
|
50
|
+
const signal = AbortSignal.timeout(this.#timeout);
|
|
51
|
+
instance.$hydrate(payload, context, signal);
|
|
52
|
+
const { abortPromise, cleanupAbortListener } = this.#createTimeoutAbortRace(
|
|
53
|
+
signal,
|
|
54
|
+
instance.constructor.name
|
|
55
|
+
);
|
|
56
|
+
try {
|
|
57
|
+
await Promise.race([instance.execute(), abortPromise]);
|
|
58
|
+
} finally {
|
|
59
|
+
cleanupAbortListener();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Convert an execution error into a retry or permanent-failure outcome.
|
|
64
|
+
*/
|
|
65
|
+
resolveFailure(error, attempts) {
|
|
66
|
+
if (error instanceof E_JOB_TIMEOUT && this.#options.failOnTimeout) {
|
|
67
|
+
return {
|
|
68
|
+
type: "failed",
|
|
69
|
+
reason: "timeout",
|
|
70
|
+
storageError: error,
|
|
71
|
+
hookError: error
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
if (typeof this.#retryConfig.maxRetries === "undefined" || this.#retryConfig.maxRetries <= 0) {
|
|
75
|
+
return {
|
|
76
|
+
type: "failed",
|
|
77
|
+
reason: "no-retries",
|
|
78
|
+
storageError: error,
|
|
79
|
+
hookError: error
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
if (attempts >= this.#retryConfig.maxRetries) {
|
|
83
|
+
return {
|
|
84
|
+
type: "failed",
|
|
85
|
+
reason: "max-attempts",
|
|
86
|
+
storageError: error,
|
|
87
|
+
hookError: new E_JOB_MAX_ATTEMPTS_REACHED([this.#jobName], { cause: error })
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
if (this.#retryConfig.backoff) {
|
|
91
|
+
return {
|
|
92
|
+
type: "retry",
|
|
93
|
+
retryAt: this.#retryConfig.backoff().getNextRetryAt(attempts + 1)
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
return { type: "retry" };
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Create the timeout race used to abort a job execution cleanly.
|
|
100
|
+
*/
|
|
101
|
+
#createTimeoutAbortRace(signal, runtimeJobName) {
|
|
102
|
+
const timeout = this.#timeout;
|
|
103
|
+
let abortHandler;
|
|
104
|
+
const abortPromise = new Promise((_, reject) => {
|
|
105
|
+
abortHandler = () => {
|
|
106
|
+
reject(new E_JOB_TIMEOUT([runtimeJobName, timeout]));
|
|
107
|
+
};
|
|
108
|
+
if (signal.aborted) {
|
|
109
|
+
abortHandler();
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
signal.addEventListener("abort", abortHandler, { once: true });
|
|
113
|
+
});
|
|
114
|
+
return {
|
|
115
|
+
abortPromise,
|
|
116
|
+
cleanupAbortListener: () => {
|
|
117
|
+
if (abortHandler) {
|
|
118
|
+
signal.removeEventListener("abort", abortHandler);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
export {
|
|
126
|
+
JobExecutionRuntime
|
|
127
|
+
};
|
|
128
|
+
//# sourceMappingURL=chunk-WOUYSNK2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/job_runtime.ts"],"sourcesContent":["import * as errors from './exceptions.js'\nimport type { Job } from './job.js'\nimport type { Duration, JobContext, JobOptions, RetryConfig } from './types/main.js'\nimport { parse } from './utils.js'\n\nexport type JobExecutionOutcome =\n | { type: 'completed' }\n | { type: 'retry'; retryAt?: Date }\n | {\n type: 'failed'\n reason: 'timeout' | 'no-retries' | 'max-attempts'\n storageError: Error\n hookError: Error\n }\n\ntype JobExecutionRuntimeConfig = {\n jobName: string\n options?: JobOptions\n retryConfig: RetryConfig\n defaultTimeout?: Duration\n}\n\ntype JobExecutionRuntimeFactoryOptions = {\n jobName: string\n options?: JobOptions\n retryConfig: RetryConfig\n defaultTimeout?: Duration\n}\n\n/**\n * Shared execution policy for a single job runtime.\n *\n * It encapsulates timeout resolution and retry/failure decisions so the\n * worker and the sync adapter follow the same execution rules.\n */\nexport class JobExecutionRuntime {\n readonly #jobName: string\n readonly #options: JobOptions\n readonly #retryConfig: RetryConfig\n readonly #timeout?: number\n\n /**\n * Build a runtime from already-resolved queue/job execution config.\n */\n static from({\n jobName,\n options,\n retryConfig,\n defaultTimeout,\n }: JobExecutionRuntimeFactoryOptions): JobExecutionRuntime {\n return new JobExecutionRuntime({\n jobName,\n options,\n retryConfig,\n defaultTimeout,\n })\n }\n\n get maxRetries(): number | undefined {\n return this.#retryConfig.maxRetries\n }\n\n /**\n * Create a runtime with fully resolved retry and timeout settings.\n */\n constructor({ jobName, options, retryConfig, defaultTimeout }: JobExecutionRuntimeConfig) {\n this.#jobName = jobName\n this.#options = options || {}\n this.#retryConfig = retryConfig\n\n const timeout = this.#options.timeout ?? defaultTimeout\n this.#timeout = timeout === undefined ? undefined : parse(timeout)\n }\n\n /**\n * Execute a hydrated job instance and enforce the configured timeout.\n */\n async execute(instance: Job, payload: unknown, context: JobContext): Promise<void> {\n if (this.#timeout === undefined) {\n instance.$hydrate(payload, context)\n return instance.execute()\n }\n\n const signal = AbortSignal.timeout(this.#timeout)\n instance.$hydrate(payload, context, signal)\n\n const { abortPromise, cleanupAbortListener } = this.#createTimeoutAbortRace(\n signal,\n instance.constructor.name\n )\n\n try {\n await Promise.race([instance.execute(), abortPromise])\n } finally {\n cleanupAbortListener()\n }\n }\n\n /**\n * Convert an execution error into a retry or permanent-failure outcome.\n */\n resolveFailure(error: Error, attempts: number): JobExecutionOutcome {\n if (error instanceof errors.E_JOB_TIMEOUT && this.#options.failOnTimeout) {\n return {\n type: 'failed',\n reason: 'timeout',\n storageError: error,\n hookError: error,\n }\n }\n\n if (typeof this.#retryConfig.maxRetries === 'undefined' || this.#retryConfig.maxRetries <= 0) {\n return {\n type: 'failed',\n reason: 'no-retries',\n storageError: error,\n hookError: error,\n }\n }\n\n if (attempts >= this.#retryConfig.maxRetries) {\n return {\n type: 'failed',\n reason: 'max-attempts',\n storageError: error,\n hookError: new errors.E_JOB_MAX_ATTEMPTS_REACHED([this.#jobName], { cause: error }),\n }\n }\n\n if (this.#retryConfig.backoff) {\n return {\n type: 'retry',\n retryAt: this.#retryConfig.backoff().getNextRetryAt(attempts + 1),\n }\n }\n\n return { type: 'retry' }\n }\n\n /**\n * Create the timeout race used to abort a job execution cleanly.\n */\n #createTimeoutAbortRace(signal: AbortSignal, runtimeJobName: string) {\n const timeout = this.#timeout!\n let abortHandler: (() => void) | undefined\n\n const abortPromise = new Promise<never>((_, reject) => {\n abortHandler = () => {\n reject(new errors.E_JOB_TIMEOUT([runtimeJobName, timeout]))\n }\n\n if (signal.aborted) {\n abortHandler()\n return\n }\n\n signal.addEventListener('abort', abortHandler, { once: true })\n })\n\n return {\n abortPromise,\n cleanupAbortListener: () => {\n if (abortHandler) {\n signal.removeEventListener('abort', abortHandler)\n }\n },\n }\n }\n}\n"],"mappings":";;;;;;;AAmCO,IAAM,sBAAN,MAAM,qBAAoB;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA;AAAA,EAKT,OAAO,KAAK;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAA2D;AACzD,WAAO,IAAI,qBAAoB;AAAA,MAC7B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,IAAI,aAAiC;AACnC,WAAO,KAAK,aAAa;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,EAAE,SAAS,SAAS,aAAa,eAAe,GAA8B;AACxF,SAAK,WAAW;AAChB,SAAK,WAAW,WAAW,CAAC;AAC5B,SAAK,eAAe;AAEpB,UAAM,UAAU,KAAK,SAAS,WAAW;AACzC,SAAK,WAAW,YAAY,SAAY,SAAY,MAAM,OAAO;AAAA,EACnE;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAQ,UAAe,SAAkB,SAAoC;AACjF,QAAI,KAAK,aAAa,QAAW;AAC/B,eAAS,SAAS,SAAS,OAAO;AAClC,aAAO,SAAS,QAAQ;AAAA,IAC1B;AAEA,UAAM,SAAS,YAAY,QAAQ,KAAK,QAAQ;AAChD,aAAS,SAAS,SAAS,SAAS,MAAM;AAE1C,UAAM,EAAE,cAAc,qBAAqB,IAAI,KAAK;AAAA,MAClD;AAAA,MACA,SAAS,YAAY;AAAA,IACvB;AAEA,QAAI;AACF,YAAM,QAAQ,KAAK,CAAC,SAAS,QAAQ,GAAG,YAAY,CAAC;AAAA,IACvD,UAAE;AACA,2BAAqB;AAAA,IACvB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,eAAe,OAAc,UAAuC;AAClE,QAAI,iBAAwB,iBAAiB,KAAK,SAAS,eAAe;AACxE,aAAO;AAAA,QACL,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,cAAc;AAAA,QACd,WAAW;AAAA,MACb;AAAA,IACF;AAEA,QAAI,OAAO,KAAK,aAAa,eAAe,eAAe,KAAK,aAAa,cAAc,GAAG;AAC5F,aAAO;AAAA,QACL,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,cAAc;AAAA,QACd,WAAW;AAAA,MACb;AAAA,IACF;AAEA,QAAI,YAAY,KAAK,aAAa,YAAY;AAC5C,aAAO;AAAA,QACL,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,cAAc;AAAA,QACd,WAAW,IAAW,2BAA2B,CAAC,KAAK,QAAQ,GAAG,EAAE,OAAO,MAAM,CAAC;AAAA,MACpF;AAAA,IACF;AAEA,QAAI,KAAK,aAAa,SAAS;AAC7B,aAAO;AAAA,QACL,MAAM;AAAA,QACN,SAAS,KAAK,aAAa,QAAQ,EAAE,eAAe,WAAW,CAAC;AAAA,MAClE;AAAA,IACF;AAEA,WAAO,EAAE,MAAM,QAAQ;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAKA,wBAAwB,QAAqB,gBAAwB;AACnE,UAAM,UAAU,KAAK;AACrB,QAAI;AAEJ,UAAM,eAAe,IAAI,QAAe,CAAC,GAAG,WAAW;AACrD,qBAAe,MAAM;AACnB,eAAO,IAAW,cAAc,CAAC,gBAAgB,OAAO,CAAC,CAAC;AAAA,MAC5D;AAEA,UAAI,OAAO,SAAS;AAClB,qBAAa;AACb;AAAA,MACF;AAEA,aAAO,iBAAiB,SAAS,cAAc,EAAE,MAAM,KAAK,CAAC;AAAA,IAC/D,CAAC;AAED,WAAO;AAAA,MACL;AAAA,MACA,sBAAsB,MAAM;AAC1B,YAAI,cAAc;AAChB,iBAAO,oBAAoB,SAAS,YAAY;AAAA,QAClD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
|
|
@@ -21,7 +21,7 @@ __export(exceptions_exports, {
|
|
|
21
21
|
E_NO_JOBS_FOUND: () => E_NO_JOBS_FOUND,
|
|
22
22
|
E_QUEUE_NOT_INITIALIZED: () => E_QUEUE_NOT_INITIALIZED
|
|
23
23
|
});
|
|
24
|
-
import { createError } from "@poppinss/utils";
|
|
24
|
+
import { createError } from "@poppinss/utils/exception";
|
|
25
25
|
var E_INVALID_DURATION_EXPRESSION = createError(
|
|
26
26
|
'Invalid duration expression: "%s"',
|
|
27
27
|
"E_INVALID_DURATION_EXPRESSION",
|
|
@@ -144,4 +144,4 @@ export {
|
|
|
144
144
|
parse,
|
|
145
145
|
calculateScore
|
|
146
146
|
};
|
|
147
|
-
//# sourceMappingURL=chunk-
|
|
147
|
+
//# sourceMappingURL=chunk-ZZFSQY36.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/exceptions.ts","../src/constants.ts","../src/utils.ts"],"sourcesContent":["import { createError } from '@poppinss/utils/exception'\n\nexport const E_INVALID_DURATION_EXPRESSION = createError(\n 'Invalid duration expression: \"%s\"',\n 'E_INVALID_DURATION_EXPRESSION',\n 500\n)\n\nexport const E_INVALID_BASE_DELAY = createError<[reason: string]>(\n 'Invalid base delay. Reason: %s',\n 'E_INVALID_BASE_DELAY',\n 500\n)\n\nexport const E_INVALID_MAX_DELAY = createError<[reason: string]>(\n 'Invalid max delay. Reason: %s',\n 'E_INVALID_MAX_DELAY',\n 500\n)\n\nexport const E_INVALID_MULTIPLIER = createError<[reason: string]>(\n 'Invalid multiplier. Reason: %s',\n 'E_INVALID_MULTIPLIER',\n 500\n)\n\nexport const E_CONFIGURATION_ERROR = createError<[reason: string]>(\n 'Configuration error. Reason: %s',\n 'E_CONFIGURATION_ERROR',\n 500\n)\n\nexport const E_JOB_NOT_FOUND = createError<[jobName: string]>(\n 'Requested job \"%s\" is not registered',\n 'E_JOB_NOT_FOUND'\n)\n\nexport const E_JOB_MAX_ATTEMPTS_REACHED = createError<[jobName: string]>(\n 'The job \"%s\" has reached the maximum number of retry attempts',\n 'E_JOB_MAX_ATTEMPTS_REACHED'\n)\n\nexport const E_JOB_TIMEOUT = createError<[jobName: string, timeout: number]>(\n 'The job \"%s\" has exceeded the timeout of %dms',\n 'E_JOB_TIMEOUT'\n)\n\nexport const E_QUEUE_NOT_INITIALIZED = createError(\n 'QueueManager is not initialized. Call QueueManager.init() before using it.',\n 'E_QUEUE_NOT_INITIALIZED',\n 500\n)\n\nexport const E_ADAPTER_INIT_ERROR = createError<[adapterName: string, originalMessage: string]>(\n 'Failed to initialize adapter \"%s\". Reason: %s',\n 'E_ADAPTER_INIT_ERROR',\n 500\n)\n\nexport const E_NO_JOBS_FOUND = createError<[patterns: string]>(\n 'No jobs found for the specified locations: %s. Verify your glob patterns match your job files.',\n 'E_NO_JOBS_FOUND',\n 500\n)\n\nexport const E_INVALID_CRON_EXPRESSION = createError<[expression: string, reason: string]>(\n 'Invalid cron expression \"%s\": %s',\n 'E_INVALID_CRON_EXPRESSION',\n 500\n)\n\nexport const E_INVALID_SCHEDULE_CONFIG = createError<[reason: string]>(\n 'Invalid schedule configuration: %s',\n 'E_INVALID_SCHEDULE_CONFIG',\n 500\n)\n","/**\n * Default job priority (1-10 scale, lower = higher priority)\n */\nexport const DEFAULT_PRIORITY = 5\n\n/**\n * Multiplier used in score calculation: priority * multiplier + timestamp\n *\n * This ensures higher priority jobs are processed first,\n * while preserving FIFO order within the same priority.\n * The value (1e13) leaves room for ~300 years of millisecond timestamps.\n */\nexport const PRIORITY_SCORE_MULTIPLIER = 1e13\n\n/**\n * Default delay when the worker is idle (no jobs in queue)\n */\nexport const DEFAULT_IDLE_DELAY = '2s'\n\n/**\n * Default interval between stalled job checks\n */\nexport const DEFAULT_STALLED_INTERVAL = '30s'\n\n/**\n * Default threshold after which a job is considered stalled\n */\nexport const DEFAULT_STALLED_THRESHOLD = '30s'\n\n/**\n * Default delay before retrying after an error\n */\nexport const DEFAULT_ERROR_RETRY_DELAY = '5s'\n","import { parse as parseDuration } from '@lukeed/ms'\nimport type { Duration, JobRetention } from './types/main.js'\nimport * as errors from './exceptions.js'\nimport { PRIORITY_SCORE_MULTIPLIER } from './constants.js'\n\nexport interface ResolvedRetention {\n keep: boolean\n maxAge: number\n maxCount: number\n}\n\nexport function resolveRetention(retention?: JobRetention): ResolvedRetention {\n if (retention === undefined || retention === true) {\n return { keep: false, maxAge: 0, maxCount: 0 }\n }\n\n if (retention === false) {\n return { keep: true, maxAge: 0, maxCount: 0 }\n }\n\n return {\n keep: true,\n maxAge: retention.age ? parse(retention.age) : 0,\n maxCount: retention.count ?? 0,\n }\n}\n\nexport function parse(duration: Duration): number {\n if (typeof duration === 'number') {\n return duration\n }\n\n const milliseconds = parseDuration(duration)\n\n if (typeof milliseconds === 'undefined') {\n throw new errors.E_INVALID_DURATION_EXPRESSION([duration])\n }\n\n return milliseconds\n}\n\n/**\n * Calculate the score for job ordering in the queue.\n * Lower scores are processed first.\n *\n * @param priority - Job priority (1-10, lower = higher priority)\n * @param timestamp - Timestamp in milliseconds\n * @returns Score for queue ordering\n */\nexport function calculateScore(priority: number, timestamp: number): number {\n return priority * PRIORITY_SCORE_MULTIPLIER + timestamp\n}\n"],"mappings":";;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAAS,mBAAmB;AAErB,IAAM,gCAAgC;AAAA,EAC3C;AAAA,EACA;AAAA,EACA;AACF;AAEO,IAAM,uBAAuB;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AACF;AAEO,IAAM,sBAAsB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AACF;AAEO,IAAM,uBAAuB;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AACF;AAEO,IAAM,wBAAwB;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AACF;AAEO,IAAM,kBAAkB;AAAA,EAC7B;AAAA,EACA;AACF;AAEO,IAAM,6BAA6B;AAAA,EACxC;AAAA,EACA;AACF;AAEO,IAAM,gBAAgB;AAAA,EAC3B;AAAA,EACA;AACF;AAEO,IAAM,0BAA0B;AAAA,EACrC;AAAA,EACA;AAAA,EACA;AACF;AAEO,IAAM,uBAAuB;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AACF;AAEO,IAAM,kBAAkB;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AACF;AAEO,IAAM,4BAA4B;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AACF;AAEO,IAAM,4BAA4B;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AACF;;;ACxEO,IAAM,mBAAmB;AASzB,IAAM,4BAA4B;AAKlC,IAAM,qBAAqB;AAK3B,IAAM,2BAA2B;AAKjC,IAAM,4BAA4B;AAKlC,IAAM,4BAA4B;;;AChCzC,SAAS,SAAS,qBAAqB;AAWhC,SAAS,iBAAiB,WAA6C;AAC5E,MAAI,cAAc,UAAa,cAAc,MAAM;AACjD,WAAO,EAAE,MAAM,OAAO,QAAQ,GAAG,UAAU,EAAE;AAAA,EAC/C;AAEA,MAAI,cAAc,OAAO;AACvB,WAAO,EAAE,MAAM,MAAM,QAAQ,GAAG,UAAU,EAAE;AAAA,EAC9C;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,QAAQ,UAAU,MAAM,MAAM,UAAU,GAAG,IAAI;AAAA,IAC/C,UAAU,UAAU,SAAS;AAAA,EAC/B;AACF;AAEO,SAAS,MAAM,UAA4B;AAChD,MAAI,OAAO,aAAa,UAAU;AAChC,WAAO;AAAA,EACT;AAEA,QAAM,eAAe,cAAc,QAAQ;AAE3C,MAAI,OAAO,iBAAiB,aAAa;AACvC,UAAM,IAAW,8BAA8B,CAAC,QAAQ,CAAC;AAAA,EAC3D;AAEA,SAAO;AACT;AAUO,SAAS,eAAe,UAAkB,WAA2B;AAC1E,SAAO,WAAW,4BAA4B;AAChD;","names":[]}
|
|
@@ -411,7 +411,7 @@ interface JobContext {
|
|
|
411
411
|
* The constructor accepts any arguments for dependency injection.
|
|
412
412
|
* Payload and context are provided separately via `$hydrate()`.
|
|
413
413
|
*/
|
|
414
|
-
type JobClass<T extends Job = Job> = (new (...args:
|
|
414
|
+
type JobClass<T extends Job = Job> = (new (...args: unknown[]) => T) & {
|
|
415
415
|
options?: JobOptions;
|
|
416
416
|
};
|
|
417
417
|
/**
|
|
@@ -452,7 +452,7 @@ interface BackoffConfig {
|
|
|
452
452
|
}
|
|
453
453
|
interface QueueConfig {
|
|
454
454
|
adapter?: string;
|
|
455
|
-
retry?:
|
|
455
|
+
retry?: RetryConfig;
|
|
456
456
|
defaultJobOptions?: JobOptions;
|
|
457
457
|
}
|
|
458
458
|
interface WorkerConfig {
|
|
@@ -506,11 +506,11 @@ interface WorkerConfig {
|
|
|
506
506
|
type WorkerCycle = {
|
|
507
507
|
type: 'started';
|
|
508
508
|
queue: string;
|
|
509
|
-
job:
|
|
509
|
+
job: JobData;
|
|
510
510
|
} | {
|
|
511
511
|
type: 'completed';
|
|
512
512
|
queue: string;
|
|
513
|
-
job:
|
|
513
|
+
job: JobData;
|
|
514
514
|
} | {
|
|
515
515
|
type: 'idle';
|
|
516
516
|
suggestedDelay: Duration;
|
|
@@ -796,6 +796,14 @@ interface Adapter {
|
|
|
796
796
|
* @param config - The schedule configuration
|
|
797
797
|
* @returns The schedule ID
|
|
798
798
|
*/
|
|
799
|
+
upsertSchedule(config: ScheduleConfig): Promise<string>;
|
|
800
|
+
/**
|
|
801
|
+
* Create or update a schedule.
|
|
802
|
+
*
|
|
803
|
+
* @deprecated Use `upsertSchedule` instead.
|
|
804
|
+
* @param config - The schedule configuration
|
|
805
|
+
* @returns The schedule ID
|
|
806
|
+
*/
|
|
799
807
|
createSchedule(config: ScheduleConfig): Promise<string>;
|
|
800
808
|
/**
|
|
801
809
|
* Get a schedule by ID.
|
|
@@ -987,7 +995,7 @@ declare class JobDispatcher<T> {
|
|
|
987
995
|
* @param onRejected - Error callback
|
|
988
996
|
* @returns Promise resolving to the DispatchResult
|
|
989
997
|
*/
|
|
990
|
-
then(onFulfilled?: (value: DispatchResult) =>
|
|
998
|
+
then<TResult1 = DispatchResult, TResult2 = never>(onFulfilled?: ((value: DispatchResult) => TResult1 | PromiseLike<TResult1>) | null, onRejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
|
|
991
999
|
}
|
|
992
1000
|
|
|
993
1001
|
/**
|
|
@@ -1108,7 +1116,7 @@ declare class JobBatchDispatcher<T> {
|
|
|
1108
1116
|
* @param onRejected - Error callback
|
|
1109
1117
|
* @returns Promise resolving to the DispatchManyResult
|
|
1110
1118
|
*/
|
|
1111
|
-
then(onFulfilled?: (value: DispatchManyResult) =>
|
|
1119
|
+
then<TResult1 = DispatchManyResult, TResult2 = never>(onFulfilled?: ((value: DispatchManyResult) => TResult1 | PromiseLike<TResult1>) | null, onRejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
|
|
1112
1120
|
}
|
|
1113
1121
|
|
|
1114
1122
|
/**
|
|
@@ -1129,9 +1137,9 @@ declare class JobBatchDispatcher<T> {
|
|
|
1129
1137
|
* .run()
|
|
1130
1138
|
* ```
|
|
1131
1139
|
*/
|
|
1132
|
-
declare class ScheduleBuilder implements PromiseLike<ScheduleResult> {
|
|
1140
|
+
declare class ScheduleBuilder<TPayload = unknown> implements PromiseLike<ScheduleResult> {
|
|
1133
1141
|
#private;
|
|
1134
|
-
constructor(name: string, payload:
|
|
1142
|
+
constructor(name: string, payload: TPayload);
|
|
1135
1143
|
/**
|
|
1136
1144
|
* Set a custom schedule ID.
|
|
1137
1145
|
* If not specified, defaults to the job name.
|
|
@@ -1179,7 +1187,7 @@ declare class ScheduleBuilder implements PromiseLike<ScheduleResult> {
|
|
|
1179
1187
|
/**
|
|
1180
1188
|
* Implement PromiseLike to allow `await builder.every('5m')` syntax.
|
|
1181
1189
|
*/
|
|
1182
|
-
then<TResult1 = ScheduleResult, TResult2 = never>(onfulfilled?: ((value: ScheduleResult) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason:
|
|
1190
|
+
then<TResult1 = ScheduleResult, TResult2 = never>(onfulfilled?: ((value: ScheduleResult) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
|
|
1183
1191
|
}
|
|
1184
1192
|
|
|
1185
1193
|
/**
|
|
@@ -1331,7 +1339,7 @@ declare abstract class Job<Payload = any> {
|
|
|
1331
1339
|
* .run()
|
|
1332
1340
|
* ```
|
|
1333
1341
|
*/
|
|
1334
|
-
static dispatch<T extends Job>(this: new (...args: any[]) => T, payload: T extends Job<infer P> ? P : never): JobDispatcher<T extends Job<infer P> ? P : never>;
|
|
1342
|
+
static dispatch<T extends Job>(this: abstract new (...args: any[]) => T, payload: T extends Job<infer P> ? P : never): JobDispatcher<T extends Job<infer P> ? P : never>;
|
|
1335
1343
|
/**
|
|
1336
1344
|
* Dispatch multiple jobs to the queue in a single batch.
|
|
1337
1345
|
*
|
|
@@ -1359,7 +1367,7 @@ declare abstract class Job<Payload = any> {
|
|
|
1359
1367
|
* console.log(`Dispatched ${jobIds.length} jobs`)
|
|
1360
1368
|
* ```
|
|
1361
1369
|
*/
|
|
1362
|
-
static dispatchMany<T extends Job>(this: new (...args: any[]) => T, payloads: (T extends Job<infer P> ? P : never)[]): JobBatchDispatcher<T extends Job<infer P> ? P : never>;
|
|
1370
|
+
static dispatchMany<T extends Job>(this: abstract new (...args: any[]) => T, payloads: (T extends Job<infer P> ? P : never)[]): JobBatchDispatcher<T extends Job<infer P> ? P : never>;
|
|
1363
1371
|
/**
|
|
1364
1372
|
* Create a schedule for this job.
|
|
1365
1373
|
*
|
|
@@ -1385,7 +1393,7 @@ declare abstract class Job<Payload = any> {
|
|
|
1385
1393
|
* .run()
|
|
1386
1394
|
* ```
|
|
1387
1395
|
*/
|
|
1388
|
-
static schedule<T extends Job>(this: new (...args: any[]) => T, payload: T extends Job<infer P> ? P : never): ScheduleBuilder
|
|
1396
|
+
static schedule<T extends Job>(this: abstract new (...args: any[]) => T, payload: T extends Job<infer P> ? P : never): ScheduleBuilder<T extends Job<infer P> ? P : never>;
|
|
1389
1397
|
/**
|
|
1390
1398
|
* Execute the job's business logic.
|
|
1391
1399
|
*
|
|
@@ -1428,4 +1436,4 @@ declare abstract class Job<Payload = any> {
|
|
|
1428
1436
|
failed?(error: Error): Promise<void>;
|
|
1429
1437
|
}
|
|
1430
1438
|
|
|
1431
|
-
export { type Adapter as A, type BackoffStrategy as B, type Duration as D, type JobData as J, type Logger as L, type QueueManagerConfig as Q, type RetryConfig as R, type ScheduleConfig as S, type WorkerCycle as W, type JobClass as a, type AcquiredJob as b, type JobRetention as c, type JobRecord as d, type ScheduleData as e, type ScheduleListOptions as f, type
|
|
1439
|
+
export { type Adapter as A, type BackoffStrategy as B, type Duration as D, type JobData as J, type Logger as L, type QueueManagerConfig as Q, type RetryConfig as R, type ScheduleConfig as S, type WorkerCycle as W, type JobClass as a, type AcquiredJob as b, type JobRetention as c, type JobRecord as d, type ScheduleData as e, type ScheduleListOptions as f, type JobOptions as g, type QueueConfig as h, type JobFactory as i, Job as j, type ScheduleStatus as k, ScheduleBuilder as l, JobBatchDispatcher as m, customBackoff as n, linearBackoff as o, exponentialBackoff as p, fixedBackoff as q, type JobStatus as r, type DispatchResult as s, type DispatchManyResult as t, type JobContext as u, type BackoffConfig as v, type WorkerConfig as w, type AdapterFactory as x, type ScheduleResult as y };
|
package/build/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { Q as QueueManagerConfig, W as WorkerCycle,
|
|
2
|
-
export {
|
|
1
|
+
import { Q as QueueManagerConfig, W as WorkerCycle, R as RetryConfig, g as JobOptions, h as QueueConfig, D as Duration, A as Adapter, i as JobFactory, L as Logger, j as Job, a as JobClass, e as ScheduleData, k as ScheduleStatus, f as ScheduleListOptions } from './index-B1XdqWpN.js';
|
|
2
|
+
export { m as JobBatchDispatcher, l as ScheduleBuilder, n as customBackoff, p as exponentialBackoff, q as fixedBackoff, o as linearBackoff } from './index-B1XdqWpN.js';
|
|
3
3
|
import { FakeAdapter } from './src/drivers/fake_adapter.js';
|
|
4
4
|
import { Knex } from 'knex';
|
|
5
|
-
import * as
|
|
5
|
+
import * as _poppinss_utils_exception from '@poppinss/utils/exception';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Job processing worker.
|
|
@@ -72,7 +72,8 @@ declare class Worker {
|
|
|
72
72
|
/**
|
|
73
73
|
* Stop the worker gracefully.
|
|
74
74
|
*
|
|
75
|
-
* Waits for all running jobs to complete before
|
|
75
|
+
* Waits for all running jobs to complete before stopping job consumption.
|
|
76
|
+
* Adapter cleanup remains the responsibility of `QueueManager.destroy()`.
|
|
76
77
|
* Called automatically on SIGINT/SIGTERM if gracefulShutdown is enabled.
|
|
77
78
|
*/
|
|
78
79
|
stop(): Promise<void>;
|
|
@@ -130,6 +131,42 @@ declare class Worker {
|
|
|
130
131
|
process(queues: string[]): AsyncGenerator<WorkerCycle, void, unknown>;
|
|
131
132
|
}
|
|
132
133
|
|
|
134
|
+
/**
|
|
135
|
+
* Resolve effective queue/job runtime configuration from the initialized
|
|
136
|
+
* queue config.
|
|
137
|
+
*
|
|
138
|
+
* This keeps merge rules in one place without coupling execution code to the
|
|
139
|
+
* full `QueueManager` lifecycle and adapter concerns.
|
|
140
|
+
*/
|
|
141
|
+
declare class QueueConfigResolver {
|
|
142
|
+
#private;
|
|
143
|
+
/**
|
|
144
|
+
* Create a resolver from the queue manager config.
|
|
145
|
+
*/
|
|
146
|
+
static from(config: QueueManagerConfig): QueueConfigResolver;
|
|
147
|
+
/**
|
|
148
|
+
* Create a resolver from already-materialized config fragments.
|
|
149
|
+
*/
|
|
150
|
+
constructor({ globalRetryConfig, globalJobOptions, queueConfigs, workerTimeout, }: {
|
|
151
|
+
globalRetryConfig?: RetryConfig;
|
|
152
|
+
globalJobOptions?: JobOptions;
|
|
153
|
+
queueConfigs?: Map<string, QueueConfig>;
|
|
154
|
+
workerTimeout?: Duration;
|
|
155
|
+
});
|
|
156
|
+
/**
|
|
157
|
+
* Resolve the retry policy for a job using priority: job > queue > global.
|
|
158
|
+
*/
|
|
159
|
+
resolveRetryConfig(queue: string, jobOptions?: JobOptions): RetryConfig;
|
|
160
|
+
/**
|
|
161
|
+
* Resolve effective retention options using priority: job > queue > global.
|
|
162
|
+
*/
|
|
163
|
+
resolveJobOptions(queue: string, jobOptions?: JobOptions): JobOptions;
|
|
164
|
+
/**
|
|
165
|
+
* Return the configured default worker timeout.
|
|
166
|
+
*/
|
|
167
|
+
getWorkerTimeout(): Duration | undefined;
|
|
168
|
+
}
|
|
169
|
+
|
|
133
170
|
/**
|
|
134
171
|
* Central configuration and adapter management for the queue system.
|
|
135
172
|
*
|
|
@@ -234,24 +271,6 @@ declare class QueueManagerSingleton {
|
|
|
234
271
|
* Restore adapters after calling `fake()`.
|
|
235
272
|
*/
|
|
236
273
|
restore(): void;
|
|
237
|
-
/**
|
|
238
|
-
* Get the merged retry configuration for a job.
|
|
239
|
-
*
|
|
240
|
-
* Configuration is merged with priority: job > queue > global.
|
|
241
|
-
* This allows specific jobs or queues to override global defaults.
|
|
242
|
-
*
|
|
243
|
-
* @param queue - The queue name
|
|
244
|
-
* @param jobRetryConfig - Optional job-level retry config
|
|
245
|
-
* @returns The merged retry configuration
|
|
246
|
-
*
|
|
247
|
-
* @example
|
|
248
|
-
* ```typescript
|
|
249
|
-
* // Global: maxRetries=3, Queue: maxRetries=5, Job: maxRetries=1
|
|
250
|
-
* // Result: maxRetries=1 (job wins)
|
|
251
|
-
* const config = QueueManager.getMergedRetryConfig('emails', { maxRetries: 1 })
|
|
252
|
-
* ```
|
|
253
|
-
*/
|
|
254
|
-
getMergedRetryConfig(queue: string, jobRetryConfig?: RetryConfig): RetryConfig;
|
|
255
274
|
/**
|
|
256
275
|
* Get the configured job factory for custom instantiation.
|
|
257
276
|
*
|
|
@@ -259,9 +278,13 @@ declare class QueueManagerSingleton {
|
|
|
259
278
|
*/
|
|
260
279
|
getJobFactory(): JobFactory | undefined;
|
|
261
280
|
/**
|
|
262
|
-
* Get the
|
|
281
|
+
* Get the configured logger used by the queue runtime.
|
|
282
|
+
*/
|
|
283
|
+
getLogger(): Logger;
|
|
284
|
+
/**
|
|
285
|
+
* Get the resolver responsible for effective queue/job runtime config.
|
|
263
286
|
*/
|
|
264
|
-
|
|
287
|
+
getConfigResolver(): QueueConfigResolver;
|
|
265
288
|
/**
|
|
266
289
|
* Clean up all adapter instances and reset state.
|
|
267
290
|
*
|
|
@@ -399,7 +422,7 @@ declare class Schedule {
|
|
|
399
422
|
constructor(data: ScheduleData);
|
|
400
423
|
get id(): string;
|
|
401
424
|
get name(): string;
|
|
402
|
-
get payload():
|
|
425
|
+
get payload(): unknown;
|
|
403
426
|
get cronExpression(): string | null;
|
|
404
427
|
get everyMs(): number | null;
|
|
405
428
|
get timezone(): string;
|
|
@@ -471,19 +494,19 @@ declare class QueueSchemaService {
|
|
|
471
494
|
dropSchedulesTable(tableName?: string): Promise<void>;
|
|
472
495
|
}
|
|
473
496
|
|
|
474
|
-
declare const E_INVALID_DURATION_EXPRESSION: new (args?: any, options?: ErrorOptions) =>
|
|
475
|
-
declare const E_INVALID_BASE_DELAY: new (args: [reason: string], options?: ErrorOptions) =>
|
|
476
|
-
declare const E_INVALID_MAX_DELAY: new (args: [reason: string], options?: ErrorOptions) =>
|
|
477
|
-
declare const E_INVALID_MULTIPLIER: new (args: [reason: string], options?: ErrorOptions) =>
|
|
478
|
-
declare const E_CONFIGURATION_ERROR: new (args: [reason: string], options?: ErrorOptions) =>
|
|
479
|
-
declare const E_JOB_NOT_FOUND: new (args: [jobName: string], options?: ErrorOptions) =>
|
|
480
|
-
declare const E_JOB_MAX_ATTEMPTS_REACHED: new (args: [jobName: string], options?: ErrorOptions) =>
|
|
481
|
-
declare const E_JOB_TIMEOUT: new (args: [jobName: string, timeout: number], options?: ErrorOptions) =>
|
|
482
|
-
declare const E_QUEUE_NOT_INITIALIZED: new (args?: any, options?: ErrorOptions) =>
|
|
483
|
-
declare const E_ADAPTER_INIT_ERROR: new (args: [adapterName: string, originalMessage: string], options?: ErrorOptions) =>
|
|
484
|
-
declare const E_NO_JOBS_FOUND: new (args: [patterns: string], options?: ErrorOptions) =>
|
|
485
|
-
declare const E_INVALID_CRON_EXPRESSION: new (args: [expression: string, reason: string], options?: ErrorOptions) =>
|
|
486
|
-
declare const E_INVALID_SCHEDULE_CONFIG: new (args: [reason: string], options?: ErrorOptions) =>
|
|
497
|
+
declare const E_INVALID_DURATION_EXPRESSION: new (args?: any, options?: ErrorOptions) => _poppinss_utils_exception.Exception;
|
|
498
|
+
declare const E_INVALID_BASE_DELAY: new (args: [reason: string], options?: ErrorOptions) => _poppinss_utils_exception.Exception;
|
|
499
|
+
declare const E_INVALID_MAX_DELAY: new (args: [reason: string], options?: ErrorOptions) => _poppinss_utils_exception.Exception;
|
|
500
|
+
declare const E_INVALID_MULTIPLIER: new (args: [reason: string], options?: ErrorOptions) => _poppinss_utils_exception.Exception;
|
|
501
|
+
declare const E_CONFIGURATION_ERROR: new (args: [reason: string], options?: ErrorOptions) => _poppinss_utils_exception.Exception;
|
|
502
|
+
declare const E_JOB_NOT_FOUND: new (args: [jobName: string], options?: ErrorOptions) => _poppinss_utils_exception.Exception;
|
|
503
|
+
declare const E_JOB_MAX_ATTEMPTS_REACHED: new (args: [jobName: string], options?: ErrorOptions) => _poppinss_utils_exception.Exception;
|
|
504
|
+
declare const E_JOB_TIMEOUT: new (args: [jobName: string, timeout: number], options?: ErrorOptions) => _poppinss_utils_exception.Exception;
|
|
505
|
+
declare const E_QUEUE_NOT_INITIALIZED: new (args?: any, options?: ErrorOptions) => _poppinss_utils_exception.Exception;
|
|
506
|
+
declare const E_ADAPTER_INIT_ERROR: new (args: [adapterName: string, originalMessage: string], options?: ErrorOptions) => _poppinss_utils_exception.Exception;
|
|
507
|
+
declare const E_NO_JOBS_FOUND: new (args: [patterns: string], options?: ErrorOptions) => _poppinss_utils_exception.Exception;
|
|
508
|
+
declare const E_INVALID_CRON_EXPRESSION: new (args: [expression: string, reason: string], options?: ErrorOptions) => _poppinss_utils_exception.Exception;
|
|
509
|
+
declare const E_INVALID_SCHEDULE_CONFIG: new (args: [reason: string], options?: ErrorOptions) => _poppinss_utils_exception.Exception;
|
|
487
510
|
|
|
488
511
|
declare const exceptions_E_ADAPTER_INIT_ERROR: typeof E_ADAPTER_INIT_ERROR;
|
|
489
512
|
declare const exceptions_E_CONFIGURATION_ERROR: typeof E_CONFIGURATION_ERROR;
|
package/build/index.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
JobExecutionRuntime
|
|
3
|
+
} from "./chunk-WOUYSNK2.js";
|
|
1
4
|
import {
|
|
2
5
|
Job,
|
|
3
6
|
JobBatchDispatcher,
|
|
@@ -6,7 +9,7 @@ import {
|
|
|
6
9
|
QueueManager,
|
|
7
10
|
ScheduleBuilder,
|
|
8
11
|
debug_default
|
|
9
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-OVYXMSSU.js";
|
|
10
13
|
import {
|
|
11
14
|
DEFAULT_ERROR_RETRY_DELAY,
|
|
12
15
|
DEFAULT_IDLE_DELAY,
|
|
@@ -16,11 +19,9 @@ import {
|
|
|
16
19
|
E_INVALID_BASE_DELAY,
|
|
17
20
|
E_INVALID_MAX_DELAY,
|
|
18
21
|
E_INVALID_MULTIPLIER,
|
|
19
|
-
E_JOB_MAX_ATTEMPTS_REACHED,
|
|
20
|
-
E_JOB_TIMEOUT,
|
|
21
22
|
exceptions_exports,
|
|
22
23
|
parse
|
|
23
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-ZZFSQY36.js";
|
|
24
25
|
|
|
25
26
|
// src/worker.ts
|
|
26
27
|
import { randomUUID } from "crypto";
|
|
@@ -199,7 +200,8 @@ var Worker = class {
|
|
|
199
200
|
/**
|
|
200
201
|
* Stop the worker gracefully.
|
|
201
202
|
*
|
|
202
|
-
* Waits for all running jobs to complete before
|
|
203
|
+
* Waits for all running jobs to complete before stopping job consumption.
|
|
204
|
+
* Adapter cleanup remains the responsibility of `QueueManager.destroy()`.
|
|
203
205
|
* Called automatically on SIGINT/SIGTERM if gracefulShutdown is enabled.
|
|
204
206
|
*/
|
|
205
207
|
async stop() {
|
|
@@ -209,9 +211,6 @@ var Worker = class {
|
|
|
209
211
|
debug_default("worker %s: waiting for %d running jobs to complete", this.#id, this.#pool.size);
|
|
210
212
|
await this.#pool.drain();
|
|
211
213
|
}
|
|
212
|
-
if (this.#adapter) {
|
|
213
|
-
await this.#adapter.destroy();
|
|
214
|
-
}
|
|
215
214
|
this.#removeShutdownHandlers();
|
|
216
215
|
}
|
|
217
216
|
/**
|
|
@@ -322,45 +321,48 @@ var Worker = class {
|
|
|
322
321
|
async #execute(job, queue) {
|
|
323
322
|
const startTime = performance.now();
|
|
324
323
|
debug_default("worker %s: executing job %s (%s)", this.#id, job.id, job.name);
|
|
325
|
-
const { instance, options,
|
|
326
|
-
const
|
|
324
|
+
const { instance, options, context, payload } = await this.#initJob(job, queue);
|
|
325
|
+
const configResolver = QueueManager.getConfigResolver();
|
|
326
|
+
const retention = configResolver.resolveJobOptions(queue, options);
|
|
327
|
+
const runtime = JobExecutionRuntime.from({
|
|
328
|
+
jobName: job.name,
|
|
329
|
+
options,
|
|
330
|
+
retryConfig: configResolver.resolveRetryConfig(queue, options),
|
|
331
|
+
defaultTimeout: configResolver.getWorkerTimeout()
|
|
332
|
+
});
|
|
327
333
|
try {
|
|
328
|
-
await
|
|
334
|
+
await runtime.execute(instance, payload, context);
|
|
329
335
|
await this.#adapter.completeJob(job.id, queue, retention.removeOnComplete);
|
|
330
336
|
const duration = (performance.now() - startTime).toFixed(2);
|
|
331
337
|
debug_default("worker %s: successfully executed job %s in %dms", this.#id, job.id, duration);
|
|
332
338
|
} catch (e) {
|
|
333
|
-
const
|
|
334
|
-
if (
|
|
339
|
+
const outcome = runtime.resolveFailure(e, job.attempts);
|
|
340
|
+
if (outcome.type === "failed" && outcome.reason === "timeout") {
|
|
335
341
|
debug_default("worker %s: job %s timed out and failOnTimeout is set", this.#id, job.id);
|
|
336
|
-
await this.#adapter.failJob(job.id, queue,
|
|
337
|
-
await instance.failed?.(
|
|
342
|
+
await this.#adapter.failJob(job.id, queue, outcome.storageError, retention.removeOnFail);
|
|
343
|
+
await instance.failed?.(outcome.hookError);
|
|
338
344
|
return;
|
|
339
345
|
}
|
|
340
|
-
|
|
341
|
-
if (typeof mergedConfig.maxRetries === "undefined" || mergedConfig.maxRetries <= 0) {
|
|
346
|
+
if (outcome.type === "failed" && outcome.reason === "no-retries") {
|
|
342
347
|
debug_default("worker %s: job %s has no retries configured, marking as failed", this.#id, job.id);
|
|
343
|
-
await this.#adapter.failJob(job.id, queue,
|
|
344
|
-
await instance.failed?.(
|
|
348
|
+
await this.#adapter.failJob(job.id, queue, outcome.storageError, retention.removeOnFail);
|
|
349
|
+
await instance.failed?.(outcome.hookError);
|
|
345
350
|
return;
|
|
346
351
|
}
|
|
347
|
-
if (
|
|
352
|
+
if (outcome.type === "failed" && outcome.reason === "max-attempts") {
|
|
348
353
|
debug_default(
|
|
349
354
|
"worker %s: job %s has exceeded max retries (%d), marking as failed",
|
|
350
355
|
this.#id,
|
|
351
356
|
job.id,
|
|
352
|
-
|
|
357
|
+
runtime.maxRetries
|
|
353
358
|
);
|
|
354
|
-
await this.#adapter.failJob(job.id, queue,
|
|
355
|
-
|
|
356
|
-
await instance.failed?.(exception);
|
|
359
|
+
await this.#adapter.failJob(job.id, queue, outcome.storageError, retention.removeOnFail);
|
|
360
|
+
await instance.failed?.(outcome.hookError);
|
|
357
361
|
return;
|
|
358
362
|
}
|
|
359
|
-
if (
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
debug_default("worker %s: job %s will retry at %s", this.#id, job.id, nextRetryAt.toISOString());
|
|
363
|
-
await this.#adapter.retryJob(job.id, queue, nextRetryAt);
|
|
363
|
+
if (outcome.type === "retry" && outcome.retryAt) {
|
|
364
|
+
debug_default("worker %s: job %s will retry at %s", this.#id, job.id, outcome.retryAt.toISOString());
|
|
365
|
+
await this.#adapter.retryJob(job.id, queue, outcome.retryAt);
|
|
364
366
|
return;
|
|
365
367
|
}
|
|
366
368
|
await this.#adapter.retryJob(job.id, queue);
|
|
@@ -381,38 +383,14 @@ var Worker = class {
|
|
|
381
383
|
const jobFactory = QueueManager.getJobFactory();
|
|
382
384
|
const instance = jobFactory ? await jobFactory(JobClass) : new JobClass();
|
|
383
385
|
const options = JobClass.options || {};
|
|
384
|
-
|
|
385
|
-
return { instance, options, timeout, context, payload: job.payload };
|
|
386
|
+
return { instance, options, context, payload: job.payload };
|
|
386
387
|
} catch (error) {
|
|
387
388
|
debug_default("worker %s: failed to initialize job %s (%s)", this.#id, job.id, job.name);
|
|
388
|
-
const retention = QueueManager.
|
|
389
|
+
const retention = QueueManager.getConfigResolver().resolveJobOptions(queue);
|
|
389
390
|
await this.#adapter.failJob(job.id, queue, error, retention.removeOnFail);
|
|
390
391
|
throw error;
|
|
391
392
|
}
|
|
392
393
|
}
|
|
393
|
-
#getJobTimeout(options) {
|
|
394
|
-
if (options.timeout !== void 0) {
|
|
395
|
-
return parse(options.timeout);
|
|
396
|
-
}
|
|
397
|
-
if (this.#config.worker?.timeout !== void 0) {
|
|
398
|
-
return parse(this.#config.worker.timeout);
|
|
399
|
-
}
|
|
400
|
-
return void 0;
|
|
401
|
-
}
|
|
402
|
-
async #executeWithTimeout(instance, payload, context, timeout) {
|
|
403
|
-
if (!timeout) {
|
|
404
|
-
instance.$hydrate(payload, context);
|
|
405
|
-
return instance.execute();
|
|
406
|
-
}
|
|
407
|
-
const signal = AbortSignal.timeout(timeout);
|
|
408
|
-
instance.$hydrate(payload, context, signal);
|
|
409
|
-
const abortPromise = new Promise((_, reject) => {
|
|
410
|
-
signal.addEventListener("abort", () => {
|
|
411
|
-
reject(new E_JOB_TIMEOUT([instance.constructor.name, timeout]));
|
|
412
|
-
});
|
|
413
|
-
});
|
|
414
|
-
await Promise.race([instance.execute(), abortPromise]);
|
|
415
|
-
}
|
|
416
394
|
async #acquireNextJob(queues) {
|
|
417
395
|
for (const queue of queues) {
|
|
418
396
|
const job = await this.#adapter.popFrom(queue);
|
|
@@ -682,7 +660,7 @@ var QueueSchemaService = class {
|
|
|
682
660
|
};
|
|
683
661
|
|
|
684
662
|
// src/strategies/backoff_strategy.ts
|
|
685
|
-
import { RuntimeException } from "@poppinss/utils";
|
|
663
|
+
import { RuntimeException } from "@poppinss/utils/exception";
|
|
686
664
|
import { assertUnreachable } from "@poppinss/utils/assert";
|
|
687
665
|
var BackoffStrategy = class {
|
|
688
666
|
#config;
|