qwerk 0.1.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,744 @@
1
+ /**
2
+ * Job status
3
+ */
4
+ type JobStatus = "waiting" | "active" | "completed" | "failed" | "delayed" | "stalled";
5
+ /**
6
+ * Logger interface - implement this to use your own logger
7
+ */
8
+ interface Logger {
9
+ debug(message: string, ...args: unknown[]): void;
10
+ info(message: string, ...args: unknown[]): void;
11
+ warn(message: string, ...args: unknown[]): void;
12
+ error(message: string, ...args: unknown[]): void;
13
+ }
14
+ /**
15
+ * Default console logger
16
+ */
17
+ declare const consoleLogger: Logger;
18
+ /**
19
+ * Silent logger (no output)
20
+ */
21
+ declare const silentLogger: Logger;
22
+ /**
23
+ * Represents a job in the queue
24
+ */
25
+ interface Job<
26
+ T = unknown,
27
+ R = unknown
28
+ > {
29
+ readonly id: string;
30
+ readonly name: string;
31
+ readonly data: T;
32
+ readonly attempts: number;
33
+ readonly maxAttempts: number;
34
+ readonly createdAt: number;
35
+ readonly scheduledAt: number;
36
+ readonly backoff: BackoffOptions;
37
+ /** When the job started processing (set by pop) */
38
+ readonly startedAt?: number;
39
+ /** Job priority (lower = higher priority, default: 0) */
40
+ readonly priority: number;
41
+ /** Job timeout in ms (default: 30000) */
42
+ readonly timeout: number;
43
+ /** Repeat configuration for recurring jobs */
44
+ readonly repeat?: RepeatOptions;
45
+ /** Current progress (0-100) */
46
+ readonly progress?: number;
47
+ /** Job result (set after completion) */
48
+ readonly result?: R;
49
+ }
50
+ /**
51
+ * Options for creating a new job
52
+ */
53
+ interface JobOptions {
54
+ /** Maximum retry attempts (default: 3) */
55
+ maxAttempts?: number;
56
+ /** Delay before first execution in ms (default: 0) */
57
+ delay?: number;
58
+ /** Backoff strategy for retries */
59
+ backoff?: BackoffOptions;
60
+ /** Job priority - lower number = higher priority (default: 0) */
61
+ priority?: number;
62
+ /** Job timeout in ms - job fails if handler exceeds this (default: 30000) */
63
+ timeout?: number;
64
+ /** Unique job ID - if provided, prevents duplicate jobs with same ID */
65
+ jobId?: string;
66
+ /** Repeat configuration for recurring jobs */
67
+ repeat?: RepeatOptions;
68
+ }
69
+ /**
70
+ * Configuration for repeatable/recurring jobs
71
+ */
72
+ interface RepeatOptions {
73
+ /** Cron expression (e.g., "0 * * * *" for every hour) */
74
+ cron?: string;
75
+ /** Fixed interval in ms between job completions */
76
+ every?: number;
77
+ /** Maximum number of times to repeat (undefined = infinite) */
78
+ limit?: number;
79
+ /** Number of times this job has been repeated */
80
+ count?: number;
81
+ /** Unique key for this repeatable job (auto-generated if not provided) */
82
+ key?: string;
83
+ }
84
+ /**
85
+ * Backoff configuration for retries
86
+ */
87
+ interface BackoffOptions {
88
+ type: "exponential" | "linear" | "fixed";
89
+ /** Base delay in ms (default: 1000) */
90
+ delay: number;
91
+ /** Maximum delay in ms (default: 30000) */
92
+ maxDelay?: number;
93
+ }
94
+ /**
95
+ * Context passed to job handlers for progress updates and signals
96
+ */
97
+ interface JobContext {
98
+ /** Update job progress (0-100) */
99
+ updateProgress(progress: number): Promise<void>;
100
+ /** AbortSignal for cancellation */
101
+ signal: AbortSignal;
102
+ }
103
+ /**
104
+ * Backend interface - implement this for custom storage
105
+ */
106
+ interface Backend {
107
+ /**
108
+ * Add a job to the queue
109
+ * @returns false if job with same ID already exists (deduplication)
110
+ */
111
+ push(job: Job): Promise<boolean>;
112
+ /**
113
+ * Add multiple jobs to the queue (bulk operation)
114
+ * @returns number of jobs successfully added
115
+ */
116
+ pushBulk(jobs: Job[]): Promise<number>;
117
+ /**
118
+ * Get the next job ready for processing (atomic)
119
+ * Moves job to "active" state with visibility timeout
120
+ */
121
+ pop(visibilityTimeout: number): Promise<Job | null>;
122
+ /**
123
+ * Acknowledge successful job completion
124
+ * Removes job from active set and stores result
125
+ */
126
+ ack(jobId: string, result?: unknown): Promise<void>;
127
+ /**
128
+ * Negative acknowledge - reschedule job for retry
129
+ */
130
+ nack(job: Job, nextAttemptAt: number): Promise<void>;
131
+ /**
132
+ * Move a job to the dead letter queue
133
+ */
134
+ fail(job: Job, error: Error): Promise<void>;
135
+ /**
136
+ * Get stalled jobs (exceeded visibility timeout)
137
+ * These should be moved back to waiting or failed
138
+ */
139
+ getStalled(): Promise<Job[]>;
140
+ /**
141
+ * Update job progress (0-100)
142
+ */
143
+ updateProgress(jobId: string, progress: number): Promise<void>;
144
+ /**
145
+ * Get a completed job with its result
146
+ */
147
+ getCompleted(jobId: string): Promise<{
148
+ job: Job;
149
+ result: unknown;
150
+ completedAt: number;
151
+ } | null>;
152
+ /**
153
+ * Get completed jobs count
154
+ */
155
+ completedCount(): Promise<number>;
156
+ /**
157
+ * Get recent completed jobs
158
+ */
159
+ getCompletedJobs(limit?: number): Promise<Array<{
160
+ job: Job;
161
+ result: unknown;
162
+ completedAt: number;
163
+ }>>;
164
+ /**
165
+ * Subscribe to job notifications (for real-time processing)
166
+ */
167
+ subscribe(callback: () => void): void;
168
+ /**
169
+ * Unsubscribe from notifications
170
+ */
171
+ unsubscribe(): void;
172
+ /**
173
+ * Get queue size (pending jobs)
174
+ */
175
+ size(): Promise<number>;
176
+ /**
177
+ * Get count of active (processing) jobs
178
+ */
179
+ activeCount(): Promise<number>;
180
+ /**
181
+ * Get count of failed jobs in DLQ
182
+ */
183
+ failedCount(): Promise<number>;
184
+ /**
185
+ * Get failed jobs from DLQ
186
+ */
187
+ getFailed(limit?: number): Promise<Array<{
188
+ job: Job;
189
+ error: string;
190
+ failedAt: number;
191
+ }>>;
192
+ /**
193
+ * Retry a failed job (move from DLQ back to queue)
194
+ */
195
+ retryFailed(jobId: string): Promise<boolean>;
196
+ /**
197
+ * Remove a job by ID (from any state)
198
+ */
199
+ remove(jobId: string): Promise<boolean>;
200
+ /**
201
+ * Clear all jobs (waiting, active, failed)
202
+ */
203
+ clear(): Promise<void>;
204
+ /**
205
+ * Close/cleanup resources
206
+ */
207
+ close?(): Promise<void>;
208
+ }
209
+ /**
210
+ * Queue events
211
+ */
212
+ interface QueueEvents<
213
+ T = unknown,
214
+ R = unknown
215
+ > {
216
+ /** Job completed successfully */
217
+ completed: (job: Job<T, R>, result: R | undefined) => void;
218
+ /** Job failed after all retries (moved to DLQ) */
219
+ failed: (job: Job<T, R>, error: Error) => void;
220
+ /** Job failed, will retry */
221
+ retry: (job: Job<T, R>, error: Error) => void;
222
+ /** Job exceeded visibility timeout, will be reprocessed */
223
+ stalled: (job: Job<T, R>) => void;
224
+ /** Job timed out during processing */
225
+ timeout: (job: Job<T, R>) => void;
226
+ /** Job started processing */
227
+ active: (job: Job<T, R>) => void;
228
+ /** Job was added to the queue */
229
+ added: (job: Job<T, R>) => void;
230
+ /** Rate limit hit - job delayed */
231
+ rateLimited: (job: Job<T, R>) => void;
232
+ /** Job progress updated */
233
+ progress: (job: Job<T, R>, progress: number) => void;
234
+ }
235
+ /**
236
+ * Rate limiter configuration
237
+ */
238
+ interface RateLimitOptions {
239
+ /** Maximum number of jobs to process per interval */
240
+ max: number;
241
+ /** Time window in ms (default: 1000 = 1 second) */
242
+ duration?: number;
243
+ }
244
+ /**
245
+ * Queue options
246
+ */
247
+ interface QueueOptions {
248
+ /** Polling interval in ms when no jobs (default: 1000) */
249
+ pollInterval?: number;
250
+ /** Concurrency limit (default: 1) */
251
+ concurrency?: number;
252
+ /** Visibility timeout in ms - how long a job can be processing before considered stalled (default: 30000) */
253
+ visibilityTimeout?: number;
254
+ /** How often to check for stalled jobs in ms (default: 5000) */
255
+ stalledInterval?: number;
256
+ /** Rate limiting configuration */
257
+ rateLimit?: RateLimitOptions;
258
+ /** Custom logger (default: consoleLogger) */
259
+ logger?: Logger;
260
+ /** Maximum job payload size in bytes (default: unlimited) */
261
+ maxPayloadSize?: number;
262
+ /** Maximum queue size - rejects new jobs when exceeded (default: unlimited) */
263
+ maxQueueSize?: number;
264
+ }
265
+ /**
266
+ * Queue metrics snapshot
267
+ */
268
+ interface QueueMetrics {
269
+ /** Number of jobs waiting to be processed */
270
+ waiting: number;
271
+ /** Number of jobs currently being processed */
272
+ active: number;
273
+ /** Number of failed jobs in DLQ */
274
+ failed: number;
275
+ /** Total jobs completed since start */
276
+ completed: number;
277
+ /** Total jobs that failed (moved to DLQ) since start */
278
+ totalFailed: number;
279
+ /** Total job processing time in ms */
280
+ totalProcessingTime: number;
281
+ /** Average job processing time in ms */
282
+ avgProcessingTime: number;
283
+ /** Jobs processed per second (recent) */
284
+ throughput: number;
285
+ }
286
+ type EventCallback = (...args: unknown[]) => void;
287
+ /**
288
+ * Events emitted by a JobHandle
289
+ */
290
+ interface JobHandleEvents<
291
+ TData,
292
+ TResult
293
+ > {
294
+ completed: (job: Job<TData, TResult>, result: TResult | undefined) => void;
295
+ failed: (job: Job<TData, TResult>, error: Error) => void;
296
+ retry: (job: Job<TData, TResult>, error: Error) => void;
297
+ stalled: (job: Job<TData, TResult>) => void;
298
+ timeout: (job: Job<TData, TResult>) => void;
299
+ active: (job: Job<TData, TResult>) => void;
300
+ added: (job: Job<TData, TResult>) => void;
301
+ progress: (job: Job<TData, TResult>, progress: number) => void;
302
+ }
303
+ /**
304
+ * Options for defining a job type
305
+ */
306
+ interface JobDefineOptions {
307
+ maxAttempts?: number;
308
+ timeout?: number;
309
+ backoff?: BackoffOptions;
310
+ priority?: number;
311
+ }
312
+ /**
313
+ * Options when adding a job instance (overrides defaults)
314
+ */
315
+ interface JobAddOptions {
316
+ delay?: number;
317
+ priority?: number;
318
+ jobId?: string;
319
+ maxAttempts?: number;
320
+ timeout?: number;
321
+ backoff?: BackoffOptions;
322
+ repeat?: RepeatOptions;
323
+ }
324
+ /**
325
+ * Handler function for processing jobs
326
+ */
327
+ type JobHandleHandler<
328
+ TData,
329
+ TResult
330
+ > = (data: TData, ctx: JobContext) => Promise<TResult | void> | TResult | void;
331
+ /**
332
+ * Interface for queue operations needed by JobHandle
333
+ */
334
+ interface JobHandleQueue {
335
+ addJob(name: string, data: unknown, options: JobOptions): Promise<Job | null>;
336
+ addJobBulk(jobs: Array<{
337
+ name: string;
338
+ data: unknown;
339
+ options?: JobOptions;
340
+ }>): Promise<Job[]>;
341
+ processJob(name: string, handler: (job: Job, ctx: JobContext) => Promise<unknown>): void;
342
+ subscribeToEvent(event: string, name: string, callback: EventCallback): void;
343
+ unsubscribeFromEvent(event: string, name: string, callback: EventCallback): void;
344
+ }
345
+ /**
346
+ * A typed handle for a specific job type.
347
+ * Provides type-safe methods for adding and processing jobs.
348
+ */
349
+ declare class JobHandle<
350
+ TData = unknown,
351
+ TResult = void
352
+ > {
353
+ private readonly queue;
354
+ readonly name: string;
355
+ private readonly defaults;
356
+ private events;
357
+ private onceEvents;
358
+ private handler;
359
+ constructor(queue: JobHandleQueue, name: string, defaults?: JobDefineOptions);
360
+ /**
361
+ * Register a handler for this job type
362
+ */
363
+ process(handler: JobHandleHandler<TData, TResult>): this;
364
+ /**
365
+ * Add a job to the queue
366
+ */
367
+ add(data: TData, options?: JobAddOptions): Promise<Job<TData, TResult> | null>;
368
+ /**
369
+ * Add multiple jobs to the queue
370
+ */
371
+ addBulk(items: Array<{
372
+ data: TData;
373
+ options?: JobAddOptions;
374
+ }>): Promise<Job<TData, TResult>[]>;
375
+ /**
376
+ * Subscribe to events for this job type
377
+ */
378
+ on<K extends keyof JobHandleEvents<TData, TResult>>(event: K, callback: JobHandleEvents<TData, TResult>[K]): this;
379
+ /**
380
+ * Subscribe to a single occurrence of an event
381
+ */
382
+ once<K extends keyof JobHandleEvents<TData, TResult>>(event: K, callback: JobHandleEvents<TData, TResult>[K]): this;
383
+ /**
384
+ * Unsubscribe from events
385
+ */
386
+ off<K extends keyof JobHandleEvents<TData, TResult>>(event: K, callback: JobHandleEvents<TData, TResult>[K]): this;
387
+ }
388
+ type EventCallback2 = (...args: unknown[]) => void;
389
+ /**
390
+ * Type-safe job queue with pluggable backends
391
+ */
392
+ declare class Queue implements JobHandleQueue {
393
+ private backend;
394
+ private handlers;
395
+ private events;
396
+ private onceEvents;
397
+ private jobEvents;
398
+ private running;
399
+ private processing;
400
+ private pollInterval;
401
+ private concurrency;
402
+ private visibilityTimeout;
403
+ private stalledInterval;
404
+ private pollTimer;
405
+ private stalledTimer;
406
+ private activeJobs;
407
+ private shuttingDown;
408
+ private shutdownResolve;
409
+ private rateLimit;
410
+ private rateLimitTokens;
411
+ private rateLimitLastRefill;
412
+ private logger;
413
+ private maxPayloadSize;
414
+ private maxQueueSize;
415
+ private metricsData;
416
+ constructor(backend: Backend, options?: QueueOptions);
417
+ /**
418
+ * Add a job to the queue (internal)
419
+ * @internal
420
+ */
421
+ private add;
422
+ /**
423
+ * Add multiple jobs to the queue (internal)
424
+ * @internal
425
+ */
426
+ private addBulk;
427
+ /**
428
+ * Define a new job type and return a typed handle for it.
429
+ * The handle provides type-safe methods for adding and processing jobs.
430
+ *
431
+ * @example
432
+ * const sendEmail = queue.define<{ to: string; subject: string }>("send-email", {
433
+ * maxAttempts: 5,
434
+ * timeout: 60_000,
435
+ * });
436
+ *
437
+ * sendEmail.process(async (data, ctx) => {
438
+ * await mail(data.to, data.subject);
439
+ * });
440
+ *
441
+ * await sendEmail.add({ to: "test@example.com", subject: "Hello" });
442
+ */
443
+ define<
444
+ TData,
445
+ TResult = void
446
+ >(name: string, defaults?: JobDefineOptions): JobHandle<TData, TResult>;
447
+ /** @internal */
448
+ addJob(name: string, data: unknown, options: JobOptions): Promise<Job | null>;
449
+ /** @internal */
450
+ addJobBulk(jobs: Array<{
451
+ name: string;
452
+ data: unknown;
453
+ options?: JobOptions;
454
+ }>): Promise<Job[]>;
455
+ /** @internal */
456
+ processJob(name: string, handler: (job: Job, ctx: JobContext) => Promise<unknown>): void;
457
+ /** @internal */
458
+ subscribeToEvent(event: string, name: string, callback: EventCallback2): void;
459
+ /** @internal */
460
+ unsubscribeFromEvent(event: string, name: string, callback: EventCallback2): void;
461
+ /**
462
+ * Start processing jobs
463
+ */
464
+ start(): void;
465
+ /**
466
+ * Stop processing jobs gracefully
467
+ * @param timeout Max time to wait for in-flight jobs (default: 30000ms)
468
+ * @returns Promise that resolves when all jobs complete or timeout
469
+ */
470
+ stop(timeout?: number): Promise<void>;
471
+ /**
472
+ * Pause processing (finish current jobs but don't pick up new ones)
473
+ */
474
+ pause(): void;
475
+ /**
476
+ * Resume processing after pause
477
+ */
478
+ resume(): void;
479
+ /**
480
+ * Wait for all current jobs to complete
481
+ */
482
+ drain(): Promise<void>;
483
+ /**
484
+ * Subscribe to queue events
485
+ */
486
+ on<K extends keyof QueueEvents>(event: K, callback: QueueEvents[K]): this;
487
+ /**
488
+ * Subscribe to a single occurrence of an event
489
+ */
490
+ once<K extends keyof QueueEvents>(event: K, callback: QueueEvents[K]): this;
491
+ /**
492
+ * Unsubscribe from queue events
493
+ */
494
+ off<K extends keyof QueueEvents>(event: K, callback: QueueEvents[K]): this;
495
+ /**
496
+ * Get current queue size (waiting jobs)
497
+ */
498
+ size(): Promise<number>;
499
+ /**
500
+ * Get count of active (processing) jobs
501
+ */
502
+ activeCount(): Promise<number>;
503
+ /**
504
+ * Get count of failed jobs
505
+ */
506
+ failedCount(): Promise<number>;
507
+ /**
508
+ * Get failed jobs
509
+ */
510
+ getFailed(limit?: number): Promise<Array<{
511
+ job: Job;
512
+ error: string;
513
+ failedAt: number;
514
+ }>>;
515
+ /**
516
+ * Get a completed job with its result
517
+ */
518
+ getCompleted(jobId: string): Promise<{
519
+ job: Job;
520
+ result: unknown;
521
+ completedAt: number;
522
+ } | null>;
523
+ /**
524
+ * Get count of completed jobs (with stored results)
525
+ */
526
+ completedCount(): Promise<number>;
527
+ /**
528
+ * Get recent completed jobs with results
529
+ */
530
+ getCompletedJobs(limit?: number): Promise<Array<{
531
+ job: Job;
532
+ result: unknown;
533
+ completedAt: number;
534
+ }>>;
535
+ /**
536
+ * Retry a failed job
537
+ */
538
+ retryFailed(jobId: string): Promise<boolean>;
539
+ /**
540
+ * Remove a job by ID
541
+ */
542
+ remove(jobId: string): Promise<boolean>;
543
+ /**
544
+ * Clear all jobs
545
+ */
546
+ clear(): Promise<void>;
547
+ /**
548
+ * Close the queue and backend
549
+ */
550
+ close(): Promise<void>;
551
+ /**
552
+ * Get queue metrics
553
+ */
554
+ getMetrics(): Promise<QueueMetrics>;
555
+ private startStalledChecker;
556
+ private checkStalled;
557
+ private checkRateLimit;
558
+ private tick;
559
+ private executeJob;
560
+ private scheduleNextRepeat;
561
+ private emit;
562
+ }
563
+ /**
564
+ * In-memory backend - single process, no persistence
565
+ * Good for development, testing, or simple use cases
566
+ * Uses a min-heap for O(log n) job retrieval by priority
567
+ */
568
+ declare class MemoryBackend implements Backend {
569
+ /** Waiting jobs heap (sorted by priority, then scheduledAt) */
570
+ private waitingHeap;
571
+ /** Waiting jobs map for O(1) lookup by ID */
572
+ private waiting;
573
+ /** Active jobs being processed */
574
+ private active;
575
+ /** Failed jobs (dead letter queue) */
576
+ private failed;
577
+ /** Completed jobs with results */
578
+ private completed;
579
+ /** All job IDs for deduplication */
580
+ private allIds;
581
+ /** Job progress */
582
+ private progress;
583
+ private listener;
584
+ push(job: Job): Promise<boolean>;
585
+ pushBulk(jobs: Job[]): Promise<number>;
586
+ pop(visibilityTimeout: number): Promise<Job | null>;
587
+ ack(jobId: string, result?: unknown): Promise<void>;
588
+ nack(job: Job, nextAttemptAt: number): Promise<void>;
589
+ fail(job: Job, error: Error): Promise<void>;
590
+ getStalled(): Promise<Job[]>;
591
+ updateProgress(jobId: string, progress: number): Promise<void>;
592
+ getCompleted(jobId: string): Promise<{
593
+ job: Job;
594
+ result: unknown;
595
+ completedAt: number;
596
+ } | null>;
597
+ completedCount(): Promise<number>;
598
+ getCompletedJobs(limit?: number): Promise<Array<{
599
+ job: Job;
600
+ result: unknown;
601
+ completedAt: number;
602
+ }>>;
603
+ subscribe(callback: () => void): void;
604
+ unsubscribe(): void;
605
+ size(): Promise<number>;
606
+ activeCount(): Promise<number>;
607
+ failedCount(): Promise<number>;
608
+ getFailed(limit?: number): Promise<Array<{
609
+ job: Job;
610
+ error: string;
611
+ failedAt: number;
612
+ }>>;
613
+ retryFailed(jobId: string): Promise<boolean>;
614
+ remove(jobId: string): Promise<boolean>;
615
+ clear(): Promise<void>;
616
+ close(): Promise<void>;
617
+ private notify;
618
+ }
619
+ /**
620
+ * BroadcastChannel backend - cross-tab/worker communication
621
+ *
622
+ * Uses BroadcastChannel API for real-time sync between:
623
+ * - Browser tabs (same origin)
624
+ * - Web Workers
625
+ * - Bun/Node worker threads
626
+ *
627
+ * Uses distributed claim protocol to prevent duplicate job processing.
628
+ */
629
+ declare class BroadcastBackend implements Backend {
630
+ private waiting;
631
+ private active;
632
+ private failed;
633
+ private completed;
634
+ private allIds;
635
+ private progress;
636
+ private channel;
637
+ private listener;
638
+ private isLeader;
639
+ private leaderTimeout;
640
+ private instanceId;
641
+ private pendingClaims;
642
+ constructor(channelName?: string);
643
+ private electLeader;
644
+ private handleMessage;
645
+ push(job: Job): Promise<boolean>;
646
+ pushBulk(jobs: Job[]): Promise<number>;
647
+ pop(visibilityTimeout: number): Promise<Job | null>;
648
+ private tryClaim;
649
+ ack(jobId: string, result?: unknown): Promise<void>;
650
+ nack(job: Job, nextAttemptAt: number): Promise<void>;
651
+ fail(job: Job, error: Error): Promise<void>;
652
+ getStalled(): Promise<Job[]>;
653
+ updateProgress(jobId: string, progress: number): Promise<void>;
654
+ getCompleted(jobId: string): Promise<{
655
+ job: Job;
656
+ result: unknown;
657
+ completedAt: number;
658
+ } | null>;
659
+ completedCount(): Promise<number>;
660
+ getCompletedJobs(limit?: number): Promise<Array<{
661
+ job: Job;
662
+ result: unknown;
663
+ completedAt: number;
664
+ }>>;
665
+ subscribe(callback: () => void): void;
666
+ unsubscribe(): void;
667
+ size(): Promise<number>;
668
+ activeCount(): Promise<number>;
669
+ failedCount(): Promise<number>;
670
+ getFailed(limit?: number): Promise<Array<{
671
+ job: Job;
672
+ error: string;
673
+ failedAt: number;
674
+ }>>;
675
+ retryFailed(jobId: string): Promise<boolean>;
676
+ remove(jobId: string): Promise<boolean>;
677
+ clear(): Promise<void>;
678
+ close(): Promise<void>;
679
+ private notify;
680
+ }
681
+ type RedisClient = InstanceType<typeof Bun.RedisClient>;
682
+ /**
683
+ * Redis backend options
684
+ */
685
+ interface RedisBackendOptions {
686
+ /** Key prefix for all queue data (default: "qwerk") */
687
+ prefix?: string;
688
+ /** Separate client for pub/sub subscriptions (optional, will create one if not provided) */
689
+ subscriber?: RedisClient;
690
+ }
691
+ /**
692
+ * Redis backend - distributed, persistent job queue
693
+ *
694
+ * Uses atomic Lua scripts for safe concurrent access.
695
+ * Requires Bun's built-in Redis client.
696
+ */
697
+ declare class RedisBackend implements Backend {
698
+ private client;
699
+ private subscriber;
700
+ private prefix;
701
+ private listener;
702
+ private ownsSubscriber;
703
+ private url;
704
+ constructor(url: string, options?: RedisBackendOptions);
705
+ private key;
706
+ /**
707
+ * Execute a Lua script via EVAL command
708
+ */
709
+ private evalScript;
710
+ push(job: Job): Promise<boolean>;
711
+ pushBulk(jobs: Job[]): Promise<number>;
712
+ pop(visibilityTimeout: number): Promise<Job | null>;
713
+ ack(jobId: string, result?: unknown): Promise<void>;
714
+ nack(job: Job, nextAttemptAt: number): Promise<void>;
715
+ fail(job: Job, error: Error): Promise<void>;
716
+ getStalled(): Promise<Job[]>;
717
+ updateProgress(jobId: string, progress: number): Promise<void>;
718
+ getCompleted(jobId: string): Promise<{
719
+ job: Job;
720
+ result: unknown;
721
+ completedAt: number;
722
+ } | null>;
723
+ completedCount(): Promise<number>;
724
+ getCompletedJobs(limit?: number): Promise<Array<{
725
+ job: Job;
726
+ result: unknown;
727
+ completedAt: number;
728
+ }>>;
729
+ subscribe(callback: () => void): void;
730
+ unsubscribe(): void;
731
+ size(): Promise<number>;
732
+ activeCount(): Promise<number>;
733
+ failedCount(): Promise<number>;
734
+ getFailed(limit?: number): Promise<Array<{
735
+ job: Job;
736
+ error: string;
737
+ failedAt: number;
738
+ }>>;
739
+ retryFailed(jobId: string): Promise<boolean>;
740
+ remove(jobId: string): Promise<boolean>;
741
+ clear(): Promise<void>;
742
+ close(): Promise<void>;
743
+ }
744
+ export { silentLogger, consoleLogger, RepeatOptions, RedisBackendOptions, RedisBackend, RateLimitOptions, QueueOptions, QueueMetrics, QueueEvents, Queue, MemoryBackend, Logger, JobStatus, JobOptions, JobHandleHandler, JobHandleEvents, JobHandle, JobDefineOptions, JobContext, JobAddOptions, Job, BroadcastBackend, BackoffOptions, Backend };