@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 +1 -1
- package/src/config/queueConfig.js +106 -3
- package/src/index.js +4 -3
- package/src/utils/initInfrastructureQueues.js +0 -143
package/package.json
CHANGED
|
@@ -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.') ||
|
|
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 '
|
|
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 {
|
|
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
|
-
|