@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.
@@ -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-3BIR4IQD.js.map
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: any[]) => T) & {
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?: any;
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: any;
509
+ job: JobData;
510
510
  } | {
511
511
  type: 'completed';
512
512
  queue: string;
513
- job: any;
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) => any, onRejected?: (reason: any) => any): Promise<any>;
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) => any, onRejected?: (reason: any) => any): Promise<any>;
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: any);
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: any) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
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 JobFactory as g, type JobOptions as h, Job as i, type ScheduleStatus as j, ScheduleBuilder as k, JobBatchDispatcher as l, customBackoff as m, linearBackoff as n, exponentialBackoff as o, fixedBackoff as p, type JobStatus as q, type DispatchResult as r, type DispatchManyResult as s, type JobContext as t, type BackoffConfig as u, type QueueConfig as v, type WorkerConfig as w, type AdapterFactory as x, type ScheduleResult as y };
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, A as Adapter, R as RetryConfig, g as JobFactory, h as JobOptions, i as Job, a as JobClass, e as ScheduleData, j as ScheduleStatus, f as ScheduleListOptions } from './index-CoubP-c4.js';
2
- export { l as JobBatchDispatcher, k as ScheduleBuilder, m as customBackoff, o as exponentialBackoff, p as fixedBackoff, n as linearBackoff } from './index-CoubP-c4.js';
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 _poppinss_utils from '@poppinss/utils';
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 shutting down.
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 merged job options for a job (priority: job > queue > global).
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
- getMergedJobOptions(queue: string, jobOptions?: JobOptions): JobOptions;
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(): any;
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) => _poppinss_utils.Exception;
475
- declare const E_INVALID_BASE_DELAY: new (args: [reason: string], options?: ErrorOptions) => _poppinss_utils.Exception;
476
- declare const E_INVALID_MAX_DELAY: new (args: [reason: string], options?: ErrorOptions) => _poppinss_utils.Exception;
477
- declare const E_INVALID_MULTIPLIER: new (args: [reason: string], options?: ErrorOptions) => _poppinss_utils.Exception;
478
- declare const E_CONFIGURATION_ERROR: new (args: [reason: string], options?: ErrorOptions) => _poppinss_utils.Exception;
479
- declare const E_JOB_NOT_FOUND: new (args: [jobName: string], options?: ErrorOptions) => _poppinss_utils.Exception;
480
- declare const E_JOB_MAX_ATTEMPTS_REACHED: new (args: [jobName: string], options?: ErrorOptions) => _poppinss_utils.Exception;
481
- declare const E_JOB_TIMEOUT: new (args: [jobName: string, timeout: number], options?: ErrorOptions) => _poppinss_utils.Exception;
482
- declare const E_QUEUE_NOT_INITIALIZED: new (args?: any, options?: ErrorOptions) => _poppinss_utils.Exception;
483
- declare const E_ADAPTER_INIT_ERROR: new (args: [adapterName: string, originalMessage: string], options?: ErrorOptions) => _poppinss_utils.Exception;
484
- declare const E_NO_JOBS_FOUND: new (args: [patterns: string], options?: ErrorOptions) => _poppinss_utils.Exception;
485
- declare const E_INVALID_CRON_EXPRESSION: new (args: [expression: string, reason: string], options?: ErrorOptions) => _poppinss_utils.Exception;
486
- declare const E_INVALID_SCHEDULE_CONFIG: new (args: [reason: string], options?: ErrorOptions) => _poppinss_utils.Exception;
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-H6WOFLPJ.js";
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-3BIR4IQD.js";
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 shutting down.
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, timeout, context, payload } = await this.#initJob(job, queue);
326
- const retention = QueueManager.getMergedJobOptions(queue, options);
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 this.#executeWithTimeout(instance, payload, context, timeout);
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 isTimeout = e instanceof E_JOB_TIMEOUT;
334
- if (isTimeout && options.failOnTimeout) {
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, e, retention.removeOnFail);
337
- await instance.failed?.(e);
342
+ await this.#adapter.failJob(job.id, queue, outcome.storageError, retention.removeOnFail);
343
+ await instance.failed?.(outcome.hookError);
338
344
  return;
339
345
  }
340
- const mergedConfig = QueueManager.getMergedRetryConfig(queue, options.retry);
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, e, retention.removeOnFail);
344
- await instance.failed?.(e);
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 (job.attempts >= mergedConfig.maxRetries) {
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
- mergedConfig.maxRetries
357
+ runtime.maxRetries
353
358
  );
354
- await this.#adapter.failJob(job.id, queue, e, retention.removeOnFail);
355
- const exception = new E_JOB_MAX_ATTEMPTS_REACHED([job.name], { cause: e });
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 (mergedConfig.backoff) {
360
- const strategy = mergedConfig.backoff();
361
- const nextRetryAt = strategy.getNextRetryAt(job.attempts + 1);
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
- const timeout = this.#getJobTimeout(options);
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.getMergedJobOptions(queue);
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;