rabbitmq-with-retry-and-dlq 1.0.23 → 1.0.25

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.
package/README.md CHANGED
@@ -20,6 +20,48 @@ npm install rabbitmq-with-retry-and-dlq
20
20
 
21
21
  ---
22
22
 
23
+ ## Quick Start (Best Practice)
24
+
25
+ ```typescript
26
+ import {
27
+ initializeRabbitMQ,
28
+ publisher,
29
+ consumer,
30
+ } from 'rabbitmq-with-retry-and-dlq';
31
+
32
+ // 1. Initialize connection
33
+ await initializeRabbitMQ('amqp://localhost:5672');
34
+
35
+ // 2. Publisher: Assert exchange
36
+ await publisher.assertExchange('orders', { exchangeType: 'topic' });
37
+
38
+ // 3. Consumer: Setup queue with exchange and routing keys
39
+ await consumer.setupQueue({
40
+ queueName: 'orders-processor',
41
+ exchangeName: 'orders',
42
+ exchangeType: 'topic',
43
+ routingKeys: ['order.created', 'order.updated'],
44
+ retryConfig: { maxRetries: 5, retryDelayMs: 2000 },
45
+ });
46
+
47
+ // 4. Consumer: Start consuming
48
+ await consumer.consumeQueue({
49
+ queueName: 'orders-processor',
50
+ onMessage: async (message) => {
51
+ await processOrder(message);
52
+ },
53
+ });
54
+
55
+ // 5. Publisher: Publish messages
56
+ await publisher.publishToExchange({
57
+ exchangeName: 'orders',
58
+ routingKey: 'order.created',
59
+ message: { orderId: 123 },
60
+ });
61
+ ```
62
+
63
+ ---
64
+
23
65
  ## Usage
24
66
 
25
67
  ### 1. Initialize (Required - Call Once with Await)
@@ -27,7 +69,11 @@ npm install rabbitmq-with-retry-and-dlq
27
69
  **You must call `await initializeRabbitMQ()` once** in your application setup or helper file:
28
70
 
29
71
  ```typescript
30
- import { initializeRabbitMQ, isPublisherConnected, isConsumerConnected } from 'rabbitmq-with-retry-and-dlq';
72
+ import {
73
+ initializeRabbitMQ,
74
+ isPublisherConnected,
75
+ isConsumerConnected,
76
+ } from 'rabbitmq-with-retry-and-dlq';
31
77
 
32
78
  try {
33
79
  // Call once at application startup (in your helper/setup file)
@@ -36,7 +82,7 @@ try {
36
82
 
37
83
  // Check connection status (both should be true after await)
38
84
  console.log('Publisher connected:', isPublisherConnected()); // true
39
- console.log('Consumer connected:', isConsumerConnected()); // true
85
+ console.log('Consumer connected:', isConsumerConnected()); // true
40
86
  } catch (error) {
41
87
  // Connection failed (wrong URL, RabbitMQ not running, timeout, etc.)
42
88
  console.error('Failed to connect to RabbitMQ:', error);
@@ -45,6 +91,7 @@ try {
45
91
  ```
46
92
 
47
93
  **Error Handling:**
94
+
48
95
  - Throws error if URL is wrong
49
96
  - Throws error if RabbitMQ is not running
50
97
  - Throws error if connection timeout (default: 30 seconds)
@@ -61,7 +108,7 @@ import { publisher, consumer } from 'rabbitmq-with-retry-and-dlq';
61
108
  // First call automatically establishes connection
62
109
  await publisher.publishToQueue({
63
110
  queueName: 'orders',
64
- message: { orderId: 123 }
111
+ message: { orderId: 123 },
65
112
  });
66
113
  ```
67
114
 
@@ -75,6 +122,7 @@ This library follows the RabbitMQ best practice pattern:
75
122
  - **Consumer** → Owns **Queues** and **Bindings** (decides what to subscribe to)
76
123
 
77
124
  This is cleaner because:
125
+
78
126
  1. Publishers don't need to know about queues
79
127
  2. Consumers can create their own queues and choose their bindings
80
128
  3. Multiple consumers can bind differently to the same exchange
@@ -95,8 +143,8 @@ await publisher.assertExchange(['orders', 'payments', 'notifications']);
95
143
 
96
144
  // With options
97
145
  await publisher.assertExchange('orders', {
98
- exchangeType: 'direct', // 'direct' | 'topic' | 'fanout' | 'headers' (default: 'direct')
99
- durable: true, // Survives broker restart (default: true)
146
+ exchangeType: 'direct', // 'direct' | 'topic' | 'fanout' | 'headers' (default: 'direct')
147
+ durable: true, // Survives broker restart (default: true)
100
148
  });
101
149
  ```
102
150
 
@@ -111,12 +159,52 @@ await consumer.assertExchange('orders', { exchangeType: 'topic' });
111
159
  await consumer.assertExchange('payments', { exchangeType: 'direct' });
112
160
 
113
161
  // Or assert multiple exchanges at once
114
- await consumer.assertExchange(['orders', 'payments'], { exchangeType: 'direct' });
162
+ await consumer.assertExchange(['orders', 'payments'], {
163
+ exchangeType: 'direct',
164
+ });
115
165
  ```
116
166
 
117
167
  > **Why?** Publisher and consumer use separate connections. Even if publisher creates the exchange, the consumer's connection might not see it immediately. Asserting exchanges on the consumer's connection ensures they exist before binding.
118
168
 
119
- ### Consumer: Assert Queues
169
+ ### Consumer: Setup Queue (RECOMMENDED - Best Practice)
170
+
171
+ **Use `setupQueue()` for complete setup in one atomic operation** - prevents race conditions and supports multiple routing keys:
172
+
173
+ ```typescript
174
+ // ✅ RECOMMENDED: Complete setup in one call
175
+ await consumer.setupQueue({
176
+ queueName: 'orders-processor',
177
+ exchangeName: 'orders',
178
+ exchangeType: 'topic',
179
+ routingKeys: ['order.created', 'order.updated', 'order.cancelled'], // Multiple routing keys!
180
+ retryConfig: {
181
+ maxRetries: 5,
182
+ retryDelayMs: 2000,
183
+ backoffStrategy: 'exponential',
184
+ jitterMs: 1000,
185
+ },
186
+ });
187
+
188
+ // Then consume (queue already set up)
189
+ await consumer.consumeQueue({
190
+ queueName: 'orders-processor',
191
+ onMessage: async (message) => {
192
+ console.log('Processing order:', message);
193
+ await processOrder(message);
194
+ },
195
+ });
196
+ ```
197
+
198
+ **What `setupQueue()` does:**
199
+
200
+ 1. ✅ Asserts exchange
201
+ 2. ✅ Creates queue with retry/DLQ infrastructure
202
+ 3. ✅ Binds queue to exchange with all routing keys
203
+ 4. ✅ All in ONE atomic operation (no race conditions)
204
+
205
+ ### Consumer: Assert Queues (Alternative - More Control)
206
+
207
+ Use `assertQueues()` when you need more control or want to add bindings dynamically:
120
208
 
121
209
  ```typescript
122
210
  // Assert a single queue
@@ -125,9 +213,11 @@ await consumer.assertQueues('orders-worker');
125
213
  // Assert multiple queues
126
214
  await consumer.assertQueues(['orders-worker', 'payments-worker']);
127
215
 
128
- // Assert queue with retry/DLQ configuration
216
+ // Assert queue with exchange binding and retry/DLQ configuration
129
217
  await consumer.assertQueues('orders-worker', {
130
- durable: true, // Queue survives restart (default: true)
218
+ exchangeName: 'orders',
219
+ exchangeType: 'direct',
220
+ routingKey: 'order.created', // Single routing key
131
221
  retryConfig: {
132
222
  maxRetries: 5,
133
223
  retryDelayMs: 2000,
@@ -136,27 +226,34 @@ await consumer.assertQueues('orders-worker', {
136
226
  });
137
227
  ```
138
228
 
139
- ### Consumer: Bind Queue to Exchange
229
+ ### Consumer: Bind Queue to Exchange (For Additional Bindings)
230
+
231
+ Use `bindQueue()` to add more routing key bindings after initial setup:
140
232
 
141
233
  ```typescript
142
234
  // IMPORTANT: Call consumer.assertExchange() FIRST to prevent race conditions!
143
235
 
144
236
  // Bind queue to exchange with routing key
145
- await consumer.bindQueue('orders-worker', 'orders', 'order.created');
237
+ await consumer.bindQueue('orders-worker', 'orders', 'order.created', {
238
+ exchangeType: 'topic', // Ensures exchange exists (recommended)
239
+ });
146
240
 
147
241
  // Bind with pattern (for topic exchanges)
148
- await consumer.bindQueue('all-orders', 'events', 'order.*');
242
+ await consumer.bindQueue('all-orders', 'events', 'order.*', {
243
+ exchangeType: 'topic',
244
+ });
149
245
 
150
- // Multiple bindings to same queue
246
+ // Add multiple bindings to same queue
151
247
  await consumer.bindQueue('orders-worker', 'orders', 'order.created');
152
248
  await consumer.bindQueue('orders-worker', 'orders', 'order.updated');
249
+ await consumer.bindQueue('orders-worker', 'orders', 'order.cancelled');
153
250
  ```
154
251
 
155
- ### Complete Best Practice Example
252
+ ### Complete Best Practice Example (RECOMMENDED)
156
253
 
157
254
  ```typescript
158
255
  // === PUBLISHER SIDE ===
159
- // Publisher only creates exchanges (doesn't know about queues)
256
+ // Publisher only knows about exchanges
160
257
  await publisher.assertExchange('orders', { exchangeType: 'topic' });
161
258
 
162
259
  await publisher.publishToExchange({
@@ -166,66 +263,66 @@ await publisher.publishToExchange({
166
263
  });
167
264
 
168
265
  // === CONSUMER SIDE ===
169
- // Step 1: Assert exchanges on consumer's connection (PREVENTS RACE CONDITIONS!)
170
- await consumer.assertExchange('orders', { exchangeType: 'topic' });
171
-
172
- // Step 2: Create queues with retry/DLQ config
173
- await consumer.assertQueues('orders-processor', {
174
- retryConfig: { maxRetries: 3, retryDelayMs: 5000 }
266
+ // Step 1: Setup queue with exchange and multiple routing keys (RECOMMENDED)
267
+ await consumer.setupQueue({
268
+ queueName: 'orders-processor',
269
+ exchangeName: 'orders',
270
+ exchangeType: 'topic',
271
+ routingKeys: ['order.created', 'order.updated'], // Multiple keys!
272
+ retryConfig: { maxRetries: 3, retryDelayMs: 5000 },
175
273
  });
176
274
 
177
- // Step 3: Bind queues to exchanges
178
- await consumer.bindQueue('orders-processor', 'orders', 'order.created');
179
- await consumer.bindQueue('orders-processor', 'orders', 'order.updated');
180
-
181
- // Step 4: Start consuming
275
+ // Step 2: Start consuming (queue already set up)
182
276
  await consumer.consumeQueue({
183
277
  queueName: 'orders-processor',
184
278
  onMessage: async (message) => {
185
279
  console.log('Processing order:', message);
280
+ await processOrder(message);
186
281
  },
187
282
  });
188
283
  ```
189
284
 
190
- ---
191
-
192
- ## Alternative: Publisher-Managed Queues
193
-
194
- For simpler use cases, the publisher can also manage queues (backward compatible):
195
-
196
- ### 3. Assert Queues (with Retry Config)
285
+ ### Alternative: Step-by-Step Setup
197
286
 
198
- **Note:** `assertQueues()` is **idempotent** - it safely skips queues that already exist. You can call it multiple times without errors.
287
+ If you need more granular control, use separate methods:
199
288
 
200
289
  ```typescript
201
- await publisher.assertQueues('orders', {
202
- durable: true, // Queue survives restart (default: true)
203
- retryConfig: {
204
- maxRetries: 5, // Required
205
- retryDelayMs: 2000, // Base delay (default: 5000ms)
206
- backoffStrategy: 'exponential', // 'exponential' or 'linear' (default: exponential)
207
- maxDelayMs: 300000, // Max delay cap (default: 300000 = 5min)
208
- jitterMs: 1000, // Random jitter 0-1000ms (default: 0)
209
- },
290
+ // Step 1: Assert exchanges on consumer's connection (defensive)
291
+ await consumer.assertExchange('orders', { exchangeType: 'topic' });
292
+
293
+ // Step 2: Create queues with retry/DLQ config
294
+ await consumer.assertQueues('orders-processor', {
295
+ retryConfig: { maxRetries: 3, retryDelayMs: 5000 },
210
296
  });
211
297
 
212
- // Assert multiple queues
213
- await publisher.assertQueues(['orders', 'payments', 'notifications'], {
214
- retryConfig: { maxRetries: 3 }
298
+ // Step 3: Bind queues to exchanges (can add multiple routing keys)
299
+ await consumer.bindQueue('orders-processor', 'orders', 'order.created', {
300
+ exchangeType: 'topic',
301
+ });
302
+ await consumer.bindQueue('orders-processor', 'orders', 'order.updated', {
303
+ exchangeType: 'topic',
215
304
  });
216
305
 
217
- // With exchange
218
- await publisher.assertQueues('order_processing', {
219
- exchangeName: 'orders_exchange',
220
- exchangeType: 'direct', // 'direct' | 'topic' | 'fanout' | 'headers'
221
- routingKey: 'order.created',
222
- retryConfig: { maxRetries: 3 },
306
+ // Step 4: Start consuming
307
+ await consumer.consumeQueue({
308
+ queueName: 'orders-processor',
309
+ onMessage: async (message) => {
310
+ await processOrder(message);
311
+ },
223
312
  });
224
313
  ```
225
314
 
226
- ### 4. Publish to Queue
315
+ ---
316
+
317
+ ## Direct Queue Publishing (Without Exchange)
318
+
319
+ For simple point-to-point messaging without exchanges:
320
+
321
+ ### Publish to Queue
227
322
 
228
323
  ```typescript
324
+ // Note: Queue should be set up by consumer first using assertQueues() or setupQueue()
325
+
229
326
  await publisher.publishToQueue({
230
327
  queueName: 'orders',
231
328
  message: {
@@ -233,14 +330,19 @@ await publisher.publishToQueue({
233
330
  amount: 99.99,
234
331
  },
235
332
  options: {
236
- persistent: true, // Survives broker restart (default: true)
237
- priority: 5, // 0-10 priority (optional)
238
- expiration: '5000' // TTL in ms (optional)
333
+ persistent: true, // Survives broker restart (default: true)
334
+ priority: 5, // 0-10 priority (optional)
335
+ expiration: '5000', // TTL in ms (optional)
336
+ },
337
+ // Optional: retryConfig if queue wasn't set up with retry
338
+ retryConfig: {
339
+ maxRetries: 5,
340
+ retryDelayMs: 2000,
239
341
  },
240
342
  });
241
343
  ```
242
344
 
243
- ### 5. Publish to Exchange
345
+ ### Publish to Exchange
244
346
 
245
347
  ```typescript
246
348
  // Publisher only needs exchange and routing key (not queue!)
@@ -256,10 +358,10 @@ await publisher.publishToExchange({
256
358
  });
257
359
  ```
258
360
 
259
- ### 6. Consumer
361
+ ### Consumer (Best Practice)
260
362
 
261
363
  ```typescript
262
- // Set up error handler
364
+ // Set up error handler FIRST
263
365
  consumer.on('error', (errorEvent) => {
264
366
  console.error('RabbitMQ Error:', errorEvent);
265
367
  if (errorEvent.type === 'DLQ_FAILED') {
@@ -267,31 +369,34 @@ consumer.on('error', (errorEvent) => {
267
369
  }
268
370
  });
269
371
 
270
- // Consume messages
372
+ // Step 1: Setup queue with exchange and routing keys
373
+ await consumer.setupQueue({
374
+ queueName: 'orders-processor',
375
+ exchangeName: 'orders_exchange',
376
+ exchangeType: 'direct',
377
+ routingKeys: ['order.created', 'order.updated'],
378
+ retryConfig: {
379
+ maxRetries: 5,
380
+ retryDelayMs: 2000,
381
+ backoffStrategy: 'exponential',
382
+ },
383
+ });
384
+
385
+ // Step 2: Start consuming (queue already set up)
271
386
  await consumer.consumeQueue({
272
- queueName: 'orders',
387
+ queueName: 'orders-processor',
273
388
  onMessage: async (message, messageInfo) => {
274
389
  console.log('Processing:', message);
275
-
390
+
276
391
  // Your business logic
277
392
  await processOrder(message);
278
-
393
+
279
394
  // Success = auto-ack
280
- // Throw error = retry with backoff
395
+ // Throw error = retry with backoff → DLQ
281
396
  },
282
397
  options: {
283
- prefetch: 5, // Max unacked messages (default: 5)
284
- noAck: false, // Auto-ack (default: false)
285
- },
286
- });
287
-
288
- // Consume from exchange
289
- await consumer.consumeQueue({
290
- queueName: 'order_processing',
291
- exchangeName: 'orders_exchange',
292
- routingKey: 'order.created',
293
- onMessage: async (message) => {
294
- await processOrder(message);
398
+ prefetch: 5, // Max unacked messages (default: 5)
399
+ noAck: false, // Auto-ack (default: false)
295
400
  },
296
401
  });
297
402
  ```
@@ -319,11 +424,11 @@ process.on('SIGINT', shutdown);
319
424
 
320
425
  ```typescript
321
426
  interface RetryConfig {
322
- maxRetries: number; // Required: max retry attempts
323
- retryDelayMs?: number; // Optional: base delay in ms (default: 5000)
324
- backoffStrategy?: string; // Optional: 'exponential' | 'linear' (default: 'exponential')
325
- maxDelayMs?: number; // Optional: max delay cap (default: 300000)
326
- jitterMs?: number; // Optional: random jitter range (default: 0)
427
+ maxRetries: number; // Required: max retry attempts
428
+ retryDelayMs?: number; // Optional: base delay in ms (default: 5000)
429
+ backoffStrategy?: string; // Optional: 'exponential' | 'linear' (default: 'exponential')
430
+ maxDelayMs?: number; // Optional: max delay cap (default: 300000)
431
+ jitterMs?: number; // Optional: random jitter range (default: 0)
327
432
  }
328
433
  ```
329
434
 
@@ -387,9 +492,9 @@ async function startApp() {
387
492
  // 1. Initialize RabbitMQ connection (required - use await)
388
493
  console.log('Connecting to RabbitMQ...');
389
494
  await initializeRabbitMQ('amqp://user:pass@localhost:5672');
390
-
495
+
391
496
  console.log('✓ Publisher connected:', isPublisherConnected()); // true
392
- console.log('✓ Consumer connected:', isConsumerConnected()); // true
497
+ console.log('✓ Consumer connected:', isConsumerConnected()); // true
393
498
 
394
499
  // 2. Set up error handler
395
500
  consumer.on('error', (errorEvent: RabbitMQErrorEvent) => {
@@ -400,12 +505,12 @@ async function startApp() {
400
505
  await publisher.assertExchange('orders', { exchangeType: 'topic' });
401
506
  console.log('✓ Publisher exchange asserted');
402
507
 
403
- // 4. Consumer: Assert exchange on consumer's connection (PREVENTS RACE CONDITIONS!)
404
- await consumer.assertExchange('orders', { exchangeType: 'topic' });
405
- console.log('✓ Consumer exchange asserted');
406
-
407
- // 5. Consumer: Assert queues with retry config (consumer owns queues)
408
- await consumer.assertQueues('orders-processor', {
508
+ // 4. Consumer: Setup queue with exchange and routing keys (RECOMMENDED)
509
+ await consumer.setupQueue({
510
+ queueName: 'orders-processor',
511
+ exchangeName: 'orders',
512
+ exchangeType: 'topic',
513
+ routingKeys: ['order.created', 'order.updated'],
409
514
  retryConfig: {
410
515
  maxRetries: 5,
411
516
  retryDelayMs: 2000,
@@ -413,14 +518,9 @@ async function startApp() {
413
518
  jitterMs: 1000,
414
519
  },
415
520
  });
416
- console.log('✓ Queues asserted');
417
-
418
- // 6. Consumer: Bind queue to exchange (consumer decides what to receive)
419
- await consumer.bindQueue('orders-processor', 'orders', 'order.created');
420
- await consumer.bindQueue('orders-processor', 'orders', 'order.updated');
421
- console.log('✓ Queue bindings created');
521
+ console.log('✓ Queue setup complete');
422
522
 
423
- // 7. Start consumer
523
+ // 5. Start consumer (queue already set up)
424
524
  await consumer.consumeQueue({
425
525
  queueName: 'orders-processor',
426
526
  onMessage: async (message) => {
@@ -482,28 +582,28 @@ startApp();
482
582
 
483
583
  ### Publisher Methods
484
584
 
485
- | Method | Description |
486
- |--------|-------------|
487
- | `assertExchange(names, options?)` | Create exchange(s) - Publisher owns exchanges |
488
- | `assertQueues(names, options?)` | Create queue(s) with optional retry config (backward compatible) |
489
- | `publishToExchange(config)` | Publish to exchange with routing key |
490
- | `publishToQueue(config)` | Publish directly to queue |
491
- | `publishBatch(configs)` | Publish multiple messages |
492
- | `deleteQueues(names, options?)` | Delete queue(s) and related retry/DLQ queues |
493
- | `close()` | Close publisher connection |
585
+ | Method | Description |
586
+ | --------------------------------- | -------------------------------------------------------------- |
587
+ | `assertExchange(names, options?)` | Create exchange(s) - Publisher owns exchanges |
588
+ | `publishToExchange(config)` | Publish to exchange with routing key |
589
+ | `publishToQueue(config)` | Publish directly to queue (queue should be set up by consumer) |
590
+ | `publishBatch(configs)` | Publish multiple messages |
591
+ | `close()` | Close publisher connection |
494
592
 
495
593
  ### Consumer Methods
496
594
 
497
- | Method | Description |
498
- |--------|-------------|
499
- | `assertExchange(names, options?)` | Assert exchange(s) on consumer connection (prevents race conditions) |
500
- | `assertQueues(names, options?)` | Create queue(s) with optional retry/DLQ config |
501
- | `bindQueue(queue, exchange, routingKey, options?)` | Bind queue to exchange |
502
- | `consumeQueue(config)` | Start consuming from queue |
503
- | `consumeMultipleQueues(config)` | Consume from multiple queues |
504
- | `consumeWithPattern(exchange, pattern, handler)` | Consume with pattern matching (topic) |
505
- | `getConsumerStats()` | Get consumer statistics |
506
- | `close()` | Close consumer connection |
595
+ | Method | Description |
596
+ | -------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
597
+ | `setupQueue(config)` | **⭐ RECOMMENDED** - Complete setup: exchange + queue + bindings + retry/DLQ in one atomic operation |
598
+ | `assertExchange(names, options?)` | Assert exchange(s) on consumer connection (defensive) |
599
+ | `assertQueues(names, options?)` | Create queue(s) with optional exchange binding and retry/DLQ config |
600
+ | `bindQueue(queue, exchange, routingKey, options?)` | Bind queue to exchange (for additional routing keys) |
601
+ | `deleteQueues(names, options?)` | Delete queue(s) and related retry/DLQ queues |
602
+ | `consumeQueue(config)` | Start consuming from queue (queue must be set up first) |
603
+ | `consumeMultipleQueues(config)` | Consume from multiple queues |
604
+ | `consumeWithPattern(exchange, pattern, handler)` | Consume with pattern matching (topic) |
605
+ | `getConsumerStats()` | Get consumer statistics |
606
+ | `close()` | Close consumer connection |
507
607
 
508
608
  ---
509
609
 
@@ -533,12 +633,13 @@ startApp();
533
633
 
534
634
  ```typescript
535
635
  await consumer.bindQueue(
536
- 'queue-name', // Queue to bind
537
- 'exchange-name', // Exchange to bind to
538
- 'routing.key', // Routing key or pattern (for topic exchanges)
539
- { // Options (optional)
540
- exchangeType: 'topic', // If provided, asserts exchange before binding (RECOMMENDED)
541
- durable: true // Exchange durability (default: true)
636
+ 'queue-name', // Queue to bind
637
+ 'exchange-name', // Exchange to bind to
638
+ 'routing.key', // Routing key or pattern (for topic exchanges)
639
+ {
640
+ // Options (optional)
641
+ exchangeType: 'topic', // If provided, asserts exchange before binding (RECOMMENDED)
642
+ durable: true, // Exchange durability (default: true)
542
643
  }
543
644
  );
544
645
 
@@ -585,13 +686,13 @@ await consumer.bindQueue(
585
686
 
586
687
  ```typescript
587
688
  // Delete queue (includes retry and DLQ by default)
588
- await publisher.deleteQueues('orders');
689
+ await consumer.deleteQueues('orders');
589
690
 
590
691
  // Delete multiple queues
591
- await publisher.deleteQueues(['orders', 'payments']);
692
+ await consumer.deleteQueues(['orders', 'payments']);
592
693
 
593
694
  // Delete only main queue
594
- await publisher.deleteQueues('orders', {
695
+ await consumer.deleteQueues('orders', {
595
696
  includeRetry: false,
596
697
  includeDLQ: false,
597
698
  });
@@ -602,11 +703,13 @@ await publisher.deleteQueues('orders', {
602
703
  ## Important Notes
603
704
 
604
705
  ### Required (Must Implement)
706
+
605
707
  - ⚠️ **Must call `await initializeRabbitMQ(url)` with try/catch** - throws error on connection failure
606
708
  - ⚠️ **Must implement graceful shutdown handlers** (`SIGTERM`, `SIGINT`)
607
709
  - ⚠️ **Must monitor DLQ failures** (indicates message loss)
608
710
 
609
711
  ### Error Handling
712
+
610
713
  - `initializeRabbitMQ()` throws error if:
611
714
  - RabbitMQ URL is wrong
612
715
  - RabbitMQ is not running
@@ -614,6 +717,7 @@ await publisher.deleteQueues('orders', {
614
717
  - Always wrap in try/catch for fail-fast behavior
615
718
 
616
719
  ### Automatic (No Action Needed)
720
+
617
721
  - ✅ Auto-reconnection on connection loss
618
722
  - ✅ Lazy loading - connects on first use (after initialization)
619
723
  - ✅ Message durability with `persistent: true`
@@ -621,12 +725,16 @@ await publisher.deleteQueues('orders', {
621
725
  - ✅ Thread-safe initialization
622
726
 
623
727
  ### Best Practices
728
+
624
729
  - Call `initializeRabbitMQ(url)` once in your setup/helper file
625
730
  - **Use separation of concerns pattern:**
626
- - Publisher → `assertExchange()` (owns exchanges)
627
- - Consumer → `assertQueues()` + `bindQueue()` (owns queues and bindings)
628
- - Set `retryConfig` in `assertQueues()` - auto-used when processing
629
- - `assertExchange()`, `assertQueues()`, and `bindQueue()` are idempotent - safe to call multiple times
731
+ - Publisher → `assertExchange()` + `publishToExchange()` (owns exchanges)
732
+ - Consumer → `setupQueue()` or `assertQueues()` + `bindQueue()` (owns queues and bindings)
733
+ - **Recommended workflow:**
734
+ 1. Setup infrastructure at startup: `consumer.setupQueue()` or `consumer.assertQueues()`
735
+ 2. Start consuming: `consumer.consumeQueue()`
736
+ - Set `retryConfig` in `setupQueue()` or `assertQueues()` - auto-used when processing
737
+ - `assertExchange()`, `assertQueues()`, `setupQueue()`, and `bindQueue()` are idempotent - safe to call multiple times
630
738
  - Use exponential backoff with jitter to prevent thundering herd
631
739
  - Always set up error event handlers before consuming
632
740
  - Use graceful shutdown in production
@@ -638,9 +746,10 @@ await publisher.deleteQueues('orders', {
638
746
  ### Error: PRECONDITION_FAILED - inequivalent arg 'x-dead-letter-exchange'
639
747
 
640
748
  **Problem:**
749
+
641
750
  ```
642
- Error: Operation failed: QueueDeclare; 406 (PRECONDITION_FAILED) with message
643
- "PRECONDITION_FAILED - inequivalent arg 'x-dead-letter-exchange' for queue
751
+ Error: Operation failed: QueueDeclare; 406 (PRECONDITION_FAILED) with message
752
+ "PRECONDITION_FAILED - inequivalent arg 'x-dead-letter-exchange' for queue
644
753
  'my_queue' in vhost '/': received 'my_exchange' but current is ''"
645
754
  ```
646
755
 
@@ -651,32 +760,36 @@ The queue already exists in RabbitMQ with different configuration arguments than
651
760
  Delete the existing queue and let your code recreate it with the correct configuration.
652
761
 
653
762
  **Option 1 - Using the utility script:**
763
+
654
764
  ```bash
655
765
  npx ts-node scripts/delete-queue.ts my_queue
656
766
  ```
657
767
 
658
768
  **Option 2 - Using RabbitMQ Management UI:**
769
+
659
770
  1. Navigate to `http://localhost:15672` (default credentials: guest/guest)
660
771
  2. Go to the "Queues" tab
661
772
  3. Find and delete the problematic queue
662
773
 
663
774
  **Option 3 - Using RabbitMQ CLI:**
775
+
664
776
  ```bash
665
777
  rabbitmqadmin delete queue name=my_queue
666
778
  ```
667
779
 
668
780
  **Option 4 - Using this library:**
781
+
669
782
  ```typescript
670
- import { publisher } from 'rabbitmq-with-retry-and-dlq';
783
+ import { consumer } from 'rabbitmq-with-retry-and-dlq';
671
784
 
672
- await publisher.deleteQueues('my_queue', {
785
+ await consumer.deleteQueues('my_queue', {
673
786
  includeRetry: true,
674
- includeDLQ: true
787
+ includeDLQ: true,
675
788
  });
676
789
  ```
677
790
 
678
791
  **Prevention:**
679
- Always use `publisher.assertQueues()` to create queues with the proper retry configuration before publishing or consuming.
792
+ Always use `consumer.setupQueue()` or `consumer.assertQueues()` to create queues with the proper retry configuration before consuming.
680
793
 
681
794
  ---
682
795