@vercube/queue 1.3.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,715 @@
1
+ import { IOC } from "@vercube/di";
2
+ import { MaybePromise, ValidationTypes } from "@vercube/core";
3
+ //#region src/Types/QueueTypes.d.ts
4
+ declare namespace QueueTypes {
5
+ /**
6
+ * Type registry mapping queue names to the jobs they accept.
7
+ *
8
+ * It is empty by default, which keeps every queue and job name a plain string.
9
+ * Augment it to make `QueueManager.add()` fully type checked - registered queues
10
+ * then only accept their own job names with matching payloads, while unregistered
11
+ * queues keep working as before.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * declare module '@vercube/queue' {
16
+ * namespace QueueTypes {
17
+ * interface Registry {
18
+ * emails: {
19
+ * welcome: { userId: string };
20
+ * digest: { userId: string; period: 'daily' | 'weekly' };
21
+ * };
22
+ * }
23
+ * }
24
+ * }
25
+ * ```
26
+ */
27
+ interface Registry {}
28
+ /**
29
+ * Name of a queue. Resolves to the keys of {@link Registry} for autocompletion,
30
+ * while still accepting any other string.
31
+ */
32
+ type QueueName = Extract<keyof Registry, string> | (string & {});
33
+ /**
34
+ * Job names allowed on a given queue. Restricted to the jobs declared in
35
+ * {@link Registry} for registered queues, any string otherwise.
36
+ *
37
+ * @typeParam TQueue - Queue the job belongs to.
38
+ */
39
+ type JobName<TQueue> = TQueue extends keyof Registry ? Extract<keyof Registry[TQueue], string> : string;
40
+ /**
41
+ * Payload type of a job. Taken from {@link Registry} for registered queues,
42
+ * `unknown` otherwise.
43
+ *
44
+ * @typeParam TQueue - Queue the job belongs to.
45
+ * @typeParam TJob - Name of the job.
46
+ */
47
+ type JobPayload<TQueue, TJob> = TQueue extends keyof Registry ? TJob extends keyof Registry[TQueue] ? Registry[TQueue][TJob] : never : unknown;
48
+ /**
49
+ * Delay applied between two attempts of the same job.
50
+ * A plain number is a fixed delay in milliseconds.
51
+ */
52
+ type Backoff = number | {
53
+ type: 'fixed' | 'exponential';
54
+ delay: number;
55
+ };
56
+ /**
57
+ * Per-job options accepted when adding a job to a queue.
58
+ * Options a strategy cannot honour natively are either emulated by the
59
+ * {@link QueueManager} or reported through {@link Capabilities}.
60
+ */
61
+ interface JobOptions {
62
+ /**
63
+ * Total number of attempts, the first one included.
64
+ * @default 1
65
+ */
66
+ attempts?: number;
67
+ /**
68
+ * Delay between attempts. A number is treated as a fixed delay in milliseconds,
69
+ * `exponential` doubles the delay on every attempt.
70
+ * @default 0
71
+ */
72
+ backoff?: Backoff;
73
+ /** Milliseconds to wait before the job becomes available for processing. */
74
+ delay?: number;
75
+ /** Job priority, lower values are processed first. */
76
+ priority?: number;
77
+ /** Explicit job id, used by strategies that deduplicate on it. */
78
+ jobId?: string;
79
+ /** Routing or partition key, used by Kafka and RabbitMQ to keep related jobs ordered. */
80
+ key?: string;
81
+ /** Extra transport headers travelling with the job. */
82
+ headers?: Record<string, string>;
83
+ /** Whether completed jobs are kept, or how many of them, for strategies that store history. */
84
+ removeOnComplete?: boolean | number;
85
+ /** Whether failed jobs are kept, or how many of them, for strategies that store history. */
86
+ removeOnFail?: boolean | number;
87
+ }
88
+ /**
89
+ * Mount definition of a strategy, as accepted by {@link QueueManager.mount}.
90
+ * `initOptions` is required when the strategy declares initialization options.
91
+ *
92
+ * @typeParam T - Strategy being mounted.
93
+ */
94
+ type Mount<T extends QueueStrategy<unknown>> = {
95
+ /**
96
+ * Name the strategy is mounted under, referenced by the `strategy` option
97
+ * of every other call.
98
+ * @default 'default'
99
+ */
100
+ name?: string;
101
+ /** Strategy class, resolved through the container so it can use `@Inject`. */
102
+ strategy: IOC.Newable<T>;
103
+ } & (undefined extends InitOptionsOf<T> ? {
104
+ initOptions?: InitOptionsOf<T>;
105
+ } : {
106
+ initOptions: InitOptionsOf<T>;
107
+ });
108
+ /**
109
+ * Options a strategy is initialized with, read off the type-only marker
110
+ * `QueueStrategy` carries.
111
+ *
112
+ * @typeParam T - Strategy to read the options of.
113
+ */
114
+ type InitOptionsOf<T> = T extends {
115
+ __initOptions: infer U;
116
+ } ? U : never;
117
+ /** A mounted strategy together with the options it is initialized with. */
118
+ interface MountedStrategy<T = unknown> {
119
+ /** Name the strategy is mounted under. */
120
+ name: string;
121
+ /** The resolved strategy instance. */
122
+ strategy: QueueStrategy<T>;
123
+ /** Options passed to `initialize()` on first use. */
124
+ initOptions?: T;
125
+ /** Resolves once the strategy has been initialized, absent before the first use. */
126
+ ready?: Promise<void>;
127
+ /** Error the last initialization attempt failed with. */
128
+ error?: Error;
129
+ }
130
+ /**
131
+ * Request to add a single job to a queue.
132
+ *
133
+ * @typeParam TQueue - Queue the job is added to.
134
+ * @typeParam TJob - Name of the job.
135
+ */
136
+ interface AddRequest<TQueue = QueueName, TJob = JobName<TQueue>> {
137
+ /**
138
+ * Mounted strategy to publish through.
139
+ * @default 'default'
140
+ */
141
+ strategy?: string;
142
+ /** Queue the job is added to. */
143
+ queue: TQueue;
144
+ /** Name of the job, used to pick the handler on the consumer side. */
145
+ job: TJob;
146
+ /** Payload handed to the handler. Must survive JSON serialization. */
147
+ payload: JobPayload<TQueue, TJob>;
148
+ /** Per-job options such as retries, delay or priority. */
149
+ options?: JobOptions;
150
+ }
151
+ /**
152
+ * Request to add many jobs of the same kind to a queue in one round trip.
153
+ *
154
+ * @typeParam TQueue - Queue the jobs are added to.
155
+ * @typeParam TJob - Name of the jobs.
156
+ */
157
+ interface AddManyRequest<TQueue = QueueName, TJob = JobName<TQueue>> extends Omit<AddRequest<TQueue, TJob>, 'payload'> {
158
+ /** Payloads to publish, one job per entry. */
159
+ payloads: JobPayload<TQueue, TJob>[];
160
+ }
161
+ /** Identifies a job that has been published. */
162
+ interface JobRef {
163
+ /** Id assigned by the strategy, or generated when the transport has none. */
164
+ id: string;
165
+ /** Queue the job was published to. */
166
+ queue: string;
167
+ /** Name of the job. */
168
+ job: string;
169
+ /** Name of the strategy the job was published through. */
170
+ strategy: string;
171
+ }
172
+ /** A job as handed to a strategy for publishing. */
173
+ interface PublishRequest {
174
+ /** Queue to publish to. */
175
+ queue: string;
176
+ /** Name of the job. */
177
+ job: string;
178
+ /** Payload to publish. */
179
+ payload: unknown;
180
+ /** Transport headers, already including the queue module's own bookkeeping. */
181
+ headers: Record<string, string>;
182
+ /** Per-job options. */
183
+ options: JobOptions;
184
+ }
185
+ /** A job as received from a strategy, before any handler runs. */
186
+ interface IncomingJob {
187
+ /** Id of the job, unique within the queue. */
188
+ id: string;
189
+ /** Name of the job, resolved from the transport. */
190
+ job: string;
191
+ /** Raw payload, already deserialized. */
192
+ payload: unknown;
193
+ /** Transport headers received with the job. */
194
+ headers: Record<string, string>;
195
+ /**
196
+ * Attempt number, starting at 1.
197
+ */
198
+ attempt: number;
199
+ /** Total attempts the transport itself will make, when it owns retries. */
200
+ attempts?: number;
201
+ /** Strategy-native job or message, for advanced use. */
202
+ raw?: unknown;
203
+ /** Reports handler progress back to the transport, when it supports it. */
204
+ updateProgress?: (progress: number | Record<string, unknown>) => MaybePromise<void>;
205
+ }
206
+ /** Everything a handler learns about the job it is processing. */
207
+ interface JobContext<T = unknown> {
208
+ /** Id of the job. */
209
+ id: string;
210
+ /** Name of the job. */
211
+ job: string;
212
+ /** Queue the job came from. */
213
+ queue: string;
214
+ /** Name of the strategy the job came from. */
215
+ strategy: string;
216
+ /** Attempt number, starting at 1. */
217
+ attempt: number;
218
+ /** Total number of attempts this job may take. */
219
+ attempts: number;
220
+ /** Validated payload, identical to the first handler argument. */
221
+ payload: T;
222
+ /** Transport headers received with the job. */
223
+ headers: Record<string, string>;
224
+ /** Strategy-native job or message, for advanced use. */
225
+ raw?: unknown;
226
+ /** Logger scoped to this job, when a logger is bound in the container. */
227
+ logger: LoggerLike | null;
228
+ /**
229
+ * Reports progress back to the transport. A no-op for transports that
230
+ * do not track job progress.
231
+ *
232
+ * @param progress - Percentage or arbitrary progress payload.
233
+ * @returns Resolves once the progress has been reported.
234
+ */
235
+ updateProgress: (progress: number | Record<string, unknown>) => Promise<void>;
236
+ }
237
+ /**
238
+ * Minimal logger contract used inside a {@link JobContext}, so job code does not
239
+ * have to import the logger package.
240
+ */
241
+ interface LoggerLike {
242
+ debug: (...args: unknown[]) => void;
243
+ info: (...args: unknown[]) => void;
244
+ warn: (...args: unknown[]) => void;
245
+ error: (...args: unknown[]) => void;
246
+ }
247
+ /**
248
+ * A job handler.
249
+ *
250
+ * Throwing marks the job as failed and hands it to the retry policy, returning
251
+ * marks it as completed.
252
+ *
253
+ * @typeParam T - Payload type of the job.
254
+ */
255
+ type Handler<T = any> = (payload: T, context: JobContext<T>) => MaybePromise<void>;
256
+ /** Called after a job completed successfully. */
257
+ type CompletedHook = (context: JobContext) => MaybePromise<void>;
258
+ /** Called after a job threw, once per failed attempt. */
259
+ type FailedHook = (error: Error, context: JobContext) => MaybePromise<void>;
260
+ /** Consumer-side options of a single job handler. */
261
+ interface HandlerOptions {
262
+ /**
263
+ * Total attempts to apply when the published job does not carry its own
264
+ * `attempts` option.
265
+ * @default 1
266
+ */
267
+ attempts?: number;
268
+ /** Delay between attempts, used with {@link HandlerOptions.attempts}. */
269
+ backoff?: Backoff;
270
+ /** Milliseconds after which a running handler is considered failed. */
271
+ timeout?: number;
272
+ /** Standard Schema validating the payload before the handler runs. */
273
+ schema?: ValidationTypes.Schema;
274
+ }
275
+ /** Options shared by every handler of a consumer class. */
276
+ interface ConsumerOptions extends HandlerOptions {
277
+ /** Queue the consumer reads from. */
278
+ queue: QueueName;
279
+ /**
280
+ * Mounted strategy to consume from.
281
+ * @default 'default'
282
+ */
283
+ strategy?: string;
284
+ /**
285
+ * How many jobs of this queue may run in parallel.
286
+ * @default 1
287
+ */
288
+ concurrency?: number;
289
+ }
290
+ /** A registered job handler, as kept by the {@link QueueManager}. */
291
+ interface Registration {
292
+ /** Name of the strategy the handler consumes from. */
293
+ strategy: string;
294
+ /** Queue the handler consumes from. */
295
+ queue: string;
296
+ /** Name of the job the handler processes, or `*` for every unclaimed job of the queue. */
297
+ job: string;
298
+ /** The handler itself, already bound to its instance. */
299
+ handler: Handler;
300
+ /** Consumer-side options of the handler. */
301
+ options: HandlerOptions;
302
+ /** How many jobs of this queue the handler's consumer may run in parallel. */
303
+ concurrency?: number;
304
+ /** Display name of the handler, in the `Class.method` form. */
305
+ source: string;
306
+ }
307
+ /** A registered lifecycle hook, as kept by the {@link QueueManager}. */
308
+ interface HookRegistration {
309
+ /** Name of the strategy the hook listens on. */
310
+ strategy: string;
311
+ /** Queue the hook listens on. */
312
+ queue: string;
313
+ /** Job the hook is limited to, or undefined (or `*`) for every job of the queue. */
314
+ job?: string;
315
+ /** The hook itself, already bound to its instance. */
316
+ hook: CompletedHook | FailedHook;
317
+ /** Display name of the hook, in the `Class.method` form. */
318
+ source: string;
319
+ }
320
+ /** State a peeked message is sitting in. */
321
+ type PeekState = 'waiting' | 'active' | 'delayed' | 'failed';
322
+ /** Request to look at what a queue is holding, without consuming it. */
323
+ interface PeekRequest {
324
+ /** Queue to look at. */
325
+ queue: string;
326
+ /**
327
+ * How many messages to read at most.
328
+ * @default 20
329
+ */
330
+ limit: number;
331
+ /**
332
+ * States to read. Transports that only keep a backlog ignore everything but
333
+ * `waiting` and `delayed`.
334
+ * @default ['waiting', 'delayed', 'failed']
335
+ */
336
+ states: PeekState[];
337
+ }
338
+ /** A message a strategy found on a queue, as the strategy read it. */
339
+ interface PeekedMessage {
340
+ /** Id of the message. */
341
+ id: string;
342
+ /** Name of the job. */
343
+ job: string;
344
+ /** Where it is sitting. */
345
+ state: PeekState;
346
+ /** Attempt it is on, when the transport tracks that. */
347
+ attempt?: number;
348
+ /** Raw payload, rendered by the manager before it leaves the module. */
349
+ payload: unknown;
350
+ /** Transport headers. */
351
+ headers: Record<string, string>;
352
+ /** Epoch milliseconds it becomes available at, for a delayed message. */
353
+ availableAt?: number;
354
+ /** Why it failed, for a message the transport keeps in a failed set. */
355
+ error?: {
356
+ name?: string;
357
+ message: string;
358
+ stack?: string;
359
+ };
360
+ }
361
+ /** A message on a queue, ready to be inspected. */
362
+ interface PeekedJob extends Omit<PeekedMessage, 'payload'> {
363
+ /**
364
+ * Payload preview, with credential-looking fields withheld and the text
365
+ * capped at `maxPayloadBytes`.
366
+ */
367
+ payload?: string;
368
+ }
369
+ /** What a queue a strategy talks to can actually do. */
370
+ interface Capabilities {
371
+ /** The transport retries failed jobs on its own. */
372
+ retries: boolean;
373
+ /** The transport can delay a job before it becomes available. */
374
+ delay: boolean;
375
+ /** The transport honours job priority. */
376
+ priority: boolean;
377
+ /** The transport tracks job progress. */
378
+ progress: boolean;
379
+ /** The strategy can report queue statistics. */
380
+ stats: boolean;
381
+ /** The strategy can show what a queue holds without consuming it. */
382
+ peek: boolean;
383
+ }
384
+ /** Request handed to a strategy when a queue starts being consumed. */
385
+ interface ConsumeRequest {
386
+ /** Queue to consume. */
387
+ queue: string;
388
+ /** How many jobs may be processed in parallel. */
389
+ concurrency: number;
390
+ /**
391
+ * Processes a single job. Rejecting means the job failed, and the strategy
392
+ * should apply its own failure semantics.
393
+ */
394
+ dispatch: (job: IncomingJob) => Promise<void>;
395
+ }
396
+ /** Handle over a running consumer, used to stop it again. */
397
+ interface ConsumerHandle {
398
+ /** Queue being consumed. */
399
+ queue: string;
400
+ /**
401
+ * Stops the consumer, waiting for in-flight jobs to settle.
402
+ *
403
+ * @returns Resolves once the consumer is stopped.
404
+ */
405
+ stop: () => Promise<void>;
406
+ }
407
+ /** Live counters of a single queue. */
408
+ interface QueueStats {
409
+ /** Jobs waiting to be processed, when the transport can tell. */
410
+ waiting?: number;
411
+ /** Jobs currently being processed. */
412
+ active?: number;
413
+ /** Jobs that completed successfully. */
414
+ completed?: number;
415
+ /** Jobs that exhausted their attempts. */
416
+ failed?: number;
417
+ /** Jobs waiting for their delay to elapse. */
418
+ delayed?: number;
419
+ }
420
+ /** Counters the manager keeps per queue, independent of the transport. */
421
+ interface QueueMetrics {
422
+ /** Name of the strategy. */
423
+ strategy: string;
424
+ /** Name of the queue. */
425
+ queue: string;
426
+ /** Jobs published through this manager. */
427
+ published: number;
428
+ /** Jobs whose handler completed successfully. */
429
+ processed: number;
430
+ /** Attempts that ended with an error. */
431
+ failed: number;
432
+ /** Attempts scheduled again after a failure. */
433
+ retried: number;
434
+ /** Jobs received with no handler registered for their name. */
435
+ unhandled: number;
436
+ /** Handlers currently running. */
437
+ active: number;
438
+ /** Message of the last error seen on this queue. */
439
+ lastError?: string;
440
+ }
441
+ /** Outcome of a single processing attempt. */
442
+ type JobStatus = 'completed' | 'failed' | 'retried' | 'unhandled';
443
+ /** What went wrong on a failed attempt. */
444
+ interface JobFailure {
445
+ /** Error class name, for example `QueueError` or `TypeError`. */
446
+ name: string;
447
+ /** Message the error carried. */
448
+ message: string;
449
+ /** Stack trace, capped, when the error had one. */
450
+ stack?: string;
451
+ /** Queue operation that failed, for errors this module raised. */
452
+ operation?: string;
453
+ /** Whether running the job again could have helped. */
454
+ retryable?: boolean;
455
+ }
456
+ /** A processed job, as kept in the manager's ring buffer. */
457
+ interface JobEvent {
458
+ /** Epoch milliseconds the attempt finished at. */
459
+ at: number;
460
+ /** Name of the strategy. */
461
+ strategy: string;
462
+ /** Name of the queue. */
463
+ queue: string;
464
+ /** Name of the job. */
465
+ job: string;
466
+ /** Id of the job. */
467
+ id: string;
468
+ /** Attempt number. */
469
+ attempt: number;
470
+ /** Outcome of the attempt. */
471
+ status: JobStatus;
472
+ /** Wall clock duration of the handler, in milliseconds. */
473
+ duration: number;
474
+ /** What went wrong, for failed attempts. */
475
+ error?: JobFailure;
476
+ /**
477
+ * Payload preview of a failed attempt, kept only while `capturePayloads` is
478
+ * on. Credential-looking fields are withheld and the text is capped.
479
+ */
480
+ payload?: string;
481
+ /** Transport headers of a failed attempt, kept only while `capturePayloads` is on. */
482
+ headers?: Record<string, string>;
483
+ /** Handler that ran, in the `Class.method` form. */
484
+ source?: string;
485
+ }
486
+ /**
487
+ * Called for every job the manager finishes, as it finishes it.
488
+ * Used to follow a queue live instead of polling it.
489
+ */
490
+ type JobListener = (event: JobEvent) => void;
491
+ /** State of a mounted strategy. */
492
+ type StrategyStatus = 'idle' | 'ready' | 'error' | 'closed';
493
+ /** A mounted strategy, as reported by {@link QueueManager.inspect}. */
494
+ interface StrategyInfo {
495
+ /** Name the strategy is mounted under. */
496
+ name: string;
497
+ /** Transport the strategy talks to, for example `bullmq`. */
498
+ transport: string;
499
+ /** Class name of the strategy. */
500
+ driver: string;
501
+ /** Current state of the strategy. */
502
+ status: StrategyStatus;
503
+ /** What the transport supports. */
504
+ capabilities: Capabilities;
505
+ /** Message of the error the strategy failed with. */
506
+ error?: string;
507
+ }
508
+ /** A registered handler, as reported by {@link QueueManager.inspect}. */
509
+ interface ConsumerInfo {
510
+ /** Name of the strategy. */
511
+ strategy: string;
512
+ /** Queue the handler consumes from. */
513
+ queue: string;
514
+ /** Name of the job. */
515
+ job: string;
516
+ /** Display name of the handler, in the `Class.method` form. */
517
+ source: string;
518
+ /** Attempts applied when the job carries none. */
519
+ attempts: number;
520
+ /** Handler timeout in milliseconds, when one is set. */
521
+ timeout?: number;
522
+ /** Whether the payload is validated before the handler runs. */
523
+ validated: boolean;
524
+ /** Whether the queue is currently being consumed. */
525
+ running: boolean;
526
+ }
527
+ /** Full picture of the queue module at a point in time. */
528
+ interface Snapshot {
529
+ /** Whether consumers have been started. */
530
+ started: boolean;
531
+ /** Mounted strategies. */
532
+ strategies: StrategyInfo[];
533
+ /** Registered handlers. */
534
+ consumers: ConsumerInfo[];
535
+ /** Per-queue counters. */
536
+ metrics: QueueMetrics[];
537
+ /** Recently processed jobs, newest first. */
538
+ events: JobEvent[];
539
+ }
540
+ /**
541
+ * A strategy mount with its init options erased, so several mounts of
542
+ * different strategies can sit in one list.
543
+ *
544
+ * A plain array cannot check `initOptions` against its `strategy`, because
545
+ * there is nothing for TypeScript to infer the strategy from. Wrap each entry
546
+ * in {@link defineQueueStrategy} to get that check back.
547
+ */
548
+ interface AnyMount {
549
+ /**
550
+ * Name the strategy is mounted under.
551
+ * @default 'default'
552
+ */
553
+ name?: string;
554
+ /** Strategy class, resolved through the container. */
555
+ strategy: IOC.Newable<QueueStrategy<any>>;
556
+ /** Options passed to the strategy on first use. */
557
+ initOptions?: unknown;
558
+ }
559
+ /** Manager-wide settings. */
560
+ interface Defaults {
561
+ /**
562
+ * Start consumers automatically once the container is initialized.
563
+ * Set to false in producer-only processes.
564
+ * @default true
565
+ */
566
+ autoStart?: boolean;
567
+ /**
568
+ * Default number of jobs processed in parallel per queue.
569
+ * @default 1
570
+ */
571
+ concurrency?: number;
572
+ /**
573
+ * What to do with a job no handler is registered for. `ignore` drops it,
574
+ * `fail` reports it as a failed job so the transport can retry or dead-letter it.
575
+ * @default 'ignore'
576
+ */
577
+ onUnhandled?: 'ignore' | 'fail';
578
+ /**
579
+ * How many processed jobs are kept for inspection.
580
+ * @default 50
581
+ */
582
+ maxEvents?: number;
583
+ /**
584
+ * Keep the payload and headers of failed attempts, so a failure can be
585
+ * diagnosed from the outside. Off by default, because those are user data:
586
+ * `@vercube/devtools` turns it on for the session it inspects.
587
+ * @default false
588
+ */
589
+ capturePayloads?: boolean;
590
+ /**
591
+ * Largest payload preview and stack trace kept, in bytes.
592
+ * @default 4096
593
+ */
594
+ maxPayloadBytes?: number;
595
+ }
596
+ /** Options accepted by the queue plugin. */
597
+ interface PluginOptions extends Defaults {
598
+ /** Strategies to mount when the application boots. */
599
+ strategies?: AnyMount[];
600
+ }
601
+ }
602
+ //#endregion
603
+ //#region src/Services/QueueStrategy.d.ts
604
+ /**
605
+ * Base class every queue transport implements.
606
+ *
607
+ * A strategy owns the connection to a broker and translates between the broker's
608
+ * own vocabulary and the module's job model. It stays deliberately thin: routing
609
+ * jobs to handlers, retries, timeouts and metrics all live in the
610
+ * {@link QueueManager}, so every transport behaves the same way.
611
+ *
612
+ * @typeParam InitOptions - Options the strategy needs to connect. Use `undefined`
613
+ * for strategies that need none.
614
+ *
615
+ * @example
616
+ * ```ts
617
+ * export class LogStrategy extends QueueStrategy {
618
+ * public readonly transport = 'log';
619
+ *
620
+ * public initialize(): void {}
621
+ *
622
+ * public async publish(request: QueueTypes.PublishRequest): Promise<QueueTypes.JobRef> {
623
+ * console.log(request.queue, request.job, request.payload);
624
+ * return { id: '1', queue: request.queue, job: request.job, strategy: this.transport };
625
+ * }
626
+ *
627
+ * public async consume(): Promise<QueueTypes.ConsumerHandle> {
628
+ * throw new Error('This strategy only publishes');
629
+ * }
630
+ *
631
+ * public async close(): Promise<void> {}
632
+ * }
633
+ * ```
634
+ */
635
+ declare abstract class QueueStrategy<InitOptions = undefined> {
636
+ /**
637
+ * Type-only marker carrying `InitOptions`, so `QueueTypes.Mount` can tell a
638
+ * strategy that needs options from one that does not. Declared, never assigned,
639
+ * and gone at runtime.
640
+ *
641
+ * @internal
642
+ */
643
+ readonly __initOptions: InitOptions;
644
+ /** Transport this strategy talks to, used in logs and in the devtools. */
645
+ abstract readonly transport: string;
646
+ /**
647
+ * What the transport can do on its own. Anything reported as unsupported is
648
+ * either emulated by the manager or ignored.
649
+ */
650
+ get capabilities(): QueueTypes.Capabilities;
651
+ /**
652
+ * Connects to the broker. Called once per mount, before the first publish or
653
+ * consume, and never called again unless the strategy is closed.
654
+ *
655
+ * @param options - Options the strategy was mounted with.
656
+ * @returns Resolves once the strategy is ready to be used.
657
+ * @throws {QueueError} When the connection cannot be established.
658
+ */
659
+ abstract initialize(options: InitOptions): MaybePromise<void>;
660
+ /**
661
+ * Publishes a single job.
662
+ *
663
+ * @param request - Job to publish, with its headers and options already resolved.
664
+ * @returns Reference to the published job.
665
+ * @throws {QueueError} When the job cannot be published.
666
+ */
667
+ abstract publish(request: QueueTypes.PublishRequest): Promise<QueueTypes.JobRef>;
668
+ /**
669
+ * Starts consuming a queue. The strategy calls `request.dispatch()` for every
670
+ * job it receives and applies its own failure semantics when the returned
671
+ * promise rejects.
672
+ *
673
+ * @param request - Queue to consume, its concurrency and the dispatch callback.
674
+ * @returns Handle used to stop the consumer again.
675
+ * @throws {QueueError} When the consumer cannot be started.
676
+ */
677
+ abstract consume(request: QueueTypes.ConsumeRequest): Promise<QueueTypes.ConsumerHandle>;
678
+ /**
679
+ * Closes every connection the strategy holds. Called on shutdown and safe to
680
+ * call more than once.
681
+ *
682
+ * @returns Resolves once everything is closed.
683
+ */
684
+ abstract close(): Promise<void>;
685
+ /**
686
+ * Publishes many jobs of the same kind. The default implementation publishes
687
+ * them one by one, transports with a batch API should override it.
688
+ *
689
+ * @param requests - Jobs to publish, all targeting the same queue.
690
+ * @returns References to the published jobs, in the same order.
691
+ * @throws {QueueError} When the jobs cannot be published.
692
+ */
693
+ publishMany(requests: QueueTypes.PublishRequest[]): Promise<QueueTypes.JobRef[]>;
694
+ /**
695
+ * Reads live counters of a queue, for transports that keep them.
696
+ *
697
+ * @param queue - Queue to read.
698
+ * @returns The counters the transport can report.
699
+ */
700
+ stats?(queue: string): Promise<QueueTypes.QueueStats>;
701
+ /**
702
+ * Shows what a queue is holding without consuming any of it.
703
+ *
704
+ * Only transports that can be read without side effects implement this: a
705
+ * broker where looking means taking delivery, such as RabbitMQ, leaves it out
706
+ * rather than perturbing the queue it is asked about.
707
+ *
708
+ * @param request - Queue to look at, how many messages to read and which states.
709
+ * @returns The messages found, in the order the transport returned them.
710
+ * @throws {QueueError} When the queue cannot be read.
711
+ */
712
+ peek?(request: QueueTypes.PeekRequest): Promise<QueueTypes.PeekedMessage[]>;
713
+ }
714
+ //#endregion
715
+ export { QueueTypes as n, QueueStrategy as t };