@boringnode/queue 0.2.0 → 0.3.1

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.
@@ -179,6 +179,7 @@ var QueueManagerSingleton = class {
179
179
  #adapters = {};
180
180
  #adapterInstances = /* @__PURE__ */ new Map();
181
181
  #globalRetryConfig;
182
+ #globalJobOptions;
182
183
  #queueConfigs = /* @__PURE__ */ new Map();
183
184
  #logger = consoleLogger;
184
185
  #jobFactory;
@@ -213,6 +214,7 @@ var QueueManagerSingleton = class {
213
214
  this.#defaultAdapter = config.default;
214
215
  this.#adapters = config.adapters;
215
216
  this.#globalRetryConfig = config.retry;
217
+ this.#globalJobOptions = config.defaultJobOptions;
216
218
  this.#logger = config.logger ?? consoleLogger;
217
219
  this.#jobFactory = config.jobFactory;
218
220
  if (config.queues) {
@@ -309,6 +311,17 @@ var QueueManagerSingleton = class {
309
311
  getJobFactory() {
310
312
  return this.#jobFactory;
311
313
  }
314
+ /**
315
+ * Get the merged job options for a job (priority: job > queue > global).
316
+ */
317
+ getMergedJobOptions(queue, jobOptions) {
318
+ const queueConfig = this.#queueConfigs.get(queue);
319
+ const queueJobOptions = queueConfig?.defaultJobOptions;
320
+ return {
321
+ removeOnComplete: jobOptions?.removeOnComplete ?? queueJobOptions?.removeOnComplete ?? this.#globalJobOptions?.removeOnComplete,
322
+ removeOnFail: jobOptions?.removeOnFail ?? queueJobOptions?.removeOnFail ?? this.#globalJobOptions?.removeOnFail
323
+ };
324
+ }
312
325
  #validateConfig(config) {
313
326
  if (!config.adapters || Object.keys(config.adapters).length === 0) {
314
327
  throw new E_CONFIGURATION_ERROR(["At least one adapter must be configured"]);
@@ -355,4 +368,4 @@ export {
355
368
  Locator,
356
369
  QueueManager
357
370
  };
358
- //# sourceMappingURL=chunk-RIXMQXYJ.js.map
371
+ //# sourceMappingURL=chunk-LI2ZMCNO.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/debug.ts","../src/locator.ts","../src/logger.ts","../src/queue_manager.ts"],"sourcesContent":["import { debuglog } from 'node:util'\n\nexport default debuglog('boringnode:queue')\n","import { Job } from './job.js'\nimport * as errors from './exceptions.js'\nimport type { JobClass } from './types/main.js'\nimport debug from './debug.js'\nimport { glob } from 'node:fs/promises'\nimport { resolve } from 'node:path'\n\n/**\n * Job class registry.\n *\n * The Locator maintains a mapping of job names to their classes,\n * allowing the Worker to instantiate jobs by name when processing.\n *\n * Jobs are typically registered automatically via `QueueManager.init()`\n * using the `locations` config option, but can also be registered manually.\n *\n * @example\n * ```typescript\n * import { Locator } from '@boringnode/queue'\n * import SendEmailJob from './jobs/send_email_job.js'\n *\n * // Manual registration\n * Locator.register('SendEmailJob', SendEmailJob)\n *\n * // Auto-registration via glob (used by QueueManager.init)\n * await Locator.registerFromGlob(['./jobs/**\\/*.js'])\n *\n * // Retrieve a job class\n * const JobClass = Locator.getOrThrow('SendEmailJob')\n * ```\n */\nclass LocatorSingleton {\n #registry = new Map<string, JobClass>()\n\n /**\n * Register a job class with a given name.\n *\n * @param name - The job name (usually the class name)\n * @param JobClass - The job class constructor\n *\n * @example\n * ```typescript\n * Locator.register('SendEmailJob', SendEmailJob)\n * ```\n */\n register<T extends Job>(name: string, JobClass: JobClass<T>) {\n debug('registering job: %s', name)\n\n this.#registry.set(name, JobClass)\n }\n\n /**\n * Auto-register job classes from files matching glob patterns.\n *\n * Each file should have a default export that is a Job class.\n * The class name is used as the registration name.\n *\n * @param patterns - Glob patterns to match job files\n * @returns Number of jobs successfully registered\n *\n * @example\n * ```typescript\n * const count = await Locator.registerFromGlob([\n * './jobs/**\\/*.js',\n * './app/jobs/**\\/*.ts'\n * ])\n * console.log(`Registered ${count} jobs`)\n * ```\n */\n async registerFromGlob(patterns: string[]): Promise<number> {\n let registered = 0\n\n for (const pattern of patterns) {\n debug('registering jobs from glob pattern: %s', pattern)\n for await (const file of glob(pattern)) {\n debug('found job file: %s', file)\n\n try {\n const absolutePath = resolve(file)\n const module = await import(`file://${absolutePath}`)\n const JobClass = module.default as JobClass\n\n if (JobClass && typeof JobClass === 'function') {\n const jobName = JobClass.options?.name || JobClass.name\n this.register(jobName, JobClass)\n registered++\n }\n } catch (error) {\n console.warn(`Failed to load job from ${file}:`, error)\n }\n }\n }\n\n return registered\n }\n\n /**\n * Get a job class by name.\n *\n * @param name - The job name to look up\n * @returns The job class, or undefined if not found\n *\n * @example\n * ```typescript\n * const JobClass = Locator.get('SendEmailJob')\n * if (JobClass) {\n * const instance = new JobClass(payload)\n * }\n * ```\n */\n get<T extends Job = Job>(name: string): JobClass<T> | undefined {\n return this.#registry.get(name) as JobClass<T> | undefined\n }\n\n /**\n * Get a job class by name, throwing if not found.\n *\n * @param name - The job name to look up\n * @returns The job class\n * @throws {E_JOB_NOT_FOUND} If the job is not registered\n *\n * @example\n * ```typescript\n * const JobClass = Locator.getOrThrow('SendEmailJob')\n * const instance = new JobClass(payload)\n * ```\n */\n getOrThrow<T extends Job = Job>(name: string): JobClass<T> {\n const JobClass = this.get<T>(name)\n\n if (!JobClass) {\n throw new errors.E_JOB_NOT_FOUND([name])\n }\n\n return JobClass\n }\n\n /**\n * Remove all registered jobs.\n *\n * Primarily useful for testing.\n */\n clear(): void {\n this.#registry.clear()\n }\n}\n\n/** Global job class registry singleton */\nexport const Locator = new LocatorSingleton()\n","export interface LogObject {\n [key: string]: unknown\n}\n\nexport interface ErrorObject extends LogObject {\n err?: Error\n}\n\nexport interface Logger {\n trace(msg: string): void\n trace(obj: LogObject, msg: string): void\n\n debug(msg: string): void\n debug(obj: LogObject, msg: string): void\n\n info(msg: string): void\n info(obj: LogObject, msg: string): void\n\n warn(msg: string): void\n warn(obj: LogObject, msg: string): void\n\n error(msg: string): void\n error(obj: ErrorObject, msg: string): void\n\n child(obj: LogObject): Logger\n}\n\n/**\n * A simple logger that writes to console.\n */\nclass ConsoleLogger implements Logger {\n #prefix: string\n\n constructor(prefix: string = 'queue') {\n this.#prefix = prefix\n }\n\n #format(level: string, msgOrObj: string | LogObject, msg?: string): [string, LogObject?] {\n const prefix = `[${this.#prefix}] ${level}:`\n\n if (typeof msgOrObj === 'object') {\n return [`${prefix} ${msg}`, msgOrObj]\n }\n\n return [`${prefix} ${msgOrObj}`]\n }\n\n trace(msg: string): void\n trace(obj: LogObject, msg: string): void\n trace(msgOrObj: string | LogObject, msg?: string): void {\n const [message, obj] = this.#format('TRACE', msgOrObj, msg)\n\n if (obj) {\n return console.log(message, obj)\n }\n\n console.log(message)\n }\n\n debug(msg: string): void\n debug(obj: LogObject, msg: string): void\n debug(msgOrObj: string | LogObject, msg?: string): void {\n const [message, obj] = this.#format('DEBUG', msgOrObj, msg)\n\n if (obj) {\n return console.log(message, obj)\n }\n\n console.log(message)\n }\n\n info(msg: string): void\n info(obj: LogObject, msg: string): void\n info(msgOrObj: string | LogObject, msg?: string): void {\n const [message, obj] = this.#format('INFO', msgOrObj, msg)\n\n if (obj) {\n return console.log(message, obj)\n }\n\n console.log(message)\n }\n\n warn(msg: string): void\n warn(obj: LogObject, msg: string): void\n warn(msgOrObj: string | LogObject, msg?: string): void {\n const [message, obj] = this.#format('WARN', msgOrObj, msg)\n\n if (obj) {\n return console.warn(message, obj)\n }\n\n console.warn(message)\n }\n\n error(msg: string): void\n error(obj: ErrorObject, msg: string): void\n error(msgOrObj: string | ErrorObject, msg?: string): void {\n const [message, obj] = this.#format('ERROR', msgOrObj, msg)\n\n if (obj) {\n return console.error(message, obj)\n }\n\n console.error(message)\n }\n\n child(obj: LogObject): Logger {\n const childPrefix = obj.pkg ? String(obj.pkg) : this.#prefix\n return new ConsoleLogger(childPrefix)\n }\n}\n\nexport const consoleLogger = new ConsoleLogger()\n","import * as errors from './exceptions.js'\nimport debug from './debug.js'\nimport { Locator } from './locator.js'\nimport { consoleLogger, type Logger } from './logger.js'\nimport type { Adapter } from './contracts/adapter.js'\nimport type {\n AdapterFactory,\n JobFactory,\n JobOptions,\n QueueConfig,\n QueueManagerConfig,\n RetryConfig,\n} from './types/main.js'\n\n/**\n * Central configuration and adapter management for the queue system.\n *\n * The QueueManager is responsible for:\n * - Initializing adapters and job registration\n * - Providing adapter instances to workers and dispatchers\n * - Managing retry configuration across global, queue, and job levels\n *\n * @example\n * ```typescript\n * import { QueueManager, redis } from '@boringnode/queue'\n *\n * await QueueManager.init({\n * default: 'redis',\n * adapters: {\n * redis: redis({ host: 'localhost' }),\n * },\n * locations: ['./jobs/**\\/*.js'],\n * retry: {\n * maxRetries: 3,\n * backoff: exponentialBackoff(),\n * },\n * })\n *\n * // Get the default adapter\n * const adapter = QueueManager.use()\n *\n * // Clean up when done\n * await QueueManager.destroy()\n * ```\n */\nclass QueueManagerSingleton {\n #initialized = false\n #defaultAdapter!: string\n #adapters: Record<string, AdapterFactory> = {}\n #adapterInstances: Map<string, Adapter> = new Map()\n #globalRetryConfig?: RetryConfig\n #globalJobOptions?: JobOptions\n #queueConfigs: Map<string, QueueConfig> = new Map()\n #logger: Logger = consoleLogger\n #jobFactory?: JobFactory\n\n /**\n * Initialize the queue system with the given configuration.\n *\n * This must be called before using the queue system. It:\n * - Validates the configuration\n * - Registers adapters\n * - Auto-discovers and registers job classes from `locations`\n *\n * @param config - The queue configuration\n * @returns This instance for chaining\n * @throws {E_CONFIGURATION_ERROR} If the configuration is invalid\n *\n * @example\n * ```typescript\n * await QueueManager.init({\n * default: 'redis',\n * adapters: {\n * redis: redis(),\n * postgres: knex(pgConfig),\n * },\n * locations: ['./jobs/**\\/*.js'],\n * })\n * ```\n */\n async init(config: QueueManagerConfig) {\n debug('initializing queue manager with config: %O', config)\n\n this.#validateConfig(config)\n\n this.#adapterInstances.clear()\n\n this.#defaultAdapter = config.default\n this.#adapters = config.adapters\n this.#globalRetryConfig = config.retry\n this.#globalJobOptions = config.defaultJobOptions\n this.#logger = config.logger ?? consoleLogger\n this.#jobFactory = config.jobFactory\n\n if (config.queues) {\n for (const [queue, queueConfig] of Object.entries(config.queues)) {\n this.#queueConfigs.set(queue, queueConfig as QueueConfig)\n }\n }\n\n if (config.locations && config.locations.length > 0) {\n const registered = await Locator.registerFromGlob(config.locations)\n\n if (registered === 0) {\n this.#logger.warn(\n `No jobs found for locations: ${config.locations.join(', ')}. ` +\n 'Verify your glob patterns match your job files.'\n )\n }\n }\n\n this.#initialized = true\n\n return this\n }\n\n /**\n * Get an adapter instance by name.\n *\n * Adapter instances are cached and reused. If no name is provided,\n * the default adapter is returned.\n *\n * @param adapter - Adapter name (optional, defaults to the default adapter)\n * @returns The adapter instance\n * @throws {E_QUEUE_NOT_INITIALIZED} If `init()` hasn't been called\n * @throws {E_CONFIGURATION_ERROR} If the adapter is not registered\n * @throws {E_ADAPTER_INIT_ERROR} If the adapter factory throws\n *\n * @example\n * ```typescript\n * // Get default adapter\n * const adapter = QueueManager.use()\n *\n * // Get specific adapter\n * const redisAdapter = QueueManager.use('redis')\n * ```\n */\n use(adapter?: string): Adapter {\n if (!this.#initialized) {\n throw new errors.E_QUEUE_NOT_INITIALIZED()\n }\n\n if (!adapter) {\n adapter = this.#defaultAdapter\n }\n\n // Return cached instance if exists\n const cached = this.#adapterInstances.get(adapter)\n if (cached) {\n return cached\n }\n\n const adapterFactory = this.#adapters[adapter]\n\n if (!adapterFactory) {\n throw new errors.E_CONFIGURATION_ERROR([`Adapter \"${adapter}\" is not registered`])\n }\n\n debug('using adapter \"%s\"', adapter)\n\n try {\n const instance = adapterFactory()\n this.#adapterInstances.set(adapter, instance)\n return instance\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n throw new errors.E_ADAPTER_INIT_ERROR([adapter, message])\n }\n }\n\n /**\n * Get the merged retry configuration for a job.\n *\n * Configuration is merged with priority: job > queue > global.\n * This allows specific jobs or queues to override global defaults.\n *\n * @param queue - The queue name\n * @param jobRetryConfig - Optional job-level retry config\n * @returns The merged retry configuration\n *\n * @example\n * ```typescript\n * // Global: maxRetries=3, Queue: maxRetries=5, Job: maxRetries=1\n * // Result: maxRetries=1 (job wins)\n * const config = QueueManager.getMergedRetryConfig('emails', { maxRetries: 1 })\n * ```\n */\n getMergedRetryConfig(queue: string, jobRetryConfig?: RetryConfig): RetryConfig {\n const queueConfig = this.#queueConfigs.get(queue)\n const queueRetryConfig = queueConfig?.retry || {}\n\n let maxRetries =\n jobRetryConfig?.maxRetries ||\n queueRetryConfig.maxRetries ||\n this.#globalRetryConfig?.maxRetries ||\n 0\n\n let backoff =\n jobRetryConfig?.backoff || queueRetryConfig.backoff || this.#globalRetryConfig?.backoff\n\n return { maxRetries, backoff }\n }\n\n /**\n * Get the configured job factory for custom instantiation.\n *\n * @returns The job factory function, or undefined if not configured\n */\n getJobFactory(): JobFactory | undefined {\n return this.#jobFactory\n }\n\n /**\n * Get the merged job options for a job (priority: job > queue > global).\n */\n getMergedJobOptions(queue: string, jobOptions?: JobOptions): JobOptions {\n const queueConfig = this.#queueConfigs.get(queue)\n const queueJobOptions = queueConfig?.defaultJobOptions\n\n return {\n removeOnComplete:\n jobOptions?.removeOnComplete ??\n queueJobOptions?.removeOnComplete ??\n this.#globalJobOptions?.removeOnComplete,\n removeOnFail:\n jobOptions?.removeOnFail ??\n queueJobOptions?.removeOnFail ??\n this.#globalJobOptions?.removeOnFail,\n }\n }\n\n #validateConfig(config: QueueManagerConfig): void {\n if (!config.adapters || Object.keys(config.adapters).length === 0) {\n throw new errors.E_CONFIGURATION_ERROR(['At least one adapter must be configured'])\n }\n\n if (!config.default) {\n throw new errors.E_CONFIGURATION_ERROR(['Default adapter must be specified'])\n }\n\n if (!config.adapters[config.default]) {\n throw new errors.E_CONFIGURATION_ERROR([\n `Default adapter \"${config.default}\" not found in adapters configuration`,\n ])\n }\n\n for (const [name, factory] of Object.entries(config.adapters)) {\n if (typeof factory !== 'function') {\n throw new errors.E_CONFIGURATION_ERROR([`Adapter \"${name}\" must be a factory function`])\n }\n }\n }\n\n /**\n * Clean up all adapter instances and reset state.\n *\n * Call this when shutting down the application or when\n * you need to reinitialize with a new configuration.\n *\n * @example\n * ```typescript\n * // On application shutdown\n * await QueueManager.destroy()\n * ```\n */\n async destroy() {\n for (const [name, adapter] of this.#adapterInstances) {\n debug('destroying adapter \"%s\"', name)\n await adapter.destroy()\n }\n this.#adapterInstances.clear()\n this.#initialized = false\n }\n}\n\n/** Global queue manager singleton */\nexport const QueueManager = new QueueManagerSingleton()\n"],"mappings":"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","names":[]}
@@ -5,6 +5,19 @@ import {
5
5
 
6
6
  // src/utils.ts
7
7
  import { parse as parseDuration } from "@lukeed/ms";
8
+ function resolveRetention(retention) {
9
+ if (retention === void 0 || retention === true) {
10
+ return { keep: false, maxAge: 0, maxCount: 0 };
11
+ }
12
+ if (retention === false) {
13
+ return { keep: true, maxAge: 0, maxCount: 0 };
14
+ }
15
+ return {
16
+ keep: true,
17
+ maxAge: retention.age ? parse(retention.age) : 0,
18
+ maxCount: retention.count ?? 0
19
+ };
20
+ }
8
21
  function parse(duration) {
9
22
  if (typeof duration === "number") {
10
23
  return duration;
@@ -20,7 +33,8 @@ function calculateScore(priority, timestamp) {
20
33
  }
21
34
 
22
35
  export {
36
+ resolveRetention,
23
37
  parse,
24
38
  calculateScore
25
39
  };
26
- //# sourceMappingURL=chunk-NPQKBCCY.js.map
40
+ //# sourceMappingURL=chunk-PBGPIFI5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils.ts"],"sourcesContent":["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,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":[]}
@@ -198,6 +198,21 @@ interface Logger {
198
198
  * ```
199
199
  */
200
200
  type Duration = number | string;
201
+ /**
202
+ * Retention policy for completed/failed jobs.
203
+ *
204
+ * - `true` (default): Remove job immediately
205
+ * - `false`: Keep job in history indefinitely
206
+ * - `{ age?, count? }`: Keep with pruning by age and/or count
207
+ */
208
+ type JobRetention = boolean | {
209
+ age?: Duration;
210
+ count?: number;
211
+ };
212
+ /**
213
+ * Possible statuses for a job in the queue.
214
+ */
215
+ type JobStatus = 'pending' | 'active' | 'delayed' | 'completed' | 'failed';
201
216
  /**
202
217
  * Result returned when dispatching a job.
203
218
  *
@@ -211,6 +226,19 @@ interface DispatchResult {
211
226
  /** Unique identifier for this specific job instance */
212
227
  jobId: string;
213
228
  }
229
+ /**
230
+ * Result returned when dispatching multiple jobs at once.
231
+ *
232
+ * @example
233
+ * ```typescript
234
+ * const { jobIds } = await SendEmailJob.dispatchMany(payloads)
235
+ * console.log(`Dispatched ${jobIds.length} jobs`)
236
+ * ```
237
+ */
238
+ interface DispatchManyResult {
239
+ /** Unique identifiers for all dispatched job instances */
240
+ jobIds: string[];
241
+ }
214
242
  /**
215
243
  * Internal representation of a job in the queue.
216
244
  *
@@ -248,6 +276,34 @@ interface JobData {
248
276
  * Number of times this job was recovered from stalled state.
249
277
  */
250
278
  stalledCount?: number;
279
+ /**
280
+ * Optional group identifier for organizing related jobs.
281
+ *
282
+ * Jobs with the same groupId can be filtered and displayed together
283
+ * in monitoring UIs. Useful for batch operations like newsletters
284
+ * or bulk exports.
285
+ *
286
+ * @example
287
+ * ```typescript
288
+ * await SendEmailJob.dispatch({ to: 'user@example.com' })
289
+ * .group('newsletter-jan-2025')
290
+ * .run()
291
+ * ```
292
+ */
293
+ groupId?: string;
294
+ }
295
+ /**
296
+ * Record of a job's current state, including history for completed/failed jobs.
297
+ */
298
+ interface JobRecord {
299
+ /** Current status of the job */
300
+ status: JobStatus;
301
+ /** Original job data */
302
+ data: JobData;
303
+ /** Timestamp when the job finished (for completed/failed jobs) */
304
+ finishedAt?: number;
305
+ /** Error message (for failed jobs) */
306
+ error?: string;
251
307
  }
252
308
  /**
253
309
  * Static options for a Job class.
@@ -314,6 +370,8 @@ interface JobOptions {
314
370
  * @default true
315
371
  */
316
372
  failOnTimeout?: boolean;
373
+ removeOnComplete?: JobRetention;
374
+ removeOnFail?: JobRetention;
317
375
  }
318
376
  /**
319
377
  * Context information available to a job during execution.
@@ -395,6 +453,7 @@ interface BackoffConfig {
395
453
  interface QueueConfig {
396
454
  adapter?: string;
397
455
  retry?: any;
456
+ defaultJobOptions?: JobOptions;
398
457
  }
399
458
  interface WorkerConfig {
400
459
  /**
@@ -541,6 +600,7 @@ interface QueueManagerConfig {
541
600
  default: string;
542
601
  adapters: Record<string, AdapterFactory>;
543
602
  retry?: RetryConfig;
603
+ defaultJobOptions?: JobOptions;
544
604
  queues?: Record<string, QueueConfig>;
545
605
  worker?: WorkerConfig;
546
606
  locations?: string[];
@@ -634,16 +694,18 @@ interface Adapter {
634
694
  *
635
695
  * @param jobId - The job ID to complete
636
696
  * @param queue - The queue the job belongs to
697
+ * @param removeOnComplete - Optional retention policy for completed jobs
637
698
  */
638
- completeJob(jobId: string, queue: string): Promise<void>;
699
+ completeJob(jobId: string, queue: string, removeOnComplete?: JobRetention): Promise<void>;
639
700
  /**
640
701
  * Mark a job as failed permanently and remove it from the queue.
641
702
  *
642
703
  * @param jobId - The job ID to fail
643
704
  * @param queue - The queue the job belongs to
644
705
  * @param error - Optional error that caused the failure
706
+ * @param removeOnFail - Optional retention policy for failed jobs
645
707
  */
646
- failJob(jobId: string, queue: string, error?: Error): Promise<void>;
708
+ failJob(jobId: string, queue: string, error?: Error, removeOnFail?: JobRetention): Promise<void>;
647
709
  /**
648
710
  * Retry a job by moving it back to pending with incremented attempts.
649
711
  *
@@ -652,6 +714,14 @@ interface Adapter {
652
714
  * @param retryAt - Optional future date to delay the retry
653
715
  */
654
716
  retryJob(jobId: string, queue: string, retryAt?: Date): Promise<void>;
717
+ /**
718
+ * Get a job record by id.
719
+ *
720
+ * @param jobId - The job ID to retrieve
721
+ * @param queue - The queue the job belongs to
722
+ * @returns The job record, or null if not found
723
+ */
724
+ getJob(jobId: string, queue: string): Promise<JobRecord | null>;
655
725
  /**
656
726
  * Push a job to the default queue for immediate processing.
657
727
  *
@@ -680,6 +750,25 @@ interface Adapter {
680
750
  * @param delay - Delay in milliseconds before the job becomes available
681
751
  */
682
752
  pushLaterOn(queue: string, jobData: JobData, delay: number): Promise<void>;
753
+ /**
754
+ * Push multiple jobs to the default queue for immediate processing.
755
+ *
756
+ * This is more efficient than calling push() multiple times as it
757
+ * batches the operations (e.g., Redis pipeline, SQL batch insert).
758
+ *
759
+ * @param jobs - Array of job data to push
760
+ */
761
+ pushMany(jobs: JobData[]): Promise<void>;
762
+ /**
763
+ * Push multiple jobs to a specific queue for immediate processing.
764
+ *
765
+ * This is more efficient than calling pushOn() multiple times as it
766
+ * batches the operations (e.g., Redis pipeline, SQL batch insert).
767
+ *
768
+ * @param queue - The queue name to push to
769
+ * @param jobs - Array of job data to push
770
+ */
771
+ pushManyOn(queue: string, jobs: JobData[]): Promise<void>;
683
772
  /**
684
773
  * Get the number of pending jobs in the default queue.
685
774
  *
@@ -842,6 +931,25 @@ declare class JobDispatcher<T> {
842
931
  * ```
843
932
  */
844
933
  priority(priority: number): this;
934
+ /**
935
+ * Assign this job to a group.
936
+ *
937
+ * Jobs with the same groupId can be filtered and displayed together
938
+ * in monitoring UIs. Useful for batch operations like newsletters
939
+ * or bulk exports.
940
+ *
941
+ * @param groupId - Group identifier
942
+ * @returns This dispatcher for chaining
943
+ *
944
+ * @example
945
+ * ```typescript
946
+ * // Group newsletter jobs together
947
+ * await SendEmailJob.dispatch({ to: 'user@example.com' })
948
+ * .group('newsletter-jan-2025')
949
+ * .run()
950
+ * ```
951
+ */
952
+ group(groupId: string): this;
845
953
  /**
846
954
  * Use a specific adapter for this job.
847
955
  *
@@ -882,6 +990,127 @@ declare class JobDispatcher<T> {
882
990
  then(onFulfilled?: (value: DispatchResult) => any, onRejected?: (reason: any) => any): Promise<any>;
883
991
  }
884
992
 
993
+ /**
994
+ * Fluent builder for dispatching multiple jobs to the queue in a single batch.
995
+ *
996
+ * Provides a chainable API for configuring job options before dispatch.
997
+ * Usually created via `Job.dispatchMany()` rather than directly.
998
+ *
999
+ * ```
1000
+ * Job.dispatchMany(payloads)
1001
+ * .toQueue('emails') // optional: target queue
1002
+ * .priority(1) // optional: 1-10, lower = higher priority
1003
+ * .group('batch-123') // optional: group all jobs together
1004
+ * .with('redis') // optional: specific adapter
1005
+ * .run() // dispatch all jobs
1006
+ * ```
1007
+ *
1008
+ * @typeParam T - The payload type for these jobs
1009
+ *
1010
+ * @example
1011
+ * ```typescript
1012
+ * // Batch dispatch for newsletter
1013
+ * const { jobIds } = await SendEmailJob.dispatchMany([
1014
+ * { to: 'user1@example.com', subject: 'Newsletter' },
1015
+ * { to: 'user2@example.com', subject: 'Newsletter' },
1016
+ * ])
1017
+ * .group('newsletter-jan-2025')
1018
+ * .toQueue('emails')
1019
+ * .run()
1020
+ *
1021
+ * console.log(`Dispatched ${jobIds.length} jobs`)
1022
+ * ```
1023
+ */
1024
+ declare class JobBatchDispatcher<T> {
1025
+ #private;
1026
+ /**
1027
+ * Create a new batch job dispatcher.
1028
+ *
1029
+ * @param name - The job class name (used to locate the class at runtime)
1030
+ * @param payloads - Array of data to pass to each job
1031
+ */
1032
+ constructor(name: string, payloads: T[]);
1033
+ /**
1034
+ * Set the target queue for all jobs.
1035
+ *
1036
+ * @param queue - Queue name (default: 'default')
1037
+ * @returns This dispatcher for chaining
1038
+ *
1039
+ * @example
1040
+ * ```typescript
1041
+ * await SendEmailJob.dispatchMany(payloads).toQueue('emails')
1042
+ * ```
1043
+ */
1044
+ toQueue(queue: string): this;
1045
+ /**
1046
+ * Set the priority for all jobs.
1047
+ *
1048
+ * Lower numbers = higher priority. Jobs with lower priority values
1049
+ * are processed before jobs with higher values.
1050
+ *
1051
+ * @param priority - Priority level (1-10, default: 5)
1052
+ * @returns This dispatcher for chaining
1053
+ *
1054
+ * @example
1055
+ * ```typescript
1056
+ * await UrgentJob.dispatchMany(payloads).priority(1)
1057
+ * ```
1058
+ */
1059
+ priority(priority: number): this;
1060
+ /**
1061
+ * Assign all jobs to a group.
1062
+ *
1063
+ * Jobs with the same groupId can be filtered and displayed together
1064
+ * in monitoring UIs. Useful for batch operations like newsletters
1065
+ * or bulk exports.
1066
+ *
1067
+ * @param groupId - Group identifier
1068
+ * @returns This dispatcher for chaining
1069
+ *
1070
+ * @example
1071
+ * ```typescript
1072
+ * await SendEmailJob.dispatchMany(recipients)
1073
+ * .group('newsletter-jan-2025')
1074
+ * .run()
1075
+ * ```
1076
+ */
1077
+ group(groupId: string): this;
1078
+ /**
1079
+ * Use a specific adapter for these jobs.
1080
+ *
1081
+ * @param adapter - Adapter name or factory function
1082
+ * @returns This dispatcher for chaining
1083
+ *
1084
+ * @example
1085
+ * ```typescript
1086
+ * await Job.dispatchMany(payloads).with('redis')
1087
+ * ```
1088
+ */
1089
+ with(adapter: string | (() => Adapter)): this;
1090
+ /**
1091
+ * Dispatch all jobs to the queue.
1092
+ *
1093
+ * @returns A DispatchManyResult containing all jobIds
1094
+ *
1095
+ * @example
1096
+ * ```typescript
1097
+ * const { jobIds } = await SendEmailJob.dispatchMany(payloads).run()
1098
+ * console.log(`Dispatched ${jobIds.length} jobs`)
1099
+ * ```
1100
+ */
1101
+ run(): Promise<DispatchManyResult>;
1102
+ /**
1103
+ * Thenable implementation for auto-dispatch when awaited.
1104
+ *
1105
+ * Allows `await Job.dispatchMany(payloads)` without explicit `.run()`.
1106
+ *
1107
+ * @param onFulfilled - Success callback
1108
+ * @param onRejected - Error callback
1109
+ * @returns Promise resolving to the DispatchManyResult
1110
+ */
1111
+ then(onFulfilled?: (value: DispatchManyResult) => any, onRejected?: (reason: any) => any): Promise<any>;
1112
+ }
1113
+
885
1114
  /**
886
1115
  * Fluent builder for creating job schedules.
887
1116
  *
@@ -1103,6 +1332,34 @@ declare abstract class Job<Payload = any> {
1103
1332
  * ```
1104
1333
  */
1105
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>;
1335
+ /**
1336
+ * Dispatch multiple jobs to the queue in a single batch.
1337
+ *
1338
+ * Returns a JobBatchDispatcher for fluent configuration before dispatching.
1339
+ * The jobs are not actually dispatched until `.run()` is called or the
1340
+ * dispatcher is awaited.
1341
+ *
1342
+ * This is more efficient than calling `dispatch()` multiple times as it
1343
+ * uses batched operations (e.g., Redis pipeline, SQL batch insert).
1344
+ *
1345
+ * @param payloads - Array of data to pass to each job
1346
+ * @returns A JobBatchDispatcher for fluent configuration
1347
+ *
1348
+ * @example
1349
+ * ```typescript
1350
+ * // Batch dispatch for newsletter
1351
+ * const { jobIds } = await SendEmailJob.dispatchMany([
1352
+ * { to: 'user1@example.com', subject: 'Newsletter' },
1353
+ * { to: 'user2@example.com', subject: 'Newsletter' },
1354
+ * ])
1355
+ * .group('newsletter-jan-2025')
1356
+ * .toQueue('emails')
1357
+ * .run()
1358
+ *
1359
+ * console.log(`Dispatched ${jobIds.length} jobs`)
1360
+ * ```
1361
+ */
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>;
1106
1363
  /**
1107
1364
  * Create a schedule for this job.
1108
1365
  *
@@ -1171,4 +1428,4 @@ declare abstract class Job<Payload = any> {
1171
1428
  failed?(error: Error): Promise<void>;
1172
1429
  }
1173
1430
 
1174
- 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 AcquiredJob as a, type ScheduleData as b, type ScheduleListOptions as c, type JobFactory as d, Job as e, type JobClass as f, type ScheduleStatus as g, ScheduleBuilder as h, customBackoff as i, exponentialBackoff as j, fixedBackoff as k, linearBackoff as l, type DispatchResult as m, type JobOptions as n, type JobContext as o, type BackoffConfig as p, type QueueConfig as q, type WorkerConfig as r, type AdapterFactory as s, type ScheduleResult as t };
1431
+ export { type Adapter as A, type BackoffStrategy as B, type Duration as D, type JobRetention as J, type Logger as L, type QueueManagerConfig as Q, type RetryConfig as R, type ScheduleConfig as S, type WorkerCycle as W, type AcquiredJob as a, type JobRecord as b, type JobData as c, type ScheduleData as d, type ScheduleListOptions as e, type JobFactory as f, type JobOptions as g, Job as h, type JobClass 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 };
package/build/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { Q as QueueManagerConfig, W as WorkerCycle, A as Adapter, R as RetryConfig, d as JobFactory, e as Job, f as JobClass, b as ScheduleData, g as ScheduleStatus, c as ScheduleListOptions } from './index-C0Xg6F4E.js';
2
- export { h as ScheduleBuilder, i as customBackoff, j as exponentialBackoff, k as fixedBackoff, l as linearBackoff } from './index-C0Xg6F4E.js';
1
+ import { Q as QueueManagerConfig, W as WorkerCycle, A as Adapter, R as RetryConfig, f as JobFactory, g as JobOptions, h as Job, i as JobClass, d as ScheduleData, j as ScheduleStatus, e as ScheduleListOptions } from './index-BzPIqdx3.js';
2
+ export { l as JobBatchDispatcher, k as ScheduleBuilder, m as customBackoff, o as exponentialBackoff, p as fixedBackoff, n as linearBackoff } from './index-BzPIqdx3.js';
3
3
  import * as _poppinss_utils from '@poppinss/utils';
4
4
 
5
5
  /**
@@ -232,6 +232,10 @@ declare class QueueManagerSingleton {
232
232
  * @returns The job factory function, or undefined if not configured
233
233
  */
234
234
  getJobFactory(): JobFactory | undefined;
235
+ /**
236
+ * Get the merged job options for a job (priority: job > queue > global).
237
+ */
238
+ getMergedJobOptions(queue: string, jobOptions?: JobOptions): JobOptions;
235
239
  /**
236
240
  * Clean up all adapter instances and reset state.
237
241
  *