@onlineapps/mq-client-core 1.0.8 → 1.0.11

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/mq-client-core",
3
- "version": "1.0.8",
3
+ "version": "1.0.11",
4
4
  "description": "Core MQ client library for RabbitMQ - shared by infrastructure services and connectors",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -151,16 +151,26 @@ class RabbitMQClient extends EventEmitter {
151
151
  try {
152
152
  // Ensure queue exists if publishing directly to queue and using default exchange
153
153
  if (!exchange) {
154
- // For infrastructure queues, they should already exist with specific arguments
154
+ // CRITICAL: For infrastructure queues, they should already exist with specific arguments from queueConfig
155
155
  // Use queueChannel (regular channel) for checkQueue/assertQueue to avoid RPC reply queue issues
156
- // If queue doesn't exist (404), try to create it with default options
156
+ // If queue doesn't exist (404), we should NOT auto-create it - infrastructure queues must be created explicitly
157
+ // This prevents creating queues with wrong arguments (no TTL) which causes 406 errors later
157
158
  try {
158
159
  await this._queueChannel.checkQueue(queue);
159
160
  // Queue exists - proceed to publish
160
161
  } catch (checkErr) {
161
- // If queue doesn't exist (404), create it with default options
162
+ // If queue doesn't exist (404), this is an ERROR for infrastructure queues
163
+ // Infrastructure queues (workflow.*, registry.*) must be created explicitly with correct arguments
164
+ // We should NOT auto-create them here, as we don't have access to queueConfig in mq-client-core
162
165
  if (checkErr.code === 404) {
166
+ // Check if this is an infrastructure queue
167
+ const isInfraQueue = queue.startsWith('workflow.') || queue.startsWith('registry.');
168
+ if (isInfraQueue) {
169
+ throw new Error(`Cannot publish to infrastructure queue ${queue}: queue does not exist. Infrastructure queues must be created explicitly with correct arguments (TTL, max-length, etc.) before publishing.`);
170
+ }
171
+ // For non-infrastructure queues, allow auto-creation with default options
163
172
  const queueOptions = options.queueOptions || { durable: this._config.durable };
173
+ console.warn(`[RabbitMQClient] [mq-client-core] [PUBLISH] Auto-creating non-infrastructure queue ${queue} with default options (no TTL). This should be avoided for production.`);
164
174
  await this._queueChannel.assertQueue(queue, queueOptions);
165
175
  } else {
166
176
  // Other error - rethrow
@@ -300,6 +310,19 @@ class RabbitMQClient extends EventEmitter {
300
310
  console.log(`[RabbitMQClient] [mq-client-core] [CONSUMER] ⚠ WARNING: amqplib's consume() may internally call assertQueue() WITHOUT parameters if queue doesn't exist`);
301
311
  console.log(`[RabbitMQClient] [mq-client-core] [CONSUMER] ⚠ WARNING: We already asserted queue with correct parameters above - this should prevent auto-creation`);
302
312
 
313
+ // CRITICAL: Wrap amqplib's channel.consume() to intercept any internal assertQueue() calls
314
+ // This will help us identify if amqplib is creating the queue without TTL
315
+ const originalConsume = this._channel.consume.bind(this._channel);
316
+ const originalAssertQueue = this._channel.assertQueue.bind(this._channel);
317
+
318
+ // Intercept assertQueue() calls to log them
319
+ this._channel.assertQueue = async function(queueName, options) {
320
+ console.log(`[RabbitMQClient] [mq-client-core] [INTERCEPT] assertQueue() called for: ${queueName}`);
321
+ console.log(`[RabbitMQClient] [mq-client-core] [INTERCEPT] Options:`, JSON.stringify(options || {}, null, 2));
322
+ console.log(`[RabbitMQClient] [mq-client-core] [INTERCEPT] Stack trace:`, new Error().stack.split('\n').slice(1, 10).join('\n'));
323
+ return originalAssertQueue.call(this, queueName, options);
324
+ };
325
+
303
326
  await this._channel.consume(
304
327
  queue,
305
328
  async (msg) => {
@@ -0,0 +1,100 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * initInfrastructureQueues.js
5
+ *
6
+ * Utility for infrastructure services to initialize infrastructure queues.
7
+ * Uses queueConfig from @onlineapps/conn-infra-mq for configuration.
8
+ *
9
+ * NOTE: This is for infrastructure services (gateway, monitoring, etc.)
10
+ * Business services should use @onlineapps/conn-infra-mq connector instead.
11
+ */
12
+
13
+ /**
14
+ * Initialize all infrastructure queues
15
+ * @param {Object} channel - RabbitMQ channel
16
+ * @param {Object} options - Options
17
+ * @param {Array<string>} [options.queues] - Specific queues to create (default: all infrastructure queues)
18
+ * @param {Object} [options.logger] - Logger instance (default: console)
19
+ * @returns {Promise<void>}
20
+ */
21
+ async function initInfrastructureQueues(channel, options = {}) {
22
+ const logger = options.logger || console;
23
+
24
+ // Load queueConfig from @onlineapps/conn-infra-mq
25
+ let queueConfig;
26
+ try {
27
+ queueConfig = require('@onlineapps/conn-infra-mq/src/config/queueConfig');
28
+ } catch (requireError) {
29
+ throw new Error(`Cannot load queueConfig from @onlineapps/conn-infra-mq: ${requireError.message}. Make sure @onlineapps/conn-infra-mq is installed.`);
30
+ }
31
+
32
+ const queuesToCreate = options.queues || [
33
+ // Workflow infrastructure queues
34
+ 'workflow.init',
35
+ 'workflow.completed',
36
+ 'workflow.failed',
37
+ 'workflow.dlq',
38
+ // Registry infrastructure queues
39
+ 'registry.register',
40
+ 'registry.heartbeats'
41
+ ];
42
+
43
+ logger.log(`[QueueInit] Initializing ${queuesToCreate.length} infrastructure queues...`);
44
+
45
+ for (const queueName of queuesToCreate) {
46
+ try {
47
+ // Verify it's an infrastructure queue
48
+ if (!queueConfig.isInfrastructureQueue(queueName)) {
49
+ logger.warn(`[QueueInit] Skipping ${queueName} - not an infrastructure queue`);
50
+ continue;
51
+ }
52
+
53
+ // Get unified configuration
54
+ const config = queueConfig.getInfrastructureQueueConfig(queueName);
55
+
56
+ // CRITICAL: Check if queue exists with different arguments (406 error)
57
+ // If so, delete it and recreate with correct parameters
58
+ try {
59
+ await channel.assertQueue(queueName, {
60
+ durable: config.durable !== false,
61
+ arguments: { ...config.arguments }
62
+ });
63
+ logger.log(`[QueueInit] ✓ Created/verified infrastructure queue: ${queueName}`);
64
+ } catch (assertError) {
65
+ if (assertError.code === 406) {
66
+ // Queue exists with different arguments - delete and recreate
67
+ logger.warn(`[QueueInit] ⚠ Queue ${queueName} exists with different arguments - deleting and recreating...`);
68
+ try {
69
+ await channel.deleteQueue(queueName);
70
+ logger.log(`[QueueInit] ✓ Deleted queue ${queueName} with incorrect parameters`);
71
+ } catch (deleteError) {
72
+ logger.error(`[QueueInit] ✗ Failed to delete queue ${queueName}:`, deleteError.message);
73
+ throw new Error(`Cannot delete queue ${queueName} with incorrect parameters: ${deleteError.message}`);
74
+ }
75
+
76
+ // Recreate with correct parameters
77
+ await channel.assertQueue(queueName, {
78
+ durable: config.durable !== false,
79
+ arguments: { ...config.arguments }
80
+ });
81
+ logger.log(`[QueueInit] ✓ Recreated infrastructure queue: ${queueName} with correct parameters`);
82
+ } else {
83
+ // Other error - rethrow
84
+ logger.error(`[QueueInit] ✗ Failed to create ${queueName}:`, assertError.message);
85
+ throw assertError;
86
+ }
87
+ }
88
+ } catch (error) {
89
+ logger.error(`[QueueInit] ✗ Failed to initialize queue ${queueName}:`, error.message);
90
+ throw error;
91
+ }
92
+ }
93
+
94
+ logger.log(`[QueueInit] Infrastructure queues initialization complete`);
95
+ }
96
+
97
+ module.exports = {
98
+ initInfrastructureQueues
99
+ };
100
+