@onlineapps/mq-client-core 1.0.32 → 1.0.33
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/transports/rabbitmqClient.js +92 -11
package/package.json
CHANGED
|
@@ -94,11 +94,20 @@ class RabbitMQClient extends EventEmitter {
|
|
|
94
94
|
|
|
95
95
|
// Use ConfirmChannel to enable publisher confirms for publish operations
|
|
96
96
|
this._channel = await this._connection.createConfirmChannel();
|
|
97
|
-
|
|
97
|
+
// Enable publisher confirms explicitly
|
|
98
|
+
this._channel.on('error', (err) => {
|
|
99
|
+
console.error('[RabbitMQClient] [mq-client-core] Publisher channel error:', err.message);
|
|
100
|
+
this.emit('error', err);
|
|
101
|
+
});
|
|
98
102
|
this._channel.on('close', () => {
|
|
103
|
+
console.warn('[RabbitMQClient] [mq-client-core] Publisher channel closed');
|
|
99
104
|
// Emit a channel close error
|
|
100
105
|
this.emit('error', new Error('RabbitMQ channel closed unexpectedly'));
|
|
101
106
|
});
|
|
107
|
+
// Set up publisher confirms callback
|
|
108
|
+
this._channel.on('drain', () => {
|
|
109
|
+
console.log('[RabbitMQClient] [mq-client-core] Publisher channel drained');
|
|
110
|
+
});
|
|
102
111
|
|
|
103
112
|
// Create a separate regular channel for queue operations (assertQueue, checkQueue)
|
|
104
113
|
// This avoids RPC reply queue issues with ConfirmChannel.assertQueue()
|
|
@@ -187,8 +196,13 @@ class RabbitMQClient extends EventEmitter {
|
|
|
187
196
|
async publish(queue, buffer, options = {}) {
|
|
188
197
|
// Check channel state before publish
|
|
189
198
|
if (!this._channel || this._channel.closed) {
|
|
190
|
-
|
|
199
|
+
const errorMsg = `Cannot publish to queue "${queue}": channel is not initialized or closed (channel: ${!!this._channel}, closed: ${this._channel?.closed})`;
|
|
200
|
+
console.error('[RabbitMQClient] [mq-client-core] [PUBLISH]', errorMsg);
|
|
201
|
+
throw new Error(errorMsg);
|
|
191
202
|
}
|
|
203
|
+
|
|
204
|
+
// Log publish attempt for debugging
|
|
205
|
+
console.log(`[RabbitMQClient] [mq-client-core] [PUBLISH] Attempting to publish to queue "${queue}" (channel open: ${!this._channel.closed})`);
|
|
192
206
|
|
|
193
207
|
const exchange = this._config.exchange || '';
|
|
194
208
|
const routingKey = options.routingKey || queue;
|
|
@@ -254,23 +268,90 @@ class RabbitMQClient extends EventEmitter {
|
|
|
254
268
|
// Publish to queue using ConfirmChannel (for publisher confirms)
|
|
255
269
|
// Check channel state again before sendToQueue
|
|
256
270
|
if (this._channel.closed) {
|
|
257
|
-
throw new Error(
|
|
271
|
+
throw new Error(`Cannot publish to queue "${queue}": channel closed during operation (after queue check)`);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
console.log(`[RabbitMQClient] [mq-client-core] [PUBLISH] Sending message to queue "${queue}" (size: ${buffer.length} bytes)`);
|
|
275
|
+
|
|
276
|
+
// Use callback-based confirmation for more reliable error handling
|
|
277
|
+
const confirmPromise = new Promise((resolve, reject) => {
|
|
278
|
+
// Set up timeout
|
|
279
|
+
const timeout = setTimeout(() => {
|
|
280
|
+
reject(new Error(`Publisher confirm timeout after 5 seconds for queue "${queue}"`));
|
|
281
|
+
}, 5000);
|
|
282
|
+
|
|
283
|
+
// Send message with callback
|
|
284
|
+
const sent = this._channel.sendToQueue(queue, buffer, { persistent, headers }, (err, ok) => {
|
|
285
|
+
clearTimeout(timeout);
|
|
286
|
+
if (err) {
|
|
287
|
+
console.error(`[RabbitMQClient] [mq-client-core] [PUBLISH] Send callback error for queue "${queue}":`, err.message);
|
|
288
|
+
reject(err);
|
|
289
|
+
} else {
|
|
290
|
+
console.log(`[RabbitMQClient] [mq-client-core] [PUBLISH] ✓ Message confirmed for queue "${queue}"`);
|
|
291
|
+
resolve();
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
// If sendToQueue returns false, channel is full - wait for drain
|
|
296
|
+
if (!sent) {
|
|
297
|
+
console.log(`[RabbitMQClient] [mq-client-core] [PUBLISH] Channel full, waiting for drain for queue "${queue}"`);
|
|
298
|
+
this._channel.once('drain', () => {
|
|
299
|
+
console.log(`[RabbitMQClient] [mq-client-core] [PUBLISH] Channel drained for queue "${queue}"`);
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
try {
|
|
305
|
+
await confirmPromise;
|
|
306
|
+
} catch (confirmErr) {
|
|
307
|
+
// Check if channel was closed during confirmation
|
|
308
|
+
if (this._channel.closed) {
|
|
309
|
+
const errorMsg = `Publisher confirm failed for queue "${queue}": channel closed during confirmation. Original error: ${confirmErr.message}`;
|
|
310
|
+
console.error('[RabbitMQClient] [mq-client-core] [PUBLISH]', errorMsg);
|
|
311
|
+
throw new Error(errorMsg);
|
|
312
|
+
}
|
|
313
|
+
throw confirmErr;
|
|
258
314
|
}
|
|
259
|
-
this._channel.sendToQueue(queue, buffer, { persistent, headers });
|
|
260
315
|
} else {
|
|
261
316
|
// If exchange is specified, assert exchange and publish to it
|
|
262
317
|
if (this._channel.closed) {
|
|
263
318
|
throw new Error('Cannot publish: channel closed during operation');
|
|
264
319
|
}
|
|
265
320
|
await this._channel.assertExchange(exchange, 'direct', { durable: this._config.durable });
|
|
266
|
-
|
|
321
|
+
|
|
322
|
+
// Use callback-based confirmation for exchange publish
|
|
323
|
+
const confirmPromise = new Promise((resolve, reject) => {
|
|
324
|
+
const timeout = setTimeout(() => {
|
|
325
|
+
reject(new Error(`Publisher confirm timeout after 5 seconds for exchange "${exchange}"`));
|
|
326
|
+
}, 5000);
|
|
327
|
+
|
|
328
|
+
const sent = this._channel.publish(exchange, routingKey, buffer, { persistent, headers }, (err, ok) => {
|
|
329
|
+
clearTimeout(timeout);
|
|
330
|
+
if (err) {
|
|
331
|
+
console.error(`[RabbitMQClient] [mq-client-core] [PUBLISH] Exchange publish callback error:`, err.message);
|
|
332
|
+
reject(err);
|
|
333
|
+
} else {
|
|
334
|
+
console.log(`[RabbitMQClient] [mq-client-core] [PUBLISH] ✓ Exchange publish confirmed`);
|
|
335
|
+
resolve();
|
|
336
|
+
}
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
if (!sent) {
|
|
340
|
+
this._channel.once('drain', () => {
|
|
341
|
+
console.log(`[RabbitMQClient] [mq-client-core] [PUBLISH] Channel drained for exchange "${exchange}"`);
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
try {
|
|
347
|
+
await confirmPromise;
|
|
348
|
+
} catch (confirmErr) {
|
|
349
|
+
if (this._channel.closed) {
|
|
350
|
+
throw new Error(`Publisher confirm failed for exchange "${exchange}": channel closed during confirmation. Original error: ${confirmErr.message}`);
|
|
351
|
+
}
|
|
352
|
+
throw confirmErr;
|
|
353
|
+
}
|
|
267
354
|
}
|
|
268
|
-
// Wait for confirmation (with timeout to prevent hanging)
|
|
269
|
-
const confirmPromise = this._channel.waitForConfirms();
|
|
270
|
-
const timeoutPromise = new Promise((_, reject) => {
|
|
271
|
-
setTimeout(() => reject(new Error('Publisher confirm timeout after 5 seconds')), 5000);
|
|
272
|
-
});
|
|
273
|
-
await Promise.race([confirmPromise, timeoutPromise]);
|
|
274
355
|
} catch (err) {
|
|
275
356
|
// If channel was closed, mark it for recreation
|
|
276
357
|
if (err.message && (err.message.includes('Channel closed') || err.message.includes('channel is closed') || this._channel?.closed)) {
|