@onlineapps/conn-infra-mq 1.1.49 → 1.1.51
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 +88 -13
package/package.json
CHANGED
|
@@ -294,23 +294,89 @@ class RabbitMQClient extends EventEmitter {
|
|
|
294
294
|
// Skip assertQueue for reply queues (they're already created with specific settings)
|
|
295
295
|
// Reply queues start with 'rpc.reply.' and are created as non-durable
|
|
296
296
|
if (!queue.startsWith('rpc.reply.')) {
|
|
297
|
-
//
|
|
297
|
+
// CRITICAL: amqplib's channel.consume() may internally call assertQueue() without parameters
|
|
298
|
+
// This causes 406 errors if queue exists with different arguments
|
|
299
|
+
// Solution: Explicitly assertQueue() with correct parameters BEFORE consume()
|
|
298
300
|
const isInfraQueue = queueConfig.isInfrastructureQueue(queue);
|
|
301
|
+
const isBusinessQueue = queueConfig.isBusinessQueue(queue);
|
|
302
|
+
|
|
303
|
+
let queueOptions = { durable };
|
|
299
304
|
|
|
300
305
|
if (isInfraQueue) {
|
|
301
|
-
// Infrastructure queue -
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
306
|
+
// Infrastructure queue - use central config
|
|
307
|
+
try {
|
|
308
|
+
const infraConfig = queueConfig.getInfrastructureQueueConfig(queue);
|
|
309
|
+
queueOptions = {
|
|
310
|
+
durable: infraConfig.durable !== false,
|
|
311
|
+
arguments: { ...infraConfig.arguments }
|
|
312
|
+
};
|
|
313
|
+
console.log(`[RabbitMQClient] [CONSUMER] Asserting infrastructure queue ${queue} with config from queueConfig`);
|
|
314
|
+
} catch (configErr) {
|
|
315
|
+
console.warn(`[RabbitMQClient] [CONSUMER] Infrastructure queue config not found for ${queue}, using default:`, configErr.message);
|
|
316
|
+
}
|
|
317
|
+
} else if (isBusinessQueue) {
|
|
318
|
+
// Business queue - use central config
|
|
319
|
+
try {
|
|
320
|
+
const parsed = queueConfig.parseBusinessQueue(queue);
|
|
321
|
+
if (parsed) {
|
|
322
|
+
const businessConfig = queueConfig.getBusinessQueueConfig(parsed.queueType, parsed.serviceName);
|
|
323
|
+
queueOptions = {
|
|
324
|
+
durable: businessConfig.durable !== false,
|
|
325
|
+
arguments: { ...businessConfig.arguments }
|
|
326
|
+
};
|
|
327
|
+
console.log(`[RabbitMQClient] [CONSUMER] Asserting business queue ${queue} with config from queueConfig`);
|
|
328
|
+
}
|
|
329
|
+
} catch (configErr) {
|
|
330
|
+
console.warn(`[RabbitMQClient] [CONSUMER] Business queue config not found for ${queue}, using default:`, configErr.message);
|
|
331
|
+
}
|
|
313
332
|
}
|
|
333
|
+
|
|
334
|
+
// CRITICAL: Assert queue with correct parameters BEFORE consume()
|
|
335
|
+
// This prevents amqplib from calling assertQueue() internally without parameters
|
|
336
|
+
const assertStartTime = Date.now();
|
|
337
|
+
console.log(`[RabbitMQClient] [CONSUMER] Asserting queue ${queue} before consume() at ${new Date().toISOString()}`);
|
|
338
|
+
console.log(`[RabbitMQClient] [CONSUMER] Queue options:`, JSON.stringify(queueOptions, null, 2));
|
|
339
|
+
|
|
340
|
+
// CRITICAL: Ensure _queueChannel is open before using it
|
|
341
|
+
// If it's closed (e.g., due to 406 error), recreate it
|
|
342
|
+
if (!this._queueChannel || this._queueChannel.closed) {
|
|
343
|
+
console.warn(`[RabbitMQClient] [CONSUMER] _queueChannel is closed or null, recreating...`);
|
|
344
|
+
try {
|
|
345
|
+
this._queueChannel = await this._connection.createChannel();
|
|
346
|
+
this._queueChannel._createdAt = new Date().toISOString();
|
|
347
|
+
this._queueChannel._closeReason = null;
|
|
348
|
+
this._queueChannel._lastOperation = null;
|
|
349
|
+
|
|
350
|
+
// Re-attach event listeners
|
|
351
|
+
this._queueChannel.on('error', (err) => {
|
|
352
|
+
console.error('[RabbitMQClient] Queue channel error:', err.message);
|
|
353
|
+
console.error('[RabbitMQClient] Error code:', err.code);
|
|
354
|
+
console.error('[RabbitMQClient] Channel created at:', this._queueChannel._createdAt);
|
|
355
|
+
console.error('[RabbitMQClient] Last operation:', this._queueChannel._lastOperation);
|
|
356
|
+
this._queueChannel._closeReason = `Error: ${err.message} (code: ${err.code})`;
|
|
357
|
+
});
|
|
358
|
+
this._queueChannel.on('close', () => {
|
|
359
|
+
console.error('[RabbitMQClient] Queue channel closed');
|
|
360
|
+
console.error('[RabbitMQClient] Channel created at:', this._queueChannel._createdAt);
|
|
361
|
+
console.error('[RabbitMQClient] Close reason:', this._queueChannel._closeReason || 'Unknown');
|
|
362
|
+
console.error('[RabbitMQClient] Last operation:', this._queueChannel._lastOperation);
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
console.log(`[RabbitMQClient] [CONSUMER] ✓ _queueChannel recreated`);
|
|
366
|
+
} catch (recreateErr) {
|
|
367
|
+
console.error(`[RabbitMQClient] [CONSUMER] ✗ Failed to recreate _queueChannel:`, recreateErr.message);
|
|
368
|
+
throw new Error(`Cannot assertQueue: _queueChannel is closed and recreation failed: ${recreateErr.message}`);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// Use queueChannel for assertQueue to avoid RPC reply queue issues
|
|
373
|
+
const channelForAssert = this._queueChannel;
|
|
374
|
+
this._queueChannel._lastOperation = `About to assertQueue ${queue}`;
|
|
375
|
+
await channelForAssert.assertQueue(queue, queueOptions);
|
|
376
|
+
this._queueChannel._lastOperation = `assertQueue ${queue} succeeded`;
|
|
377
|
+
|
|
378
|
+
const assertEndTime = Date.now();
|
|
379
|
+
console.log(`[RabbitMQClient] [CONSUMER] ✓ Queue ${queue} asserted (took ${assertEndTime - assertStartTime}ms)`);
|
|
314
380
|
}
|
|
315
381
|
// Set prefetch if provided
|
|
316
382
|
if (typeof prefetch === 'number') {
|
|
@@ -322,6 +388,15 @@ class RabbitMQClient extends EventEmitter {
|
|
|
322
388
|
console.log(`[RabbitMQClient] [CONSUMER] Options: prefetch=${prefetch}, noAck=${noAck}, durable=${durable}`);
|
|
323
389
|
console.log(`[RabbitMQClient] [CONSUMER] Channel state before consume: closed=${this._channel.closed}`);
|
|
324
390
|
|
|
391
|
+
// CRITICAL WARNING: amqplib's channel.consume() may internally call assertQueue() WITHOUT parameters
|
|
392
|
+
// This happens if the queue doesn't exist or if amqplib needs to verify queue existence
|
|
393
|
+
// If queue exists with different arguments (e.g., x-message-ttl), this will cause 406 PRECONDITION-FAILED
|
|
394
|
+
// and close the channel. That's why we assertQueue() with correct parameters BEFORE consume() above.
|
|
395
|
+
console.log(`[RabbitMQClient] [CONSUMER] ⚠ WARNING: About to call amqplib's channel.consume() for queue: ${queue}`);
|
|
396
|
+
console.log(`[RabbitMQClient] [CONSUMER] ⚠ WARNING: amqplib may internally call assertQueue() WITHOUT parameters if queue doesn't exist`);
|
|
397
|
+
console.log(`[RabbitMQClient] [CONSUMER] ⚠ WARNING: If queue exists with different arguments, this will cause 406 PRECONDITION-FAILED and close channel`);
|
|
398
|
+
console.log(`[RabbitMQClient] [CONSUMER] ⚠ WARNING: We already asserted queue with correct parameters above - this should prevent 406`);
|
|
399
|
+
|
|
325
400
|
const consumeResult = await this._channel.consume(
|
|
326
401
|
queue,
|
|
327
402
|
async (msg) => {
|