@onlineapps/conn-infra-mq 1.1.37 → 1.1.39

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onlineapps/conn-infra-mq",
3
- "version": "1.1.37",
3
+ "version": "1.1.39",
4
4
  "description": "A promise-based, broker-agnostic client for sending and receiving messages via RabbitMQ",
5
5
  "main": "src/index.js",
6
6
  "repository": {
@@ -266,7 +266,7 @@ class QueueManager {
266
266
  console.error('[RabbitMQClient] Close reason:', channel._closeReason || 'Unknown');
267
267
  });
268
268
 
269
- transport.queueChannel = channel;
269
+ transport._queueChannel = channel;
270
270
  console.log(`[QueueManager] DEBUG: Channel recreated (was null) before ${queueInfo.name}`);
271
271
  } else {
272
272
  // Check if channel is closed - amqplib may not set closed property immediately
@@ -305,7 +305,7 @@ class QueueManager {
305
305
  });
306
306
 
307
307
  channel = newChannel;
308
- transport.queueChannel = channel;
308
+ transport._queueChannel = channel;
309
309
  console.log(`[QueueManager] DEBUG: Channel recreated (check failed) before ${queueInfo.name}`);
310
310
  channelUsable = true;
311
311
  } catch (recreateErr) {
@@ -365,110 +365,94 @@ class QueueManager {
365
365
  }
366
366
  }
367
367
 
368
- // CRITICAL: Use assertQueue directly - if queue exists with different args (406), that's OK
369
- // BUT: 406 PRECONDITION-FAILED closes the channel in amqplib!
370
- // Solution: Track channel state, catch 406, recreate channel immediately, and continue
368
+ // CRITICAL: Use the SAME pattern as ensureQueue() - checkQueue() FIRST, then assertQueue() only if 404
369
+ // This prevents channel closure on 406 PRECONDITION-FAILED
370
+ // Pattern: checkQueue() -> if 404, assertQueue() -> if 406, use existing queue (channel stays open)
371
371
  let queueCreated = false;
372
372
 
373
- // CRITICAL: Track operation on channel for debugging
373
+ // Track operation on channel for debugging
374
374
  if (channel && channel._lastOperation !== undefined) {
375
- channel._lastOperation = `About to assertQueue ${queueName}`;
375
+ channel._lastOperation = `About to checkQueue ${queueName}`;
376
376
  }
377
377
 
378
378
  try {
379
- console.log(`[QueueManager] DEBUG: About to assertQueue ${queueName}`);
379
+ console.log(`[QueueManager] DEBUG: About to checkQueue ${queueName} (same pattern as ensureQueue)`);
380
380
  console.log(`[QueueManager] DEBUG: Channel state: exists=${!!channel}, closed=${channel ? (channel.closed === true ? 'true' : channel.closed === false ? 'false' : 'undefined') : 'N/A'}`);
381
- console.log(`[QueueManager] DEBUG: Channel created at: ${channel?._createdAt || 'N/A'}`);
382
- console.log(`[QueueManager] DEBUG: Queue options:`, JSON.stringify(queueOptions, null, 2));
383
381
 
384
- await channel.assertQueue(queueName, queueOptions);
382
+ // CRITICAL: Use checkQueue() FIRST (same as ensureQueue() pattern)
383
+ // This prevents channel closure on 406 - if queue exists with different args, checkQueue() returns 406 but channel stays open
384
+ await channel.checkQueue(queueName);
385
385
 
386
- console.log(`[QueueManager] DEBUG: assertQueue succeeded for ${queueName}`);
386
+ // Queue exists - use it
387
+ console.log(`[QueueManager] DEBUG: checkQueue succeeded - queue ${queueName} exists`);
387
388
  if (channel && channel._lastOperation !== undefined) {
388
- channel._lastOperation = `assertQueue ${queueName} succeeded`;
389
+ channel._lastOperation = `checkQueue ${queueName} succeeded`;
389
390
  }
390
391
  queues[queueInfo.type] = queueName;
391
392
  queueCreated = true;
392
- console.info(`[QueueManager] ✓ Created business queue: ${queueName}`);
393
- } catch (assertErr) {
394
- console.error(`[QueueManager] DEBUG: assertQueue failed for ${queueName}:`, assertErr.message);
395
- console.error(`[QueueManager] DEBUG: Error code: ${assertErr.code}`);
396
- console.error(`[QueueManager] DEBUG: Channel state after error: exists=${!!channel}, closed=${channel ? (channel.closed === true ? 'true' : channel.closed === false ? 'false' : 'undefined') : 'N/A'}`);
397
- console.error(`[QueueManager] DEBUG: Channel close reason: ${channel?._closeReason || 'N/A'}`);
393
+ console.info(`[QueueManager] ✓ Business queue exists: ${queueName}`);
394
+ } catch (checkErr) {
395
+ console.log(`[QueueManager] DEBUG: checkQueue failed for ${queueName}:`, checkErr.message);
396
+ console.log(`[QueueManager] DEBUG: Error code: ${checkErr.code}`);
398
397
 
399
- // If 406 PRECONDITION-FAILED, queue exists with different args - channel is closed, recreate it IMMEDIATELY
400
- // CRITICAL: amqplib closes channel on 406 SYNCHRONOUSLY, so we MUST recreate it to continue
401
- if (assertErr.code === 406) {
402
- console.warn(`[QueueManager] Queue ${queueName} exists with different arguments (406), channel WILL BE CLOSED. Recreating channel IMMEDIATELY...`);
398
+ // Check if channel is still open
399
+ if (!channel || channel.closed) {
400
+ throw new Error('Channel closed during checkQueue - cannot verify queue');
401
+ }
402
+
403
+ // If queue doesn't exist (404), create it using assertQueue
404
+ if (checkErr.code === 404) {
405
+ console.log(`[QueueManager] DEBUG: Queue ${queueName} doesn't exist (404), creating with assertQueue...`);
403
406
 
404
- // CRITICAL: Channel is already closed by amqplib at this point
405
- // We MUST create a new channel before continuing
406
- try {
407
- // Wait a tiny bit for channel close event to propagate
408
- await new Promise(resolve => setImmediate(resolve));
409
-
410
- // Create new channel
411
- const newChannel = await transport._connection.createChannel();
412
- newChannel._createdAt = new Date().toISOString();
413
- newChannel._closeReason = null;
414
- newChannel._lastOperation = `Recreated after 406 for ${queueName}`;
415
-
416
- // Set up error/close handlers for new channel
417
- newChannel.on('error', (err) => {
418
- console.error('[RabbitMQClient] New queue channel error:', err.message);
419
- newChannel._closeReason = `Error: ${err.message} (code: ${err.code})`;
420
- });
421
- newChannel.on('close', () => {
422
- console.error('[RabbitMQClient] New queue channel closed');
423
- console.error('[RabbitMQClient] Close reason:', newChannel._closeReason || 'Unknown');
424
- });
425
-
426
- // Update references
427
- channel = newChannel;
428
- transport.queueChannel = channel;
429
-
430
- console.log(`[QueueManager] DEBUG: Channel recreated after 406 for ${queueName}`);
431
- console.log(`[QueueManager] DEBUG: New channel created at: ${channel._createdAt}`);
432
- } catch (recreateErr) {
433
- console.error(`[QueueManager] DEBUG: Failed to recreate channel after 406:`, recreateErr.message);
434
- throw new Error(`Failed to recreate channel after 406 for ${queueName}: ${recreateErr.message}`);
407
+ if (channel && channel._lastOperation !== undefined) {
408
+ channel._lastOperation = `About to assertQueue ${queueName} (queue doesn't exist)`;
435
409
  }
436
410
 
437
- // Queue exists (just with different args) - accept it
438
- queues[queueInfo.type] = queueName;
439
- queueCreated = true;
440
- } else if (assertErr.message && assertErr.message.includes('Channel closed')) {
441
- // Channel closed error (not 406) - recreate channel
442
- console.error(`[QueueManager] DEBUG: Channel was closed during assertQueue for ${queueName} (not 406), recreating...`);
443
411
  try {
444
- await new Promise(resolve => setImmediate(resolve));
445
-
446
- const newChannel = await transport._connection.createChannel();
447
- newChannel._createdAt = new Date().toISOString();
448
- newChannel._closeReason = null;
449
- newChannel._lastOperation = `Recreated after channel closed error for ${queueName}`;
450
-
451
- newChannel.on('error', (err) => {
452
- console.error('[RabbitMQClient] New queue channel error:', err.message);
453
- newChannel._closeReason = `Error: ${err.message} (code: ${err.code})`;
454
- });
455
- newChannel.on('close', () => {
456
- console.error('[RabbitMQClient] New queue channel closed');
457
- console.error('[RabbitMQClient] Close reason:', newChannel._closeReason || 'Unknown');
458
- });
459
-
460
- channel = newChannel;
461
- transport.queueChannel = channel;
412
+ await channel.assertQueue(queueName, queueOptions);
413
+ console.log(`[QueueManager] DEBUG: assertQueue succeeded for ${queueName}`);
414
+ if (channel && channel._lastOperation !== undefined) {
415
+ channel._lastOperation = `assertQueue ${queueName} succeeded`;
416
+ }
417
+ queues[queueInfo.type] = queueName;
418
+ queueCreated = true;
419
+ console.info(`[QueueManager] Created business queue: ${queueName}`);
420
+ } catch (assertErr) {
421
+ // If channel closed during assertQueue, it's a real error
422
+ if (!channel || channel.closed) {
423
+ throw new Error(`Channel closed during assertQueue for ${queueName} - check channel management`);
424
+ }
462
425
 
463
- console.log(`[QueueManager] DEBUG: Channel recreated after channel closed error for ${queueName}`);
464
- } catch (recreateErr) {
465
- throw new Error(`Channel closed during assertQueue for ${queueName} and failed to recreate: ${recreateErr.message}`);
426
+ // If 406 PRECONDITION-FAILED, queue exists with different args (race condition?)
427
+ if (assertErr.code === 406) {
428
+ console.warn(`[QueueManager] Queue ${queueName} exists with different arguments (406 from assertQueue):`, assertErr.message);
429
+ // Channel should still be open - try checkQueue to verify
430
+ if (!channel || channel.closed) {
431
+ throw new Error('Channel closed - cannot check existing queue');
432
+ }
433
+ try {
434
+ await channel.checkQueue(queueName);
435
+ queues[queueInfo.type] = queueName;
436
+ queueCreated = true;
437
+ console.info(`[QueueManager] ✓ Business queue exists (verified): ${queueName}`);
438
+ } catch (verifyErr) {
439
+ throw new Error(`Failed to verify existing queue ${queueName}: ${verifyErr.message}`);
440
+ }
441
+ } else {
442
+ // Other errors - rethrow
443
+ throw assertErr;
444
+ }
466
445
  }
467
- // Don't set queueCreated - this is a real error, not a 406
468
- throw new Error(`Failed to create business queue ${queueName}: ${assertErr.message}`);
446
+ } else if (checkErr.code === 406) {
447
+ // Queue exists with different args (406 from checkQueue) - use it as-is
448
+ // CRITICAL: checkQueue() on 406 does NOT close channel (unlike assertQueue() on 406)
449
+ console.warn(`[QueueManager] Queue ${queueName} exists with different arguments (406 from checkQueue), using as-is:`, checkErr.message);
450
+ queues[queueInfo.type] = queueName;
451
+ queueCreated = true;
452
+ console.info(`[QueueManager] ✓ Business queue exists (different args): ${queueName}`);
469
453
  } else {
470
- // Other error - critical, cannot continue
471
- throw new Error(`Failed to create business queue ${queueName}: ${assertErr.message}`);
454
+ // Other error - rethrow
455
+ throw checkErr;
472
456
  }
473
457
  }
474
458