@onlineapps/mq-client-core 1.0.23 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onlineapps/mq-client-core",
3
- "version": "1.0.23",
3
+ "version": "1.0.26",
4
4
  "description": "Core MQ client library for RabbitMQ - shared by infrastructure services and connectors",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -113,6 +113,74 @@ module.exports = {
113
113
  }
114
114
  },
115
115
 
116
+ /**
117
+ * Infrastructure health tracking queue configurations
118
+ */
119
+ infrastructure: {
120
+ /**
121
+ * infrastructure.health.checks - Health check messages from infrastructure services
122
+ */
123
+ 'health.checks': {
124
+ durable: true,
125
+ arguments: {
126
+ 'x-message-ttl': 10000, // 10 seconds TTL (prevent stale data)
127
+ 'x-max-length': 1000
128
+ }
129
+ }
130
+ },
131
+
132
+ /**
133
+ * Monitoring infrastructure queue configurations
134
+ * These are dedicated queues for Monitoring service (separate from delivery queues)
135
+ */
136
+ monitoring: {
137
+ /**
138
+ * monitoring.workflow.completed - Completed workflows for monitoring
139
+ * Business services publish here for observability (separate from workflow.completed for delivery)
140
+ */
141
+ 'workflow.completed': {
142
+ durable: true,
143
+ arguments: {
144
+ 'x-message-ttl': 300000, // 5 minutes TTL
145
+ 'x-max-length': 10000
146
+ }
147
+ },
148
+
149
+ /**
150
+ * monitoring.workflow.failed - Failed workflows for monitoring
151
+ * Business services publish here for observability (separate from workflow.failed for delivery)
152
+ */
153
+ 'workflow.failed': {
154
+ durable: true,
155
+ arguments: {
156
+ 'x-message-ttl': 300000, // 5 minutes TTL
157
+ 'x-max-length': 10000
158
+ }
159
+ },
160
+
161
+ /**
162
+ * monitoring.registry.events - Registry events for monitoring
163
+ */
164
+ 'registry.events': {
165
+ durable: true,
166
+ arguments: {
167
+ 'x-message-ttl': 60000, // 1 minute TTL
168
+ 'x-max-length': 5000
169
+ }
170
+ },
171
+
172
+ /**
173
+ * monitoring.service.heartbeats - Service heartbeats for monitoring
174
+ */
175
+ 'service.heartbeats': {
176
+ durable: true,
177
+ arguments: {
178
+ 'x-message-ttl': 120000, // 2 minutes TTL
179
+ 'x-max-length': 10000
180
+ }
181
+ }
182
+ },
183
+
116
184
  /**
117
185
  * Registry infrastructure queue configurations
118
186
  */
@@ -197,7 +265,11 @@ module.exports = {
197
265
  * @returns {boolean} True if infrastructure queue
198
266
  */
199
267
  isInfrastructureQueue(queueName) {
200
- return queueName.startsWith('workflow.') || queueName.startsWith('registry.');
268
+ return queueName.startsWith('workflow.') ||
269
+ queueName.startsWith('registry.') ||
270
+ queueName.startsWith('infrastructure.') ||
271
+ queueName.startsWith('validation.') ||
272
+ queueName.startsWith('monitoring.');
201
273
  },
202
274
 
203
275
  /**
@@ -255,9 +327,36 @@ module.exports = {
255
327
  return config;
256
328
  },
257
329
 
330
+ /**
331
+ * Get infrastructure health queue configuration
332
+ * @param {string} queueName - Queue name (e.g., 'infrastructure.health.checks')
333
+ * @returns {Object} Queue configuration
334
+ */
335
+ getInfrastructureHealthQueueConfig(queueName) {
336
+ const parts = queueName.split('.');
337
+ if (parts.length < 2 || parts[0] !== 'infrastructure') {
338
+ throw new Error(`Invalid infrastructure health queue name: ${queueName}. Expected format: infrastructure.{name}`);
339
+ }
340
+ const name = parts.slice(1).join('.');
341
+ return this.getQueueConfig('infrastructure', name);
342
+ },
343
+
344
+ /**
345
+ * Get monitoring queue configuration
346
+ * @param {string} queueName - Queue name (e.g., 'monitoring.workflow.completed')
347
+ * @returns {Object} Queue configuration
348
+ */
349
+ getMonitoringQueueConfig(queueName) {
350
+ if (!queueName.startsWith('monitoring.')) {
351
+ throw new Error(`Queue ${queueName} is not a monitoring queue`);
352
+ }
353
+ const name = queueName.replace('monitoring.', '');
354
+ return this.getQueueConfig('monitoring', name);
355
+ },
356
+
258
357
  /**
259
358
  * Get infrastructure queue configuration by queue name (auto-detect type)
260
- * @param {string} queueName - Full queue name (e.g., 'workflow.init', 'registry.register')
359
+ * @param {string} queueName - Full queue name (e.g., 'workflow.init', 'registry.register', 'infrastructure.health.checks', 'monitoring.workflow.completed')
261
360
  * @returns {Object} Queue configuration
262
361
  */
263
362
  getInfrastructureQueueConfig(queueName) {
@@ -265,8 +364,12 @@ module.exports = {
265
364
  return this.getWorkflowQueueConfig(queueName);
266
365
  } else if (queueName.startsWith('registry.')) {
267
366
  return this.getRegistryQueueConfig(queueName);
367
+ } else if (queueName.startsWith('infrastructure.')) {
368
+ return this.getInfrastructureHealthQueueConfig(queueName);
369
+ } else if (queueName.startsWith('monitoring.')) {
370
+ return this.getMonitoringQueueConfig(queueName);
268
371
  } else {
269
- throw new Error(`Queue ${queueName} is not an infrastructure queue. Infrastructure queues must start with 'workflow.' or 'registry.'`);
372
+ throw new Error(`Queue ${queueName} is not an infrastructure queue. Infrastructure queues must start with 'workflow.', 'registry.', 'infrastructure.', or 'monitoring.'`);
270
373
  }
271
374
  }
272
375
  };
package/src/index.js CHANGED
@@ -5,6 +5,9 @@
5
5
  *
6
6
  * Core MQ client library for RabbitMQ - shared by infrastructure services and connectors.
7
7
  * Provides basic publish/consume functionality without business-specific features.
8
+ *
9
+ * NOTE: Infrastructure orchestration utilities (waitForInfrastructureReady, initInfrastructureQueues)
10
+ * have been moved to @onlineapps/infrastructure-tools to keep this library focused on core MQ operations.
8
11
  */
9
12
 
10
13
  const BaseClient = require('./BaseClient');
@@ -16,16 +19,14 @@ const {
16
19
  ConsumeError,
17
20
  SerializationError,
18
21
  } = require('./utils/errorHandler');
19
- const { initInfrastructureQueues } = require('./utils/initInfrastructureQueues');
20
22
 
21
23
  // Export BaseClient as default (constructor), with additional named exports
22
- // NOTE: When destructuring, use: const { initInfrastructureQueues } = require('@onlineapps/mq-client-core');
24
+ // NOTE: When destructuring, use: const { BaseClient } = require('@onlineapps/mq-client-core');
23
25
  // When using default, use: const BaseClient = require('@onlineapps/mq-client-core');
24
26
  // BaseClient must be a constructor, so we export it directly and attach other exports as properties
25
27
  module.exports = BaseClient;
26
28
  module.exports.BaseClient = BaseClient;
27
29
  module.exports.RabbitMQClient = RabbitMQClient;
28
- module.exports.initInfrastructureQueues = initInfrastructureQueues;
29
30
  module.exports.errors = {
30
31
  ValidationError,
31
32
  ConnectionError,
@@ -1,143 +0,0 @@
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
- if (!channel) {
23
- throw new Error('initInfrastructureQueues requires a valid channel');
24
- }
25
-
26
- const logger = options.logger || console;
27
- const connection = options.connection || channel.connection;
28
-
29
- // Load queueConfig from mq-client-core (spodní vrstva)
30
- // NOTE: queueConfig is part of mq-client-core because it's used by both:
31
- // - Infrastructure services (via mq-client-core)
32
- // - Business services (via conn-infra-mq connector)
33
- const queueConfig = options.queueConfig || require('../config/queueConfig');
34
-
35
- const queuesToCreate = options.queues || [
36
- // Workflow infrastructure queues
37
- 'workflow.init',
38
- 'workflow.completed',
39
- 'workflow.failed',
40
- 'workflow.dlq',
41
- // Registry infrastructure queues
42
- 'registry.register',
43
- 'registry.heartbeats'
44
- ];
45
-
46
- const watchChannel = (ch) => {
47
- if (!ch) return ch;
48
- if (!ch.__queueInitLinked) {
49
- ch.__queueInitLinked = true;
50
- ch.once('close', () => {
51
- ch.__queueInitClosed = true;
52
- logger.warn('[QueueInit] Queue channel closed');
53
- });
54
- ch.on('error', (err) => {
55
- ch.__queueInitClosed = true;
56
- logger.warn(`[QueueInit] Queue channel error: ${err.message}`);
57
- });
58
- }
59
- return ch;
60
- };
61
-
62
- let workingChannel = watchChannel(channel);
63
-
64
- const getChannel = async (forceNew = false) => {
65
- if (!forceNew && workingChannel && !workingChannel.__queueInitClosed) {
66
- return workingChannel;
67
- }
68
- if (!connection) {
69
- throw new Error('Queue channel closed and no connection reference available to recreate it');
70
- }
71
- workingChannel = watchChannel(await connection.createChannel());
72
- return workingChannel;
73
- };
74
-
75
- logger.log(`[QueueInit] Initializing ${queuesToCreate.length} infrastructure queues...`);
76
-
77
- for (const queueName of queuesToCreate) {
78
- try {
79
- // Verify it's an infrastructure queue
80
- if (!queueConfig.isInfrastructureQueue(queueName)) {
81
- logger.warn(`[QueueInit] Skipping ${queueName} - not an infrastructure queue`);
82
- continue;
83
- }
84
-
85
- // Get unified configuration
86
- const config = queueConfig.getInfrastructureQueueConfig(queueName);
87
-
88
- // CRITICAL: Check if queue exists with different arguments (406 error)
89
- // If so, delete it and recreate with correct parameters
90
- const ensureQueue = async () => {
91
- const activeChannel = await getChannel();
92
- return activeChannel.assertQueue(queueName, {
93
- durable: config.durable !== false,
94
- arguments: { ...config.arguments }
95
- });
96
- };
97
-
98
- try {
99
- await ensureQueue();
100
- logger.log(`[QueueInit] ✓ Created/verified infrastructure queue: ${queueName}`);
101
- } catch (assertError) {
102
- if (assertError.code === 406) {
103
- logger.warn(
104
- `[QueueInit] ⚠ Queue ${queueName} exists with different arguments - deleting and recreating...`
105
- );
106
- try {
107
- const deleteChannel = await getChannel(true);
108
- await deleteChannel.deleteQueue(queueName);
109
- logger.log(`[QueueInit] ✓ Deleted queue ${queueName} with incorrect parameters`);
110
- } catch (deleteError) {
111
- logger.error(
112
- `[QueueInit] ✗ Failed to delete queue ${queueName}:`,
113
- deleteError.message
114
- );
115
- throw new Error(
116
- `Cannot delete queue ${queueName} with incorrect parameters: ${deleteError.message}`
117
- );
118
- }
119
-
120
- // Recreate with correct parameters (force fresh channel to avoid closed state)
121
- await getChannel(true);
122
- await ensureQueue();
123
- logger.log(
124
- `[QueueInit] ✓ Recreated infrastructure queue: ${queueName} with correct parameters`
125
- );
126
- } else {
127
- logger.error(`[QueueInit] ✗ Failed to create ${queueName}:`, assertError.message);
128
- throw assertError;
129
- }
130
- }
131
- } catch (error) {
132
- logger.error(`[QueueInit] ✗ Failed to initialize queue ${queueName}:`, error.message);
133
- throw error;
134
- }
135
- }
136
-
137
- logger.log(`[QueueInit] Infrastructure queues initialization complete`);
138
- }
139
-
140
- module.exports = {
141
- initInfrastructureQueues
142
- };
143
-