@onlineapps/mq-client-core 1.0.23 → 1.0.25
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 +38 -3
- package/src/index.js +4 -3
- package/src/utils/initInfrastructureQueues.js +0 -143
package/package.json
CHANGED
|
@@ -113,6 +113,22 @@ 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
|
+
|
|
116
132
|
/**
|
|
117
133
|
* Registry infrastructure queue configurations
|
|
118
134
|
*/
|
|
@@ -197,7 +213,10 @@ module.exports = {
|
|
|
197
213
|
* @returns {boolean} True if infrastructure queue
|
|
198
214
|
*/
|
|
199
215
|
isInfrastructureQueue(queueName) {
|
|
200
|
-
return queueName.startsWith('workflow.') ||
|
|
216
|
+
return queueName.startsWith('workflow.') ||
|
|
217
|
+
queueName.startsWith('registry.') ||
|
|
218
|
+
queueName.startsWith('infrastructure.') ||
|
|
219
|
+
queueName.startsWith('validation.');
|
|
201
220
|
},
|
|
202
221
|
|
|
203
222
|
/**
|
|
@@ -255,9 +274,23 @@ module.exports = {
|
|
|
255
274
|
return config;
|
|
256
275
|
},
|
|
257
276
|
|
|
277
|
+
/**
|
|
278
|
+
* Get infrastructure health queue configuration
|
|
279
|
+
* @param {string} queueName - Queue name (e.g., 'infrastructure.health.checks')
|
|
280
|
+
* @returns {Object} Queue configuration
|
|
281
|
+
*/
|
|
282
|
+
getInfrastructureHealthQueueConfig(queueName) {
|
|
283
|
+
const parts = queueName.split('.');
|
|
284
|
+
if (parts.length < 2 || parts[0] !== 'infrastructure') {
|
|
285
|
+
throw new Error(`Invalid infrastructure health queue name: ${queueName}. Expected format: infrastructure.{name}`);
|
|
286
|
+
}
|
|
287
|
+
const name = parts.slice(1).join('.');
|
|
288
|
+
return this.getQueueConfig('infrastructure', name);
|
|
289
|
+
},
|
|
290
|
+
|
|
258
291
|
/**
|
|
259
292
|
* Get infrastructure queue configuration by queue name (auto-detect type)
|
|
260
|
-
* @param {string} queueName - Full queue name (e.g., 'workflow.init', 'registry.register')
|
|
293
|
+
* @param {string} queueName - Full queue name (e.g., 'workflow.init', 'registry.register', 'infrastructure.health.checks')
|
|
261
294
|
* @returns {Object} Queue configuration
|
|
262
295
|
*/
|
|
263
296
|
getInfrastructureQueueConfig(queueName) {
|
|
@@ -265,8 +298,10 @@ module.exports = {
|
|
|
265
298
|
return this.getWorkflowQueueConfig(queueName);
|
|
266
299
|
} else if (queueName.startsWith('registry.')) {
|
|
267
300
|
return this.getRegistryQueueConfig(queueName);
|
|
301
|
+
} else if (queueName.startsWith('infrastructure.')) {
|
|
302
|
+
return this.getInfrastructureHealthQueueConfig(queueName);
|
|
268
303
|
} else {
|
|
269
|
-
throw new Error(`Queue ${queueName} is not an infrastructure queue. Infrastructure queues must start with 'workflow.' or '
|
|
304
|
+
throw new Error(`Queue ${queueName} is not an infrastructure queue. Infrastructure queues must start with 'workflow.', 'registry.', or 'infrastructure.'`);
|
|
270
305
|
}
|
|
271
306
|
}
|
|
272
307
|
};
|
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
|
-
|