@onlineapps/mq-client-core 1.0.26 → 1.0.28

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.26",
3
+ "version": "1.0.28",
4
4
  "description": "Core MQ client library for RabbitMQ - shared by infrastructure services and connectors",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -164,8 +164,9 @@ class RabbitMQClient extends EventEmitter {
164
164
  * @throws {Error} If publish fails or channel is not available.
165
165
  */
166
166
  async publish(queue, buffer, options = {}) {
167
- if (!this._channel) {
168
- throw new Error('Cannot publish: channel is not initialized');
167
+ // Check channel state before publish
168
+ if (!this._channel || this._channel.closed) {
169
+ throw new Error('Cannot publish: channel is not initialized or closed');
169
170
  }
170
171
 
171
172
  const exchange = this._config.exchange || '';
@@ -181,15 +182,42 @@ class RabbitMQClient extends EventEmitter {
181
182
  // If queue doesn't exist (404), we should NOT auto-create it - infrastructure queues must be created explicitly
182
183
  // This prevents creating queues with wrong arguments (no TTL) which causes 406 errors later
183
184
  try {
185
+ // Check queueChannel state
186
+ if (!this._queueChannel || this._queueChannel.closed) {
187
+ // Recreate queueChannel if closed
188
+ if (this._connection && !this._connection.closed) {
189
+ this._queueChannel = await this._connection.createChannel();
190
+ this._queueChannel.on('error', (err) => {
191
+ console.warn('[RabbitMQClient] Queue channel error:', err.message);
192
+ });
193
+ this._queueChannel.on('close', () => {
194
+ console.warn('[RabbitMQClient] Queue channel closed');
195
+ });
196
+ } else {
197
+ throw new Error('Cannot publish: connection is closed');
198
+ }
199
+ }
184
200
  await this._queueChannel.checkQueue(queue);
185
201
  // Queue exists - proceed to publish
186
202
  } catch (checkErr) {
187
203
  // If queue doesn't exist (404), this is an ERROR for infrastructure queues
188
- // Infrastructure queues (workflow.*, registry.*) must be created explicitly with correct arguments
204
+ // Infrastructure queues (workflow.*, registry.*, infrastructure.*, monitoring.*, validation.*) must be created explicitly with correct arguments
189
205
  // We should NOT auto-create them here, as we don't have access to queueConfig in mq-client-core
190
206
  if (checkErr.code === 404) {
191
- // Check if this is an infrastructure queue
192
- const isInfraQueue = queue.startsWith('workflow.') || queue.startsWith('registry.');
207
+ // Check if this is an infrastructure queue using queueConfig
208
+ let isInfraQueue = false;
209
+ try {
210
+ const queueConfig = require('../config/queueConfig');
211
+ isInfraQueue = queueConfig.isInfrastructureQueue(queue);
212
+ } catch (requireErr) {
213
+ // Fallback to pattern matching if queueConfig not available
214
+ isInfraQueue = queue.startsWith('workflow.') ||
215
+ queue.startsWith('registry.') ||
216
+ queue.startsWith('infrastructure.') ||
217
+ queue.startsWith('monitoring.') ||
218
+ queue.startsWith('validation.');
219
+ }
220
+
193
221
  if (isInfraQueue) {
194
222
  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.`);
195
223
  }
@@ -203,15 +231,31 @@ class RabbitMQClient extends EventEmitter {
203
231
  }
204
232
  }
205
233
  // Publish to queue using ConfirmChannel (for publisher confirms)
234
+ // Check channel state again before sendToQueue
235
+ if (this._channel.closed) {
236
+ throw new Error('Cannot publish: channel closed during operation');
237
+ }
206
238
  this._channel.sendToQueue(queue, buffer, { persistent, headers });
207
239
  } else {
208
240
  // If exchange is specified, assert exchange and publish to it
241
+ if (this._channel.closed) {
242
+ throw new Error('Cannot publish: channel closed during operation');
243
+ }
209
244
  await this._channel.assertExchange(exchange, 'direct', { durable: this._config.durable });
210
245
  this._channel.publish(exchange, routingKey, buffer, { persistent, headers });
211
246
  }
212
- // Wait for confirmation
213
- await this._channel.waitForConfirms();
247
+ // Wait for confirmation (with timeout to prevent hanging)
248
+ const confirmPromise = this._channel.waitForConfirms();
249
+ const timeoutPromise = new Promise((_, reject) => {
250
+ setTimeout(() => reject(new Error('Publisher confirm timeout after 5 seconds')), 5000);
251
+ });
252
+ await Promise.race([confirmPromise, timeoutPromise]);
214
253
  } catch (err) {
254
+ // If channel was closed, mark it for recreation
255
+ if (err.message && (err.message.includes('Channel closed') || err.message.includes('channel is closed') || this._channel?.closed)) {
256
+ console.warn('[RabbitMQClient] [mq-client-core] [PUBLISH] Channel closed during publish, will need to reconnect');
257
+ this._channel = null;
258
+ }
215
259
  this.emit('error', err);
216
260
  throw err;
217
261
  }
@@ -249,8 +293,10 @@ class RabbitMQClient extends EventEmitter {
249
293
  console.warn(`[RabbitMQClient] [mq-client-core] [CONSUMER] Cannot load queueConfig from @onlineapps/conn-infra-mq:`, requireErr.message);
250
294
  console.warn(`[RabbitMQClient] [mq-client-core] [CONSUMER] Using default queue options (this may cause 406 errors if queue exists with different args)`);
251
295
  }
252
- const isInfraQueue = queueConfig.isInfrastructureQueue(queue);
253
- const isBusinessQueue = queueConfig.isBusinessQueue(queue);
296
+
297
+ // Only check queue types if queueConfig is available
298
+ const isInfraQueue = queueConfig ? queueConfig.isInfrastructureQueue(queue) : false;
299
+ const isBusinessQueue = queueConfig ? queueConfig.isBusinessQueue(queue) : false;
254
300
 
255
301
  let queueOptions = options.queueOptions || { durable };
256
302