rabbitmq-with-retry-and-dlq 1.0.24 → 1.0.26

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,28 +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
252
  ### Complete Best Practice Example (RECOMMENDED)
156
253
 
157
- Use `setupQueue()` for atomic setup - it does everything in ONE operation, preventing all race conditions:
158
-
159
254
  ```typescript
160
255
  // === PUBLISHER SIDE ===
256
+ // Publisher only knows about exchanges
161
257
  await publisher.assertExchange('orders', { exchangeType: 'topic' });
162
258
 
163
259
  await publisher.publishToExchange({
@@ -167,81 +263,66 @@ await publisher.publishToExchange({
167
263
  });
168
264
 
169
265
  // === CONSUMER SIDE ===
170
- // Use setupQueue() - does exchange, queue, and bindings in ONE atomic operation
266
+ // Step 1: Setup queue with exchange and multiple routing keys (RECOMMENDED)
171
267
  await consumer.setupQueue({
172
268
  queueName: 'orders-processor',
173
269
  exchangeName: 'orders',
174
270
  exchangeType: 'topic',
175
- routingKeys: ['order.created', 'order.updated'],
176
- retryConfig: { maxRetries: 3, retryDelayMs: 5000 }
271
+ routingKeys: ['order.created', 'order.updated'], // Multiple keys!
272
+ retryConfig: { maxRetries: 3, retryDelayMs: 5000 },
177
273
  });
178
274
 
179
- // Start consuming
275
+ // Step 2: Start consuming (queue already set up)
180
276
  await consumer.consumeQueue({
181
277
  queueName: 'orders-processor',
182
278
  onMessage: async (message) => {
183
279
  console.log('Processing order:', message);
280
+ await processOrder(message);
184
281
  },
185
282
  });
186
283
  ```
187
284
 
188
285
  ### Alternative: Step-by-Step Setup
189
286
 
190
- If you need more control, you can use separate methods (but ensure correct order):
287
+ If you need more granular control, use separate methods:
191
288
 
192
289
  ```typescript
193
- // Step 1: Assert exchanges on consumer's connection
290
+ // Step 1: Assert exchanges on consumer's connection (defensive)
194
291
  await consumer.assertExchange('orders', { exchangeType: 'topic' });
195
292
 
196
293
  // Step 2: Create queues with retry/DLQ config
197
294
  await consumer.assertQueues('orders-processor', {
198
- retryConfig: { maxRetries: 3, retryDelayMs: 5000 }
295
+ retryConfig: { maxRetries: 3, retryDelayMs: 5000 },
296
+ });
297
+
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',
199
304
  });
200
305
 
201
- // Step 3: Bind queues to exchanges
202
- await consumer.bindQueue('orders-processor', 'orders', 'order.created');
203
- await consumer.bindQueue('orders-processor', 'orders', 'order.updated');
306
+ // Step 4: Start consuming
307
+ await consumer.consumeQueue({
308
+ queueName: 'orders-processor',
309
+ onMessage: async (message) => {
310
+ await processOrder(message);
311
+ },
312
+ });
204
313
  ```
205
314
 
206
315
  ---
207
316
 
208
- ## Alternative: Publisher-Managed Queues
209
-
210
- For simpler use cases, the publisher can also manage queues (backward compatible):
317
+ ## Direct Queue Publishing (Without Exchange)
211
318
 
212
- ### 3. Assert Queues (with Retry Config)
319
+ For simple point-to-point messaging without exchanges:
213
320
 
214
- **Note:** `assertQueues()` is **idempotent** - it safely skips queues that already exist. You can call it multiple times without errors.
321
+ ### Publish to Queue
215
322
 
216
323
  ```typescript
217
- await publisher.assertQueues('orders', {
218
- durable: true, // Queue survives restart (default: true)
219
- retryConfig: {
220
- maxRetries: 5, // Required
221
- retryDelayMs: 2000, // Base delay (default: 5000ms)
222
- backoffStrategy: 'exponential', // 'exponential' or 'linear' (default: exponential)
223
- maxDelayMs: 300000, // Max delay cap (default: 300000 = 5min)
224
- jitterMs: 1000, // Random jitter 0-1000ms (default: 0)
225
- },
226
- });
227
-
228
- // Assert multiple queues
229
- await publisher.assertQueues(['orders', 'payments', 'notifications'], {
230
- retryConfig: { maxRetries: 3 }
231
- });
232
-
233
- // With exchange
234
- await publisher.assertQueues('order_processing', {
235
- exchangeName: 'orders_exchange',
236
- exchangeType: 'direct', // 'direct' | 'topic' | 'fanout' | 'headers'
237
- routingKey: 'order.created',
238
- retryConfig: { maxRetries: 3 },
239
- });
240
- ```
324
+ // Note: Queue should be set up by consumer first using assertQueues() or setupQueue()
241
325
 
242
- ### 4. Publish to Queue
243
-
244
- ```typescript
245
326
  await publisher.publishToQueue({
246
327
  queueName: 'orders',
247
328
  message: {
@@ -249,14 +330,19 @@ await publisher.publishToQueue({
249
330
  amount: 99.99,
250
331
  },
251
332
  options: {
252
- persistent: true, // Survives broker restart (default: true)
253
- priority: 5, // 0-10 priority (optional)
254
- 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,
255
341
  },
256
342
  });
257
343
  ```
258
344
 
259
- ### 5. Publish to Exchange
345
+ ### Publish to Exchange
260
346
 
261
347
  ```typescript
262
348
  // Publisher only needs exchange and routing key (not queue!)
@@ -272,10 +358,10 @@ await publisher.publishToExchange({
272
358
  });
273
359
  ```
274
360
 
275
- ### 6. Consumer
361
+ ### Consumer (Best Practice)
276
362
 
277
363
  ```typescript
278
- // Set up error handler
364
+ // Set up error handler FIRST
279
365
  consumer.on('error', (errorEvent) => {
280
366
  console.error('RabbitMQ Error:', errorEvent);
281
367
  if (errorEvent.type === 'DLQ_FAILED') {
@@ -283,31 +369,34 @@ consumer.on('error', (errorEvent) => {
283
369
  }
284
370
  });
285
371
 
286
- // 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)
287
386
  await consumer.consumeQueue({
288
- queueName: 'orders',
387
+ queueName: 'orders-processor',
289
388
  onMessage: async (message, messageInfo) => {
290
389
  console.log('Processing:', message);
291
-
390
+
292
391
  // Your business logic
293
392
  await processOrder(message);
294
-
393
+
295
394
  // Success = auto-ack
296
- // Throw error = retry with backoff
395
+ // Throw error = retry with backoff → DLQ
297
396
  },
298
397
  options: {
299
- prefetch: 5, // Max unacked messages (default: 5)
300
- noAck: false, // Auto-ack (default: false)
301
- },
302
- });
303
-
304
- // Consume from exchange
305
- await consumer.consumeQueue({
306
- queueName: 'order_processing',
307
- exchangeName: 'orders_exchange',
308
- routingKey: 'order.created',
309
- onMessage: async (message) => {
310
- await processOrder(message);
398
+ prefetch: 5, // Max unacked messages (default: 5)
399
+ noAck: false, // Auto-ack (default: false)
311
400
  },
312
401
  });
313
402
  ```
@@ -335,11 +424,11 @@ process.on('SIGINT', shutdown);
335
424
 
336
425
  ```typescript
337
426
  interface RetryConfig {
338
- maxRetries: number; // Required: max retry attempts
339
- retryDelayMs?: number; // Optional: base delay in ms (default: 5000)
340
- backoffStrategy?: string; // Optional: 'exponential' | 'linear' (default: 'exponential')
341
- maxDelayMs?: number; // Optional: max delay cap (default: 300000)
342
- 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)
343
432
  }
344
433
  ```
345
434
 
@@ -403,9 +492,9 @@ async function startApp() {
403
492
  // 1. Initialize RabbitMQ connection (required - use await)
404
493
  console.log('Connecting to RabbitMQ...');
405
494
  await initializeRabbitMQ('amqp://user:pass@localhost:5672');
406
-
495
+
407
496
  console.log('✓ Publisher connected:', isPublisherConnected()); // true
408
- console.log('✓ Consumer connected:', isConsumerConnected()); // true
497
+ console.log('✓ Consumer connected:', isConsumerConnected()); // true
409
498
 
410
499
  // 2. Set up error handler
411
500
  consumer.on('error', (errorEvent: RabbitMQErrorEvent) => {
@@ -416,12 +505,12 @@ async function startApp() {
416
505
  await publisher.assertExchange('orders', { exchangeType: 'topic' });
417
506
  console.log('✓ Publisher exchange asserted');
418
507
 
419
- // 4. Consumer: Assert exchange on consumer's connection (PREVENTS RACE CONDITIONS!)
420
- await consumer.assertExchange('orders', { exchangeType: 'topic' });
421
- console.log('✓ Consumer exchange asserted');
422
-
423
- // 5. Consumer: Assert queues with retry config (consumer owns queues)
424
- 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'],
425
514
  retryConfig: {
426
515
  maxRetries: 5,
427
516
  retryDelayMs: 2000,
@@ -429,14 +518,9 @@ async function startApp() {
429
518
  jitterMs: 1000,
430
519
  },
431
520
  });
432
- console.log('✓ Queues asserted');
433
-
434
- // 6. Consumer: Bind queue to exchange (consumer decides what to receive)
435
- await consumer.bindQueue('orders-processor', 'orders', 'order.created');
436
- await consumer.bindQueue('orders-processor', 'orders', 'order.updated');
437
- console.log('✓ Queue bindings created');
521
+ console.log('✓ Queue setup complete');
438
522
 
439
- // 7. Start consumer
523
+ // 5. Start consumer (queue already set up)
440
524
  await consumer.consumeQueue({
441
525
  queueName: 'orders-processor',
442
526
  onMessage: async (message) => {
@@ -498,29 +582,28 @@ startApp();
498
582
 
499
583
  ### Publisher Methods
500
584
 
501
- | Method | Description |
502
- |--------|-------------|
503
- | `assertExchange(names, options?)` | Create exchange(s) - Publisher owns exchanges |
504
- | `assertQueues(names, options?)` | Create queue(s) with optional retry config (backward compatible) |
505
- | `publishToExchange(config)` | Publish to exchange with routing key |
506
- | `publishToQueue(config)` | Publish directly to queue |
507
- | `publishBatch(configs)` | Publish multiple messages |
508
- | `deleteQueues(names, options?)` | Delete queue(s) and related retry/DLQ queues |
509
- | `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 |
510
592
 
511
593
  ### Consumer Methods
512
594
 
513
- | Method | Description |
514
- |--------|-------------|
515
- | `setupQueue(config)` | **RECOMMENDED** - Atomic setup: exchange + queue + bindings in one operation |
516
- | `assertExchange(names, options?)` | Assert exchange(s) on consumer connection |
517
- | `assertQueues(names, options?)` | Create queue(s) with optional retry/DLQ config |
518
- | `bindQueue(queue, exchange, routingKey, options?)` | Bind queue to exchange |
519
- | `consumeQueue(config)` | Start consuming from queue |
520
- | `consumeMultipleQueues(config)` | Consume from multiple queues |
521
- | `consumeWithPattern(exchange, pattern, handler)` | Consume with pattern matching (topic) |
522
- | `getConsumerStats()` | Get consumer statistics |
523
- | `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 |
524
607
 
525
608
  ---
526
609
 
@@ -550,12 +633,13 @@ startApp();
550
633
 
551
634
  ```typescript
552
635
  await consumer.bindQueue(
553
- 'queue-name', // Queue to bind
554
- 'exchange-name', // Exchange to bind to
555
- 'routing.key', // Routing key or pattern (for topic exchanges)
556
- { // Options (optional)
557
- exchangeType: 'topic', // If provided, asserts exchange before binding (RECOMMENDED)
558
- 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)
559
643
  }
560
644
  );
561
645
 
@@ -602,13 +686,13 @@ await consumer.bindQueue(
602
686
 
603
687
  ```typescript
604
688
  // Delete queue (includes retry and DLQ by default)
605
- await publisher.deleteQueues('orders');
689
+ await consumer.deleteQueues('orders');
606
690
 
607
691
  // Delete multiple queues
608
- await publisher.deleteQueues(['orders', 'payments']);
692
+ await consumer.deleteQueues(['orders', 'payments']);
609
693
 
610
694
  // Delete only main queue
611
- await publisher.deleteQueues('orders', {
695
+ await consumer.deleteQueues('orders', {
612
696
  includeRetry: false,
613
697
  includeDLQ: false,
614
698
  });
@@ -619,11 +703,13 @@ await publisher.deleteQueues('orders', {
619
703
  ## Important Notes
620
704
 
621
705
  ### Required (Must Implement)
706
+
622
707
  - ⚠️ **Must call `await initializeRabbitMQ(url)` with try/catch** - throws error on connection failure
623
708
  - ⚠️ **Must implement graceful shutdown handlers** (`SIGTERM`, `SIGINT`)
624
709
  - ⚠️ **Must monitor DLQ failures** (indicates message loss)
625
710
 
626
711
  ### Error Handling
712
+
627
713
  - `initializeRabbitMQ()` throws error if:
628
714
  - RabbitMQ URL is wrong
629
715
  - RabbitMQ is not running
@@ -631,6 +717,7 @@ await publisher.deleteQueues('orders', {
631
717
  - Always wrap in try/catch for fail-fast behavior
632
718
 
633
719
  ### Automatic (No Action Needed)
720
+
634
721
  - ✅ Auto-reconnection on connection loss
635
722
  - ✅ Lazy loading - connects on first use (after initialization)
636
723
  - ✅ Message durability with `persistent: true`
@@ -638,12 +725,16 @@ await publisher.deleteQueues('orders', {
638
725
  - ✅ Thread-safe initialization
639
726
 
640
727
  ### Best Practices
728
+
641
729
  - Call `initializeRabbitMQ(url)` once in your setup/helper file
642
730
  - **Use separation of concerns pattern:**
643
- - Publisher → `assertExchange()` (owns exchanges)
644
- - Consumer → `assertQueues()` + `bindQueue()` (owns queues and bindings)
645
- - Set `retryConfig` in `assertQueues()` - auto-used when processing
646
- - `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
647
738
  - Use exponential backoff with jitter to prevent thundering herd
648
739
  - Always set up error event handlers before consuming
649
740
  - Use graceful shutdown in production
@@ -655,9 +746,10 @@ await publisher.deleteQueues('orders', {
655
746
  ### Error: PRECONDITION_FAILED - inequivalent arg 'x-dead-letter-exchange'
656
747
 
657
748
  **Problem:**
749
+
658
750
  ```
659
- Error: Operation failed: QueueDeclare; 406 (PRECONDITION_FAILED) with message
660
- "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
661
753
  'my_queue' in vhost '/': received 'my_exchange' but current is ''"
662
754
  ```
663
755
 
@@ -668,32 +760,36 @@ The queue already exists in RabbitMQ with different configuration arguments than
668
760
  Delete the existing queue and let your code recreate it with the correct configuration.
669
761
 
670
762
  **Option 1 - Using the utility script:**
763
+
671
764
  ```bash
672
765
  npx ts-node scripts/delete-queue.ts my_queue
673
766
  ```
674
767
 
675
768
  **Option 2 - Using RabbitMQ Management UI:**
769
+
676
770
  1. Navigate to `http://localhost:15672` (default credentials: guest/guest)
677
771
  2. Go to the "Queues" tab
678
772
  3. Find and delete the problematic queue
679
773
 
680
774
  **Option 3 - Using RabbitMQ CLI:**
775
+
681
776
  ```bash
682
777
  rabbitmqadmin delete queue name=my_queue
683
778
  ```
684
779
 
685
780
  **Option 4 - Using this library:**
781
+
686
782
  ```typescript
687
- import { publisher } from 'rabbitmq-with-retry-and-dlq';
783
+ import { consumer } from 'rabbitmq-with-retry-and-dlq';
688
784
 
689
- await publisher.deleteQueues('my_queue', {
785
+ await consumer.deleteQueues('my_queue', {
690
786
  includeRetry: true,
691
- includeDLQ: true
787
+ includeDLQ: true,
692
788
  });
693
789
  ```
694
790
 
695
791
  **Prevention:**
696
- 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.
697
793
 
698
794
  ---
699
795