@bymax-one/nest-queue 1.2.12 → 1.2.14

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.
@@ -58,7 +58,10 @@ interface BymaxQueueModuleOptions {
58
58
  connection: QueueConnectionConfig;
59
59
  /** Default options applied to every job enqueued through the service. */
60
60
  defaultJobOptions?: JobsOptions;
61
- /** Prefix for all Redis keys (multi-tenant isolation). Default: 'bull'. */
61
+ /**
62
+ * Prefix for all Redis keys, a namespace and not an access control: anything that can reach the
63
+ * Redis instance can read every prefix on it. Default: 'bull'.
64
+ */
62
65
  prefix?: string;
63
66
  /** Default options applied to every Queue, merged with the job/prefix defaults. */
64
67
  queueOptions?: Partial<Omit<QueueOptions, 'connection' | 'defaultJobOptions' | 'prefix'>>;
@@ -87,8 +90,26 @@ interface BymaxQueueModuleOptions {
87
90
  * Default: true.
88
91
  */
89
92
  isGlobal?: boolean;
90
- /** Mode B only: milliseconds to wait for Redis `ready` before throwing. Default: 10_000. */
93
+ /**
94
+ * Mode B only: the startup budget, in milliseconds, for Redis to reach `ready`. Connection errors
95
+ * while the client is still reconnecting do not end the wait; the budget does, with
96
+ * `CONNECTION_TIMEOUT`, and the client the library opened is closed. Default: 10_000.
97
+ */
91
98
  connectionReadyTimeoutMs?: number;
99
+ /**
100
+ * Mode B only: the deadline, in milliseconds, for one Redis command on the connection the library
101
+ * opened (ioredis `commandTimeout`). A command that gets no reply in time rejects instead of
102
+ * waiting out ioredis' own retry window. An `options.commandTimeout` in the connection config
103
+ * wins. Worker and QueueEvents connections never inherit it, because they block by design.
104
+ * Default: 5_000.
105
+ */
106
+ commandTimeoutMs?: number;
107
+ /**
108
+ * The deadline, in milliseconds, for one `enqueue` or `enqueueBulk` call in either connection mode.
109
+ * When it passes, the call rejects with `CONNECTION_TIMEOUT`; the add may still complete in Redis
110
+ * afterwards, so retry with a stable `jobId` or `deduplication`. Default: 10_000.
111
+ */
112
+ enqueueTimeoutMs?: number;
92
113
  }
93
114
  /** A factory that produces module options, for async configuration. */
94
115
  interface BymaxQueueOptionsFactory {
@@ -236,6 +257,10 @@ interface ResolvedQueueOptions {
236
257
  telemetry?: Telemetry;
237
258
  /** Mode B ready timeout in milliseconds. */
238
259
  connectionReadyTimeoutMs: number;
260
+ /** Mode B per-command deadline in milliseconds. */
261
+ commandTimeoutMs: number;
262
+ /** Deadline in milliseconds for one enqueue call. */
263
+ enqueueTimeoutMs: number;
239
264
  }
240
265
 
241
266
  /**
@@ -362,7 +387,9 @@ declare class ConnectionResolver {
362
387
  /**
363
388
  * Merge the consumer's options with the owned-connection policy
364
389
  * (`lazyConnect: false`, so the client connects eagerly and `init` can wait
365
- * for `ready`) and narrow the result to the shape ioredis 6's constructor
390
+ * for `ready`; a command deadline, so a frozen Redis fails a call in seconds; and no offline
391
+ * queue, so a call made during an outage fails at once instead of buffering without bound —
392
+ * each only where the consumer has not chosen a value) and narrow the result to the shape ioredis 6's constructor
366
393
  * accepts. The runtime object is unchanged — the cast only drops the
367
394
  * `undefined` that `RedisOptions.replyMapping` carries and the constructor
368
395
  * rejects.
@@ -378,7 +405,14 @@ declare class ConnectionResolver {
378
405
  teardown(): Promise<void>;
379
406
  /** Validate and adopt a bring-your-own client for the Queue role. */
380
407
  private initModeA;
381
- /** Resolve when the owned client reaches `ready`, or reject on timeout/error. */
408
+ /**
409
+ * Resolve when the owned client reaches `ready`. A connection error while the client is still
410
+ * reconnecting does not end the wait — a Redis that restarts during a deploy refuses connections
411
+ * for a moment first — so the budget does. The two exceptions are an answer from the server that
412
+ * waiting cannot change (a refused credential) and a client that has stopped reconnecting; both
413
+ * reject at once. The rejection carries the last error's code and never its message, which can
414
+ * name the host.
415
+ */
382
416
  private waitReady;
383
417
  }
384
418
 
@@ -412,6 +446,13 @@ declare class QueueService {
412
446
  * @param overrides - Optional per-queue option overrides.
413
447
  */
414
448
  getOrCreateQueue<TData = unknown, TResult = unknown>(queueName: string, overrides?: Partial<Omit<QueueOptions, 'connection' | 'prefix'>>): Queue<TData, TResult>;
449
+ /** The error a producer call receives when Redis does not answer within `enqueueTimeoutMs`. */
450
+ private enqueueTimeout;
451
+ /**
452
+ * Await a Redis call, reporting an ioredis command timeout as `CONNECTION_TIMEOUT` with the
453
+ * operation and the command deadline of the connection in force.
454
+ */
455
+ private call;
415
456
  /** Resolve the raw cached queue (default generics) for internal delegation. */
416
457
  private queueFor;
417
458
  /**
@@ -492,7 +533,9 @@ declare class QueueService {
492
533
  * @param queueName - Target queue.
493
534
  * @param status - Status filter.
494
535
  * @param start - Starting index (inclusive). Default: 0.
495
- * @param end - Ending index (inclusive). Default: 50.
536
+ * @param end - Ending index (inclusive). Default: 50. The window may span at most
537
+ * `MAX_JOBS_PAGE_SIZE` (1000) jobs, and BullMQ's `-1` (everything) is refused.
538
+ * @throws {QueueException} `INVALID_OPTIONS` when the window is not a bounded range of integers.
496
539
  */
497
540
  getJobs<TData = unknown, TResult = unknown>(queueName: string, status: JobStatus, start?: number, end?: number): Promise<TypedJob<TData, TResult>[]>;
498
541
  /**
@@ -597,6 +640,7 @@ declare class QueueService {
597
640
  * })
598
641
  */
599
642
  declare class FlowService {
643
+ #private;
600
644
  private readonly logger;
601
645
  private readonly producer?;
602
646
  constructor(connection: ConnectionResolver, enabled: boolean, prefix: string, telemetry?: Telemetry);
@@ -629,6 +673,8 @@ declare class FlowService {
629
673
  * @throws {QueueException} `FLOW_DISABLED` (503) when flows are not enabled.
630
674
  */
631
675
  addBulk(flows: readonly FlowJob[]): Promise<JobNode[]>;
676
+ /** The command deadline of the producer connection, read when a command has timed out. */
677
+ private commandTimeout;
632
678
  /**
633
679
  * Escape hatch returning the underlying `FlowProducer` for advanced use cases.
634
680
  * Prefer {@link FlowService.add} / {@link FlowService.addBulk} when possible.
@@ -751,6 +797,14 @@ interface WorkerOptions {
751
797
  lockDuration?: number;
752
798
  /** Interval between stalled-job checks, in milliseconds. Default: 30_000. */
753
799
  stalledInterval?: number;
800
+ /**
801
+ * Fail a job whose handler has not settled after this many milliseconds, so it retries under the
802
+ * job's `attempts` and `backoff` and its concurrency slot is freed. The handler's `signal` aborts
803
+ * at that moment; a handler that ignores it keeps running in the background. There is no default:
804
+ * without it a handler that never settles holds its slot indefinitely. Not available for
805
+ * sandboxed workers. Range: 1 to 2_147_483_647.
806
+ */
807
+ jobTimeoutMs?: number;
754
808
  }
755
809
 
756
810
  /**
@@ -773,8 +827,13 @@ interface WorkerOptions {
773
827
  interface ProgrammaticWorkerConfig<TData = unknown, TResult = unknown> {
774
828
  /** BullMQ queue the worker should consume. */
775
829
  queueName: string;
776
- /** Async function that processes a single job. Must be idempotent. */
777
- handler: (job: Job<TData, TResult>) => Promise<TResult>;
830
+ /**
831
+ * Async function that processes a single job. Must be idempotent. Its optional second argument
832
+ * is the job's `AbortSignal`: it aborts when the job's `jobTimeoutMs` passes or when BullMQ
833
+ * cancels the job (`worker.cancelJob()`, `worker.cancelAllJobs()`). Closing the worker does not
834
+ * abort it. Pass it to whatever the handler awaits so the work stops with the job.
835
+ */
836
+ handler: (job: Job<TData, TResult>, signal?: AbortSignal) => Promise<TResult>;
778
837
  /** Optional worker tuning overrides. */
779
838
  options?: WorkerOptions;
780
839
  }
@@ -912,6 +971,14 @@ declare class WorkerRegistry {
912
971
  * @throws {QueueException} `WORKER_REGISTRATION_FAILED` when values are out of range.
913
972
  */
914
973
  private validateOptions;
974
+ /**
975
+ * Validate `jobTimeoutMs`, which must be a timer delay Node honours: above 2^31 - 1 ms it would
976
+ * fire after 1 ms and fail every job at once.
977
+ *
978
+ * @param opts - The caller-supplied options (may be undefined).
979
+ * @throws {QueueException} `WORKER_REGISTRATION_FAILED` when the value is out of range.
980
+ */
981
+ private validateJobTimeout;
915
982
  /**
916
983
  * Validate that `processorFile` is a safe, reachable artifact path. Accepts
917
984
  * absolute paths with `.js`/`.cjs`/`.mjs` extensions and `file:` URLs. Rejects
@@ -1071,28 +1138,21 @@ declare class QueueLifecycle implements OnModuleDestroy, OnApplicationShutdown {
1071
1138
  */
1072
1139
  onApplicationShutdown(): Promise<void>;
1073
1140
  /**
1074
- * Close every worker with a bounded drain, force-closing any that exceed the
1075
- * budget. Returns the number of workers that had to be force-closed.
1141
+ * Close every worker in parallel, each bounded by what is left of the shutdown budget, and
1142
+ * force-close any that exceed it. Returns the number of workers that had to be force-closed.
1076
1143
  *
1144
+ * @param deadline - The epoch millisecond at which the shutdown budget ends.
1077
1145
  * @returns The count of force-closed workers.
1078
1146
  */
1079
1147
  private closeWorkers;
1080
- /**
1081
- * Race a graceful `worker.close()` against a timer. `worker.close()` already
1082
- * drains active jobs and takes no timeout argument, so the timer is the only
1083
- * way to bound the wait. Rejects with a timeout error when the budget elapses.
1084
- *
1085
- * @param worker - The worker to close.
1086
- * @param timeoutMs - The drain budget in milliseconds.
1087
- */
1088
- private closeWorkerWithTimeout;
1089
- /** Close every cached `QueueEvents`, swallowing individual failures. */
1148
+ /** Close every cached `QueueEvents` in parallel within the budget, swallowing failures. */
1090
1149
  private closeQueueEvents;
1091
1150
  /**
1092
- * Close the duplicated worker/queue-events connections the library opened.
1093
- * BullMQ treats a passed-in client as shared and never closes it, so the
1094
- * library must release these explicitly. In Mode A the consumer's shared
1095
- * client is never among them.
1151
+ * Close the duplicated worker/queue-events connections the library opened, in parallel. BullMQ
1152
+ * treats a passed-in client as shared and never closes it, so the library must release these
1153
+ * explicitly. A connection that does not quit within the budget is disconnected, which also
1154
+ * releases anything still blocked on it. In Mode A the consumer's shared client is never among
1155
+ * them.
1096
1156
  */
1097
1157
  private closeDuplicatedConnections;
1098
1158
  /**
@@ -1408,13 +1468,16 @@ declare const DEFAULT_WORKER_CONCURRENCY: 2;
1408
1468
  declare const MAX_WORKER_CONCURRENCY: 1000;
1409
1469
  /**
1410
1470
  * Default options applied to every job enqueued through the service. The
1411
- * `removeOnFail.count` cap bounds Redis memory growth under failure storms.
1471
+ * `removeOnFail.count` cap bounds Redis memory growth under failure storms. The backoff jitter
1472
+ * spreads each retry over the upper half of its delay, so jobs that failed together (a Redis
1473
+ * outage, a downstream timeout) do not all retry in the same instant.
1412
1474
  */
1413
1475
  declare const DEFAULT_JOB_OPTIONS: {
1414
1476
  readonly attempts: 3;
1415
1477
  readonly backoff: {
1416
1478
  readonly type: "exponential";
1417
1479
  readonly delay: 2000;
1480
+ readonly jitter: 0.5;
1418
1481
  };
1419
1482
  readonly removeOnComplete: {
1420
1483
  readonly age: number;
@@ -58,7 +58,10 @@ interface BymaxQueueModuleOptions {
58
58
  connection: QueueConnectionConfig;
59
59
  /** Default options applied to every job enqueued through the service. */
60
60
  defaultJobOptions?: JobsOptions;
61
- /** Prefix for all Redis keys (multi-tenant isolation). Default: 'bull'. */
61
+ /**
62
+ * Prefix for all Redis keys, a namespace and not an access control: anything that can reach the
63
+ * Redis instance can read every prefix on it. Default: 'bull'.
64
+ */
62
65
  prefix?: string;
63
66
  /** Default options applied to every Queue, merged with the job/prefix defaults. */
64
67
  queueOptions?: Partial<Omit<QueueOptions, 'connection' | 'defaultJobOptions' | 'prefix'>>;
@@ -87,8 +90,26 @@ interface BymaxQueueModuleOptions {
87
90
  * Default: true.
88
91
  */
89
92
  isGlobal?: boolean;
90
- /** Mode B only: milliseconds to wait for Redis `ready` before throwing. Default: 10_000. */
93
+ /**
94
+ * Mode B only: the startup budget, in milliseconds, for Redis to reach `ready`. Connection errors
95
+ * while the client is still reconnecting do not end the wait; the budget does, with
96
+ * `CONNECTION_TIMEOUT`, and the client the library opened is closed. Default: 10_000.
97
+ */
91
98
  connectionReadyTimeoutMs?: number;
99
+ /**
100
+ * Mode B only: the deadline, in milliseconds, for one Redis command on the connection the library
101
+ * opened (ioredis `commandTimeout`). A command that gets no reply in time rejects instead of
102
+ * waiting out ioredis' own retry window. An `options.commandTimeout` in the connection config
103
+ * wins. Worker and QueueEvents connections never inherit it, because they block by design.
104
+ * Default: 5_000.
105
+ */
106
+ commandTimeoutMs?: number;
107
+ /**
108
+ * The deadline, in milliseconds, for one `enqueue` or `enqueueBulk` call in either connection mode.
109
+ * When it passes, the call rejects with `CONNECTION_TIMEOUT`; the add may still complete in Redis
110
+ * afterwards, so retry with a stable `jobId` or `deduplication`. Default: 10_000.
111
+ */
112
+ enqueueTimeoutMs?: number;
92
113
  }
93
114
  /** A factory that produces module options, for async configuration. */
94
115
  interface BymaxQueueOptionsFactory {
@@ -236,6 +257,10 @@ interface ResolvedQueueOptions {
236
257
  telemetry?: Telemetry;
237
258
  /** Mode B ready timeout in milliseconds. */
238
259
  connectionReadyTimeoutMs: number;
260
+ /** Mode B per-command deadline in milliseconds. */
261
+ commandTimeoutMs: number;
262
+ /** Deadline in milliseconds for one enqueue call. */
263
+ enqueueTimeoutMs: number;
239
264
  }
240
265
 
241
266
  /**
@@ -362,7 +387,9 @@ declare class ConnectionResolver {
362
387
  /**
363
388
  * Merge the consumer's options with the owned-connection policy
364
389
  * (`lazyConnect: false`, so the client connects eagerly and `init` can wait
365
- * for `ready`) and narrow the result to the shape ioredis 6's constructor
390
+ * for `ready`; a command deadline, so a frozen Redis fails a call in seconds; and no offline
391
+ * queue, so a call made during an outage fails at once instead of buffering without bound —
392
+ * each only where the consumer has not chosen a value) and narrow the result to the shape ioredis 6's constructor
366
393
  * accepts. The runtime object is unchanged — the cast only drops the
367
394
  * `undefined` that `RedisOptions.replyMapping` carries and the constructor
368
395
  * rejects.
@@ -378,7 +405,14 @@ declare class ConnectionResolver {
378
405
  teardown(): Promise<void>;
379
406
  /** Validate and adopt a bring-your-own client for the Queue role. */
380
407
  private initModeA;
381
- /** Resolve when the owned client reaches `ready`, or reject on timeout/error. */
408
+ /**
409
+ * Resolve when the owned client reaches `ready`. A connection error while the client is still
410
+ * reconnecting does not end the wait — a Redis that restarts during a deploy refuses connections
411
+ * for a moment first — so the budget does. The two exceptions are an answer from the server that
412
+ * waiting cannot change (a refused credential) and a client that has stopped reconnecting; both
413
+ * reject at once. The rejection carries the last error's code and never its message, which can
414
+ * name the host.
415
+ */
382
416
  private waitReady;
383
417
  }
384
418
 
@@ -412,6 +446,13 @@ declare class QueueService {
412
446
  * @param overrides - Optional per-queue option overrides.
413
447
  */
414
448
  getOrCreateQueue<TData = unknown, TResult = unknown>(queueName: string, overrides?: Partial<Omit<QueueOptions, 'connection' | 'prefix'>>): Queue<TData, TResult>;
449
+ /** The error a producer call receives when Redis does not answer within `enqueueTimeoutMs`. */
450
+ private enqueueTimeout;
451
+ /**
452
+ * Await a Redis call, reporting an ioredis command timeout as `CONNECTION_TIMEOUT` with the
453
+ * operation and the command deadline of the connection in force.
454
+ */
455
+ private call;
415
456
  /** Resolve the raw cached queue (default generics) for internal delegation. */
416
457
  private queueFor;
417
458
  /**
@@ -492,7 +533,9 @@ declare class QueueService {
492
533
  * @param queueName - Target queue.
493
534
  * @param status - Status filter.
494
535
  * @param start - Starting index (inclusive). Default: 0.
495
- * @param end - Ending index (inclusive). Default: 50.
536
+ * @param end - Ending index (inclusive). Default: 50. The window may span at most
537
+ * `MAX_JOBS_PAGE_SIZE` (1000) jobs, and BullMQ's `-1` (everything) is refused.
538
+ * @throws {QueueException} `INVALID_OPTIONS` when the window is not a bounded range of integers.
496
539
  */
497
540
  getJobs<TData = unknown, TResult = unknown>(queueName: string, status: JobStatus, start?: number, end?: number): Promise<TypedJob<TData, TResult>[]>;
498
541
  /**
@@ -597,6 +640,7 @@ declare class QueueService {
597
640
  * })
598
641
  */
599
642
  declare class FlowService {
643
+ #private;
600
644
  private readonly logger;
601
645
  private readonly producer?;
602
646
  constructor(connection: ConnectionResolver, enabled: boolean, prefix: string, telemetry?: Telemetry);
@@ -629,6 +673,8 @@ declare class FlowService {
629
673
  * @throws {QueueException} `FLOW_DISABLED` (503) when flows are not enabled.
630
674
  */
631
675
  addBulk(flows: readonly FlowJob[]): Promise<JobNode[]>;
676
+ /** The command deadline of the producer connection, read when a command has timed out. */
677
+ private commandTimeout;
632
678
  /**
633
679
  * Escape hatch returning the underlying `FlowProducer` for advanced use cases.
634
680
  * Prefer {@link FlowService.add} / {@link FlowService.addBulk} when possible.
@@ -751,6 +797,14 @@ interface WorkerOptions {
751
797
  lockDuration?: number;
752
798
  /** Interval between stalled-job checks, in milliseconds. Default: 30_000. */
753
799
  stalledInterval?: number;
800
+ /**
801
+ * Fail a job whose handler has not settled after this many milliseconds, so it retries under the
802
+ * job's `attempts` and `backoff` and its concurrency slot is freed. The handler's `signal` aborts
803
+ * at that moment; a handler that ignores it keeps running in the background. There is no default:
804
+ * without it a handler that never settles holds its slot indefinitely. Not available for
805
+ * sandboxed workers. Range: 1 to 2_147_483_647.
806
+ */
807
+ jobTimeoutMs?: number;
754
808
  }
755
809
 
756
810
  /**
@@ -773,8 +827,13 @@ interface WorkerOptions {
773
827
  interface ProgrammaticWorkerConfig<TData = unknown, TResult = unknown> {
774
828
  /** BullMQ queue the worker should consume. */
775
829
  queueName: string;
776
- /** Async function that processes a single job. Must be idempotent. */
777
- handler: (job: Job<TData, TResult>) => Promise<TResult>;
830
+ /**
831
+ * Async function that processes a single job. Must be idempotent. Its optional second argument
832
+ * is the job's `AbortSignal`: it aborts when the job's `jobTimeoutMs` passes or when BullMQ
833
+ * cancels the job (`worker.cancelJob()`, `worker.cancelAllJobs()`). Closing the worker does not
834
+ * abort it. Pass it to whatever the handler awaits so the work stops with the job.
835
+ */
836
+ handler: (job: Job<TData, TResult>, signal?: AbortSignal) => Promise<TResult>;
778
837
  /** Optional worker tuning overrides. */
779
838
  options?: WorkerOptions;
780
839
  }
@@ -912,6 +971,14 @@ declare class WorkerRegistry {
912
971
  * @throws {QueueException} `WORKER_REGISTRATION_FAILED` when values are out of range.
913
972
  */
914
973
  private validateOptions;
974
+ /**
975
+ * Validate `jobTimeoutMs`, which must be a timer delay Node honours: above 2^31 - 1 ms it would
976
+ * fire after 1 ms and fail every job at once.
977
+ *
978
+ * @param opts - The caller-supplied options (may be undefined).
979
+ * @throws {QueueException} `WORKER_REGISTRATION_FAILED` when the value is out of range.
980
+ */
981
+ private validateJobTimeout;
915
982
  /**
916
983
  * Validate that `processorFile` is a safe, reachable artifact path. Accepts
917
984
  * absolute paths with `.js`/`.cjs`/`.mjs` extensions and `file:` URLs. Rejects
@@ -1071,28 +1138,21 @@ declare class QueueLifecycle implements OnModuleDestroy, OnApplicationShutdown {
1071
1138
  */
1072
1139
  onApplicationShutdown(): Promise<void>;
1073
1140
  /**
1074
- * Close every worker with a bounded drain, force-closing any that exceed the
1075
- * budget. Returns the number of workers that had to be force-closed.
1141
+ * Close every worker in parallel, each bounded by what is left of the shutdown budget, and
1142
+ * force-close any that exceed it. Returns the number of workers that had to be force-closed.
1076
1143
  *
1144
+ * @param deadline - The epoch millisecond at which the shutdown budget ends.
1077
1145
  * @returns The count of force-closed workers.
1078
1146
  */
1079
1147
  private closeWorkers;
1080
- /**
1081
- * Race a graceful `worker.close()` against a timer. `worker.close()` already
1082
- * drains active jobs and takes no timeout argument, so the timer is the only
1083
- * way to bound the wait. Rejects with a timeout error when the budget elapses.
1084
- *
1085
- * @param worker - The worker to close.
1086
- * @param timeoutMs - The drain budget in milliseconds.
1087
- */
1088
- private closeWorkerWithTimeout;
1089
- /** Close every cached `QueueEvents`, swallowing individual failures. */
1148
+ /** Close every cached `QueueEvents` in parallel within the budget, swallowing failures. */
1090
1149
  private closeQueueEvents;
1091
1150
  /**
1092
- * Close the duplicated worker/queue-events connections the library opened.
1093
- * BullMQ treats a passed-in client as shared and never closes it, so the
1094
- * library must release these explicitly. In Mode A the consumer's shared
1095
- * client is never among them.
1151
+ * Close the duplicated worker/queue-events connections the library opened, in parallel. BullMQ
1152
+ * treats a passed-in client as shared and never closes it, so the library must release these
1153
+ * explicitly. A connection that does not quit within the budget is disconnected, which also
1154
+ * releases anything still blocked on it. In Mode A the consumer's shared client is never among
1155
+ * them.
1096
1156
  */
1097
1157
  private closeDuplicatedConnections;
1098
1158
  /**
@@ -1408,13 +1468,16 @@ declare const DEFAULT_WORKER_CONCURRENCY: 2;
1408
1468
  declare const MAX_WORKER_CONCURRENCY: 1000;
1409
1469
  /**
1410
1470
  * Default options applied to every job enqueued through the service. The
1411
- * `removeOnFail.count` cap bounds Redis memory growth under failure storms.
1471
+ * `removeOnFail.count` cap bounds Redis memory growth under failure storms. The backoff jitter
1472
+ * spreads each retry over the upper half of its delay, so jobs that failed together (a Redis
1473
+ * outage, a downstream timeout) do not all retry in the same instant.
1412
1474
  */
1413
1475
  declare const DEFAULT_JOB_OPTIONS: {
1414
1476
  readonly attempts: 3;
1415
1477
  readonly backoff: {
1416
1478
  readonly type: "exponential";
1417
1479
  readonly delay: 2000;
1480
+ readonly jitter: 0.5;
1418
1481
  };
1419
1482
  readonly removeOnComplete: {
1420
1483
  readonly age: number;