@onlineapps/mq-client-core 1.0.31 → 1.0.32
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/package.json +1 -1
- package/src/transports/rabbitmqClient.js +68 -23
package/package.json
CHANGED
|
@@ -32,8 +32,9 @@ class RabbitMQClient extends EventEmitter {
|
|
|
32
32
|
);
|
|
33
33
|
|
|
34
34
|
this._connection = null;
|
|
35
|
-
this._channel = null;
|
|
36
|
-
this._queueChannel = null;
|
|
35
|
+
this._channel = null; // ConfirmChannel for publish operations
|
|
36
|
+
this._queueChannel = null; // Regular channel for queue operations (assertQueue, checkQueue)
|
|
37
|
+
this._consumerChannel = null; // Dedicated channel for consume operations
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
/**
|
|
@@ -109,6 +110,18 @@ class RabbitMQClient extends EventEmitter {
|
|
|
109
110
|
this._queueChannel.on('close', () => {
|
|
110
111
|
console.warn('[RabbitMQClient] Queue channel closed');
|
|
111
112
|
});
|
|
113
|
+
|
|
114
|
+
// Create a dedicated channel for consume operations
|
|
115
|
+
// This prevents channel conflicts between publish (ConfirmChannel) and consume operations
|
|
116
|
+
this._consumerChannel = await this._connection.createChannel();
|
|
117
|
+
this._consumerChannel.on('error', (err) => {
|
|
118
|
+
console.warn('[RabbitMQClient] Consumer channel error:', err.message);
|
|
119
|
+
this.emit('error', err);
|
|
120
|
+
});
|
|
121
|
+
this._consumerChannel.on('close', () => {
|
|
122
|
+
console.warn('[RabbitMQClient] Consumer channel closed');
|
|
123
|
+
this.emit('error', new Error('RabbitMQ consumer channel closed unexpectedly'));
|
|
124
|
+
});
|
|
112
125
|
} catch (err) {
|
|
113
126
|
// Cleanup partially created resources
|
|
114
127
|
if (this._connection) {
|
|
@@ -128,6 +141,14 @@ class RabbitMQClient extends EventEmitter {
|
|
|
128
141
|
* @returns {Promise<void>}
|
|
129
142
|
*/
|
|
130
143
|
async disconnect() {
|
|
144
|
+
try {
|
|
145
|
+
if (this._consumerChannel) {
|
|
146
|
+
await this._consumerChannel.close();
|
|
147
|
+
this._consumerChannel = null;
|
|
148
|
+
}
|
|
149
|
+
} catch (err) {
|
|
150
|
+
console.warn('[RabbitMQClient] Error closing consumer channel:', err.message);
|
|
151
|
+
}
|
|
131
152
|
try {
|
|
132
153
|
if (this._queueChannel) {
|
|
133
154
|
await this._queueChannel.close();
|
|
@@ -270,8 +291,40 @@ class RabbitMQClient extends EventEmitter {
|
|
|
270
291
|
* @throws {Error} If consume setup fails or channel is not available.
|
|
271
292
|
*/
|
|
272
293
|
async consume(queue, onMessage, options = {}) {
|
|
273
|
-
|
|
274
|
-
|
|
294
|
+
// Use dedicated consumer channel instead of ConfirmChannel
|
|
295
|
+
// ConfirmChannel is optimized for publish operations, not consume
|
|
296
|
+
if (!this._consumerChannel) {
|
|
297
|
+
// Recreate consumer channel if closed
|
|
298
|
+
if (this._connection && !this._connection.closed) {
|
|
299
|
+
this._consumerChannel = await this._connection.createChannel();
|
|
300
|
+
this._consumerChannel.on('error', (err) => {
|
|
301
|
+
console.warn('[RabbitMQClient] Consumer channel error:', err.message);
|
|
302
|
+
this.emit('error', err);
|
|
303
|
+
});
|
|
304
|
+
this._consumerChannel.on('close', () => {
|
|
305
|
+
console.warn('[RabbitMQClient] Consumer channel closed');
|
|
306
|
+
this.emit('error', new Error('RabbitMQ consumer channel closed unexpectedly'));
|
|
307
|
+
});
|
|
308
|
+
} else {
|
|
309
|
+
throw new Error('Cannot consume: consumer channel is not initialized and connection is closed');
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if (this._consumerChannel.closed) {
|
|
314
|
+
// Recreate consumer channel if closed
|
|
315
|
+
if (this._connection && !this._connection.closed) {
|
|
316
|
+
this._consumerChannel = await this._connection.createChannel();
|
|
317
|
+
this._consumerChannel.on('error', (err) => {
|
|
318
|
+
console.warn('[RabbitMQClient] Consumer channel error:', err.message);
|
|
319
|
+
this.emit('error', err);
|
|
320
|
+
});
|
|
321
|
+
this._consumerChannel.on('close', () => {
|
|
322
|
+
console.warn('[RabbitMQClient] Consumer channel closed');
|
|
323
|
+
this.emit('error', new Error('RabbitMQ consumer channel closed unexpectedly'));
|
|
324
|
+
});
|
|
325
|
+
} else {
|
|
326
|
+
throw new Error('Cannot consume: consumer channel is closed and connection is closed');
|
|
327
|
+
}
|
|
275
328
|
}
|
|
276
329
|
|
|
277
330
|
const durable = options.durable !== undefined ? options.durable : this._config.durable;
|
|
@@ -368,32 +421,21 @@ class RabbitMQClient extends EventEmitter {
|
|
|
368
421
|
}
|
|
369
422
|
}
|
|
370
423
|
}
|
|
371
|
-
// Set prefetch if provided
|
|
424
|
+
// Set prefetch if provided (on consumer channel)
|
|
372
425
|
if (typeof prefetch === 'number') {
|
|
373
|
-
this.
|
|
426
|
+
this._consumerChannel.prefetch(prefetch);
|
|
374
427
|
}
|
|
375
428
|
|
|
376
429
|
// CRITICAL: Log before calling amqplib's consume()
|
|
377
430
|
// amqplib's consume() may internally call assertQueue() without parameters if queue doesn't exist
|
|
378
431
|
// This would create queue with default arguments (no TTL), causing 406 errors later
|
|
379
|
-
console.log(`[RabbitMQClient] [mq-client-core] [CONSUMER] About to call amqplib's
|
|
432
|
+
console.log(`[RabbitMQClient] [mq-client-core] [CONSUMER] About to call amqplib's consumerChannel.consume(${queue})`);
|
|
380
433
|
console.log(`[RabbitMQClient] [mq-client-core] [CONSUMER] ⚠ WARNING: amqplib's consume() may internally call assertQueue() WITHOUT parameters if queue doesn't exist`);
|
|
381
434
|
console.log(`[RabbitMQClient] [mq-client-core] [CONSUMER] ⚠ WARNING: We already asserted queue with correct parameters above - this should prevent auto-creation`);
|
|
382
435
|
|
|
383
|
-
//
|
|
384
|
-
// This
|
|
385
|
-
const
|
|
386
|
-
const originalAssertQueue = this._channel.assertQueue.bind(this._channel);
|
|
387
|
-
|
|
388
|
-
// Intercept assertQueue() calls to log them
|
|
389
|
-
this._channel.assertQueue = async function(queueName, options) {
|
|
390
|
-
console.log(`[RabbitMQClient] [mq-client-core] [INTERCEPT] assertQueue() called for: ${queueName}`);
|
|
391
|
-
console.log(`[RabbitMQClient] [mq-client-core] [INTERCEPT] Options:`, JSON.stringify(options || {}, null, 2));
|
|
392
|
-
console.log(`[RabbitMQClient] [mq-client-core] [INTERCEPT] Stack trace:`, new Error().stack.split('\n').slice(1, 10).join('\n'));
|
|
393
|
-
return originalAssertQueue.call(this, queueName, options);
|
|
394
|
-
};
|
|
395
|
-
|
|
396
|
-
await this._channel.consume(
|
|
436
|
+
// Use dedicated consumer channel for consume operations
|
|
437
|
+
// This prevents conflicts with ConfirmChannel used for publish operations
|
|
438
|
+
const consumeResult = await this._consumerChannel.consume(
|
|
397
439
|
queue,
|
|
398
440
|
async (msg) => {
|
|
399
441
|
if (msg === null) {
|
|
@@ -402,15 +444,18 @@ class RabbitMQClient extends EventEmitter {
|
|
|
402
444
|
try {
|
|
403
445
|
await onMessage(msg);
|
|
404
446
|
if (!noAck) {
|
|
405
|
-
this.
|
|
447
|
+
this._consumerChannel.ack(msg);
|
|
406
448
|
}
|
|
407
449
|
} catch (handlerErr) {
|
|
408
450
|
// Negative acknowledge and requeue by default
|
|
409
|
-
this.
|
|
451
|
+
this._consumerChannel.nack(msg, false, true);
|
|
410
452
|
}
|
|
411
453
|
},
|
|
412
454
|
{ noAck }
|
|
413
455
|
);
|
|
456
|
+
|
|
457
|
+
// Return consumer tag for cancellation
|
|
458
|
+
return consumeResult.consumerTag;
|
|
414
459
|
} catch (err) {
|
|
415
460
|
this.emit('error', err);
|
|
416
461
|
throw err;
|