@onlineapps/mq-client-core 1.0.39 → 1.0.41
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
|
@@ -56,6 +56,9 @@ class RabbitMQClient extends EventEmitter {
|
|
|
56
56
|
this._reconnectMaxDelay = this._config.reconnectMaxDelay || 30000; // Max 30 seconds
|
|
57
57
|
this._reconnectEnabled = this._config.reconnectEnabled !== false; // Default: enabled
|
|
58
58
|
this._reconnectTimer = null;
|
|
59
|
+
// Reconnect wait timeout: at least maxReconnectAttempts × reconnectMaxDelay, minimum 60s
|
|
60
|
+
this._reconnectWaitTimeout = this._config.reconnectWaitTimeout ||
|
|
61
|
+
Math.max(60000, (this._maxReconnectAttempts * this._reconnectMaxDelay));
|
|
59
62
|
|
|
60
63
|
// Publisher retry configuration
|
|
61
64
|
this._publishRetryEnabled = this._config.publishRetryEnabled !== false; // Default: enabled
|
|
@@ -182,6 +185,61 @@ class RabbitMQClient extends EventEmitter {
|
|
|
182
185
|
return this._publishMonitor.getPrometheusMetrics();
|
|
183
186
|
}
|
|
184
187
|
|
|
188
|
+
/**
|
|
189
|
+
* Get current channel state
|
|
190
|
+
* @returns {Object} Channel state information
|
|
191
|
+
*/
|
|
192
|
+
getChannelState() {
|
|
193
|
+
return {
|
|
194
|
+
publisher: {
|
|
195
|
+
exists: !!this._channel,
|
|
196
|
+
closed: this._channel ? this._channel.closed : true,
|
|
197
|
+
ready: this._channel && !this._channel.closed
|
|
198
|
+
},
|
|
199
|
+
queue: {
|
|
200
|
+
exists: !!this._queueChannel,
|
|
201
|
+
closed: this._queueChannel ? this._queueChannel.closed : true,
|
|
202
|
+
ready: this._queueChannel && !this._queueChannel.closed
|
|
203
|
+
},
|
|
204
|
+
consumer: {
|
|
205
|
+
exists: !!this._consumerChannel,
|
|
206
|
+
closed: this._consumerChannel ? this._consumerChannel.closed : true,
|
|
207
|
+
ready: this._consumerChannel && !this._consumerChannel.closed
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Get current consumer state
|
|
214
|
+
* @returns {Object} Consumer state information
|
|
215
|
+
*/
|
|
216
|
+
getConsumerState() {
|
|
217
|
+
return {
|
|
218
|
+
tracked: this._activeConsumers.size,
|
|
219
|
+
active: Array.from(this._activeConsumers.keys())
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Get current buffer state
|
|
225
|
+
* @returns {Object} Buffer state information
|
|
226
|
+
*/
|
|
227
|
+
getBufferState() {
|
|
228
|
+
return {
|
|
229
|
+
size: this._publishLayer._buffer.size(),
|
|
230
|
+
inMemory: this._publishLayer._buffer._inMemory?.size() || 0,
|
|
231
|
+
persistent: this._publishLayer._buffer._persistent ? (this._publishLayer._buffer._persistent.size?.() || 0) : 0
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Check if client is connected
|
|
237
|
+
* @returns {boolean} True if connection exists and is not closed
|
|
238
|
+
*/
|
|
239
|
+
isConnected() {
|
|
240
|
+
return !!(this._connection && !this._connection.closed);
|
|
241
|
+
}
|
|
242
|
+
|
|
185
243
|
/**
|
|
186
244
|
* Getter for channel - provides compatibility with QueueManager
|
|
187
245
|
* Returns ConfirmChannel for publish operations
|
|
@@ -457,8 +515,8 @@ class RabbitMQClient extends EventEmitter {
|
|
|
457
515
|
const timeout = setTimeout(() => {
|
|
458
516
|
this.removeListener('reconnected', onReconnected);
|
|
459
517
|
this.removeListener('error', onError);
|
|
460
|
-
reject(new Error(
|
|
461
|
-
},
|
|
518
|
+
reject(new Error(`Reconnection timeout after ${this._reconnectWaitTimeout}ms`));
|
|
519
|
+
}, this._reconnectWaitTimeout);
|
|
462
520
|
|
|
463
521
|
const onReconnected = () => {
|
|
464
522
|
clearTimeout(timeout);
|
|
@@ -619,11 +677,12 @@ class RabbitMQClient extends EventEmitter {
|
|
|
619
677
|
* Ensure consumer channel exists and is open
|
|
620
678
|
* Auto-recreates and re-registers all consumers if closed
|
|
621
679
|
* @private
|
|
622
|
-
* @returns {Promise<
|
|
680
|
+
* @returns {Promise<{reRegistered: number, failed: number}>} - Number of consumers re-registered and failed
|
|
623
681
|
*/
|
|
624
682
|
async _ensureConsumerChannel() {
|
|
625
683
|
if (this._consumerChannel && !this._consumerChannel.closed) {
|
|
626
|
-
|
|
684
|
+
// Channel is good - return current consumer state
|
|
685
|
+
return { reRegistered: this._activeConsumers.size, failed: 0 };
|
|
627
686
|
}
|
|
628
687
|
|
|
629
688
|
if (!this._connection || this._connection.closed) {
|
|
@@ -631,7 +690,7 @@ class RabbitMQClient extends EventEmitter {
|
|
|
631
690
|
// Reconnection logic will handle this - don't throw, just return
|
|
632
691
|
// The channel will be recreated after reconnection completes
|
|
633
692
|
console.warn('[RabbitMQClient] [mq-client-core] Cannot recreate consumer channel: connection is closed (reconnection in progress)');
|
|
634
|
-
return;
|
|
693
|
+
return { reRegistered: 0, failed: this._activeConsumers.size };
|
|
635
694
|
}
|
|
636
695
|
|
|
637
696
|
try {
|
|
@@ -657,6 +716,9 @@ class RabbitMQClient extends EventEmitter {
|
|
|
657
716
|
this._attachConsumerChannelHandlers(this._consumerChannel);
|
|
658
717
|
|
|
659
718
|
// Re-register all active consumers
|
|
719
|
+
let reRegistered = 0;
|
|
720
|
+
let failed = 0;
|
|
721
|
+
|
|
660
722
|
if (this._activeConsumers.size > 0) {
|
|
661
723
|
console.log(`[RabbitMQClient] [mq-client-core] Re-registering ${this._activeConsumers.size} consumers...`);
|
|
662
724
|
for (const [queue, consumerInfo] of this._activeConsumers.entries()) {
|
|
@@ -665,18 +727,25 @@ class RabbitMQClient extends EventEmitter {
|
|
|
665
727
|
if (consumerInfo.options.queueOptions) {
|
|
666
728
|
try {
|
|
667
729
|
await this._ensureQueueChannel();
|
|
730
|
+
if (!this._queueChannel || this._queueChannel.closed) {
|
|
731
|
+
throw new Error('Queue channel is not available (connection may be closed)');
|
|
732
|
+
}
|
|
668
733
|
this._trackChannelOperation(this._queueChannel, `assertQueue ${queue} (re-register)`);
|
|
669
734
|
await this._queueChannel.assertQueue(queue, consumerInfo.options.queueOptions);
|
|
670
735
|
} catch (assertErr) {
|
|
671
736
|
if (assertErr.code === 404) {
|
|
672
737
|
console.warn(`[RabbitMQClient] [mq-client-core] Queue ${queue} does not exist, skipping consumer re-registration`);
|
|
673
738
|
this._activeConsumers.delete(queue);
|
|
739
|
+
failed++;
|
|
740
|
+
this.emit('consumer:re-registration:failed', { queue, error: 'Queue does not exist', code: 404 });
|
|
674
741
|
continue;
|
|
675
742
|
}
|
|
676
743
|
// 406 error means queue exists with different args - skip this consumer
|
|
677
744
|
if (assertErr.code === 406) {
|
|
678
745
|
console.warn(`[RabbitMQClient] [mq-client-core] Queue ${queue} exists with different args, skipping consumer re-registration`);
|
|
679
746
|
this._activeConsumers.delete(queue);
|
|
747
|
+
failed++;
|
|
748
|
+
this.emit('consumer:re-registration:failed', { queue, error: 'Queue exists with different arguments', code: 406 });
|
|
680
749
|
continue;
|
|
681
750
|
}
|
|
682
751
|
throw assertErr;
|
|
@@ -689,16 +758,21 @@ class RabbitMQClient extends EventEmitter {
|
|
|
689
758
|
{ noAck: consumerInfo.options.noAck }
|
|
690
759
|
);
|
|
691
760
|
consumerInfo.consumerTag = consumeResult.consumerTag;
|
|
761
|
+
reRegistered++;
|
|
692
762
|
console.log(`[RabbitMQClient] [mq-client-core] ✓ Re-registered consumer for queue: ${queue} (consumerTag: ${consumeResult.consumerTag})`);
|
|
693
763
|
} catch (err) {
|
|
764
|
+
failed++;
|
|
694
765
|
console.error(`[RabbitMQClient] [mq-client-core] Failed to re-register consumer for queue ${queue}:`, err.message);
|
|
695
766
|
// Remove failed consumer from tracking
|
|
696
767
|
this._activeConsumers.delete(queue);
|
|
768
|
+
// Emit event for re-registration failure
|
|
769
|
+
this.emit('consumer:re-registration:failed', { queue, error: err.message, code: err.code });
|
|
697
770
|
}
|
|
698
771
|
}
|
|
699
772
|
}
|
|
700
773
|
|
|
701
|
-
console.log(
|
|
774
|
+
console.log(`[RabbitMQClient] [mq-client-core] ✓ Consumer channel recreated (re-registered: ${reRegistered}, failed: ${failed})`);
|
|
775
|
+
return { reRegistered, failed };
|
|
702
776
|
} catch (err) {
|
|
703
777
|
this._consumerChannel = null;
|
|
704
778
|
throw new Error(`Failed to recreate consumer channel: ${err.message}`);
|
|
@@ -1010,6 +1084,13 @@ class RabbitMQClient extends EventEmitter {
|
|
|
1010
1084
|
try {
|
|
1011
1085
|
// Ensure queue channel exists and is open (auto-recreates if closed)
|
|
1012
1086
|
await this._ensureQueueChannel();
|
|
1087
|
+
if (!this._queueChannel || this._queueChannel.closed) {
|
|
1088
|
+
// Connection is closed and not reconnecting - cannot check queue
|
|
1089
|
+
throw new TransientPublishError(
|
|
1090
|
+
`Cannot check queue ${queue}: queue channel is not available (connection may be closed)`,
|
|
1091
|
+
new Error('Queue channel unavailable')
|
|
1092
|
+
);
|
|
1093
|
+
}
|
|
1013
1094
|
this._trackChannelOperation(this._queueChannel, `checkQueue ${queue}`);
|
|
1014
1095
|
await this._queueChannel.checkQueue(queue);
|
|
1015
1096
|
// Queue exists - proceed to publish
|
|
@@ -1037,12 +1118,32 @@ class RabbitMQClient extends EventEmitter {
|
|
|
1037
1118
|
// Jasný, hlasitý signál pro infra služby – fronta chybí, je to programátorská chyba
|
|
1038
1119
|
throw new QueueNotFoundError(queue, true, checkErr);
|
|
1039
1120
|
}
|
|
1121
|
+
// For non-infrastructure queues, check if queue creation is allowed before auto-creating
|
|
1122
|
+
// Check recovery scope and filter
|
|
1123
|
+
if (this._recoveryWorker && !this._recoveryWorker._queueCreationEnabled) {
|
|
1124
|
+
// Queue creation disabled for this scope (e.g., infrastructure scope)
|
|
1125
|
+
throw new QueueNotFoundError(queue, false, checkErr);
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
// Check queue creation filter if provided
|
|
1129
|
+
if (this._recoveryWorker && this._recoveryWorker._queueCreationFilter) {
|
|
1130
|
+
if (!this._recoveryWorker._queueCreationFilter(queue)) {
|
|
1131
|
+
// Queue creation filtered out - throw QueueNotFoundError so RecoveryWorker can handle it
|
|
1132
|
+
throw new QueueNotFoundError(queue, false, checkErr);
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1040
1136
|
// For non-infrastructure queues, allow auto-creation with default options
|
|
1041
1137
|
const queueOptions = options.queueOptions || { durable: this._config.durable };
|
|
1042
1138
|
console.warn(`[RabbitMQClient] [mq-client-core] [PUBLISH] Auto-creating non-infrastructure queue ${queue} with default options (no TTL). This should be avoided for production.`);
|
|
1043
1139
|
// Channel could have been nulled out by close handlers; ensure it's available
|
|
1044
|
-
|
|
1045
|
-
|
|
1140
|
+
await this._ensureQueueChannel();
|
|
1141
|
+
if (!this._queueChannel || this._queueChannel.closed) {
|
|
1142
|
+
// Connection is closed and not reconnecting - cannot create queue
|
|
1143
|
+
throw new TransientPublishError(
|
|
1144
|
+
`Cannot create queue ${queue}: queue channel is not available (connection may be closed)`,
|
|
1145
|
+
checkErr
|
|
1146
|
+
);
|
|
1046
1147
|
}
|
|
1047
1148
|
this._trackChannelOperation(this._queueChannel, `assertQueue ${queue}`);
|
|
1048
1149
|
await this._queueChannel.assertQueue(queue, queueOptions);
|
|
@@ -1184,23 +1285,11 @@ class RabbitMQClient extends EventEmitter {
|
|
|
1184
1285
|
await confirmPromise;
|
|
1185
1286
|
}
|
|
1186
1287
|
} catch (err) {
|
|
1187
|
-
//
|
|
1188
|
-
//
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
await this._ensurePublisherChannel();
|
|
1193
|
-
// Retry publish once (může znovu vyhodit – už dojde do retry/recovery vrstvy)
|
|
1194
|
-
return await this.publish(queue, buffer, options);
|
|
1195
|
-
} catch (retryErr) {
|
|
1196
|
-
console.error('[RabbitMQClient] [mq-client-core] [PUBLISH] Retry after channel recreation failed:', retryErr.message);
|
|
1197
|
-
const classifiedRetryErr = classifyPublishError(retryErr);
|
|
1198
|
-
this.emit('error', classifiedRetryErr);
|
|
1199
|
-
throw classifiedRetryErr;
|
|
1200
|
-
}
|
|
1201
|
-
}
|
|
1202
|
-
|
|
1203
|
-
// Všechny ostatní chyby projdou jednotnou klasifikací do Transient/Permanent/QueueNotFound.
|
|
1288
|
+
// CRITICAL: _publishOnce() je "single attempt" - žádný vnitřní retry
|
|
1289
|
+
// Retry logika je pouze v PublishLayer, aby byl počet pokusů předvídatelný
|
|
1290
|
+
// Pokud channel closed, vyhodíme TransientPublishError a necháme PublishLayer řešit retry
|
|
1291
|
+
|
|
1292
|
+
// Všechny chyby projdou jednotnou klasifikací do Transient/Permanent/QueueNotFound
|
|
1204
1293
|
const classifiedErr = classifyPublishError(err);
|
|
1205
1294
|
this.emit('error', classifiedErr);
|
|
1206
1295
|
throw classifiedErr;
|
|
@@ -1505,60 +1594,103 @@ class RabbitMQClient extends EventEmitter {
|
|
|
1505
1594
|
}
|
|
1506
1595
|
});
|
|
1507
1596
|
|
|
1508
|
-
// Recreate all channels
|
|
1597
|
+
// Recreate all channels with best effort - partial success is better than total failure
|
|
1509
1598
|
console.log('[RabbitMQClient] Recreating channels...');
|
|
1510
1599
|
|
|
1600
|
+
const channelState = { publisher: false, queue: false, consumer: false };
|
|
1601
|
+
let consumerReRegResult = { reRegistered: 0, failed: 0 };
|
|
1602
|
+
|
|
1511
1603
|
// Recreate publisher channel
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1604
|
+
try {
|
|
1605
|
+
this._channel = await this._connection.createConfirmChannel();
|
|
1606
|
+
this._channel._createdAt = new Date().toISOString();
|
|
1607
|
+
this._channel._closeReason = null;
|
|
1608
|
+
this._channel._lastOperation = 'Recreated via _reconnectWithBackoff()';
|
|
1609
|
+
this._channel._type = 'publisher';
|
|
1610
|
+
this._attachPublisherChannelHandlers(this._channel);
|
|
1611
|
+
channelState.publisher = true;
|
|
1612
|
+
console.log('[RabbitMQClient] ✓ Publisher channel recreated');
|
|
1613
|
+
} catch (err) {
|
|
1614
|
+
console.error('[RabbitMQClient] Failed to recreate publisher channel:', err.message);
|
|
1615
|
+
this._channel = null;
|
|
1616
|
+
// Continue - partial success is better than total failure
|
|
1617
|
+
}
|
|
1518
1618
|
|
|
1519
1619
|
// Recreate queue channel
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1620
|
+
try {
|
|
1621
|
+
this._queueChannel = await this._connection.createChannel();
|
|
1622
|
+
this._queueChannel._createdAt = new Date().toISOString();
|
|
1623
|
+
this._queueChannel._closeReason = null;
|
|
1624
|
+
this._queueChannel._lastOperation = 'Recreated via _reconnectWithBackoff()';
|
|
1625
|
+
this._queueChannel._type = 'queue';
|
|
1626
|
+
this._attachQueueChannelHandlers(this._queueChannel);
|
|
1627
|
+
channelState.queue = true;
|
|
1628
|
+
console.log('[RabbitMQClient] ✓ Queue channel recreated');
|
|
1629
|
+
} catch (err) {
|
|
1630
|
+
console.error('[RabbitMQClient] Failed to recreate queue channel:', err.message);
|
|
1631
|
+
this._queueChannel = null;
|
|
1632
|
+
// Continue - partial success is better than total failure
|
|
1633
|
+
}
|
|
1526
1634
|
|
|
1527
1635
|
// Recreate consumer channel and re-register all consumers
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1636
|
+
try {
|
|
1637
|
+
this._consumerChannel = await this._connection.createChannel();
|
|
1638
|
+
this._consumerChannel._createdAt = new Date().toISOString();
|
|
1639
|
+
this._consumerChannel._closeReason = null;
|
|
1640
|
+
this._consumerChannel._lastOperation = 'Recreated via _reconnectWithBackoff()';
|
|
1641
|
+
this._consumerChannel._type = 'consumer';
|
|
1642
|
+
this._attachConsumerChannelHandlers(this._consumerChannel);
|
|
1643
|
+
|
|
1644
|
+
// Re-register all consumers
|
|
1645
|
+
consumerReRegResult = await this._ensureConsumerChannel();
|
|
1646
|
+
channelState.consumer = true;
|
|
1647
|
+
console.log('[RabbitMQClient] ✓ Consumer channel recreated');
|
|
1648
|
+
} catch (err) {
|
|
1649
|
+
console.error('[RabbitMQClient] Failed to recreate consumer channel:', err.message);
|
|
1650
|
+
this._consumerChannel = null;
|
|
1651
|
+
// Continue - partial success is better than total failure
|
|
1652
|
+
}
|
|
1535
1653
|
|
|
1536
1654
|
// Reset reconnect state
|
|
1537
1655
|
this._reconnectAttempts = 0;
|
|
1538
1656
|
this._reconnecting = false;
|
|
1539
1657
|
|
|
1540
|
-
//
|
|
1541
|
-
//
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
}
|
|
1548
|
-
if (!this._consumerChannel || this._consumerChannel.closed) {
|
|
1549
|
-
throw new Error('Consumer channel not ready after reconnection');
|
|
1550
|
-
}
|
|
1658
|
+
// Emit reconnected event with state information
|
|
1659
|
+
// Partial success is acceptable - at least connection is re-established
|
|
1660
|
+
const reconnectState = {
|
|
1661
|
+
channels: channelState,
|
|
1662
|
+
consumers: consumerReRegResult,
|
|
1663
|
+
timestamp: new Date().toISOString()
|
|
1664
|
+
};
|
|
1551
1665
|
|
|
1552
|
-
console.log('[RabbitMQClient] ✓ Connection-level recovery completed
|
|
1553
|
-
this.emit('reconnected');
|
|
1666
|
+
console.log('[RabbitMQClient] ✓ Connection-level recovery completed', JSON.stringify(reconnectState, null, 2));
|
|
1667
|
+
this.emit('reconnected', reconnectState);
|
|
1554
1668
|
|
|
1555
1669
|
// Flush buffered messages po reconnectu
|
|
1670
|
+
let bufferFlushResult = { inMemory: 0, persistent: 0, flushed: false };
|
|
1556
1671
|
try {
|
|
1557
1672
|
const flushResult = await this._publishLayer.flushBuffered();
|
|
1558
|
-
|
|
1559
|
-
|
|
1673
|
+
bufferFlushResult = {
|
|
1674
|
+
inMemory: flushResult.inMemory || 0,
|
|
1675
|
+
persistent: flushResult.persistent || 0,
|
|
1676
|
+
flushed: true
|
|
1677
|
+
};
|
|
1678
|
+
this._publishMonitor.trackFlushed(bufferFlushResult.inMemory + bufferFlushResult.persistent);
|
|
1679
|
+
console.log(`[RabbitMQClient] ✓ Flushed ${bufferFlushResult.inMemory + bufferFlushResult.persistent} buffered messages after reconnection`);
|
|
1560
1680
|
} catch (flushErr) {
|
|
1561
1681
|
console.warn(`[RabbitMQClient] Failed to flush buffered messages after reconnection: ${flushErr.message}`);
|
|
1682
|
+
this.emit('buffer:flush:failed', { error: flushErr.message, bufferSize: this._publishLayer._buffer.size() });
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1685
|
+
// If critical channels failed, log warning but don't throw - connection is re-established
|
|
1686
|
+
if (!channelState.publisher) {
|
|
1687
|
+
console.warn('[RabbitMQClient] ⚠ Publisher channel not ready after reconnection - publish operations may fail');
|
|
1688
|
+
}
|
|
1689
|
+
if (!channelState.queue) {
|
|
1690
|
+
console.warn('[RabbitMQClient] ⚠ Queue channel not ready after reconnection - queue operations may fail');
|
|
1691
|
+
}
|
|
1692
|
+
if (!channelState.consumer) {
|
|
1693
|
+
console.warn('[RabbitMQClient] ⚠ Consumer channel not ready after reconnection - consume operations may fail');
|
|
1562
1694
|
}
|
|
1563
1695
|
|
|
1564
1696
|
return; // Success - exit reconnection loop
|
|
@@ -90,6 +90,11 @@ class RecoveryWorker {
|
|
|
90
90
|
// Use queue channel to create queue
|
|
91
91
|
await this._client._ensureQueueChannel();
|
|
92
92
|
|
|
93
|
+
// Guard: ensure queue channel is available after ensure
|
|
94
|
+
if (!this._client._queueChannel || this._client._queueChannel.closed) {
|
|
95
|
+
throw new Error(`Cannot create queue ${queueName}: queue channel is not available (connection may be closed)`);
|
|
96
|
+
}
|
|
97
|
+
|
|
93
98
|
const queueOptions = options.queueOptions || { durable: this._client._config.durable };
|
|
94
99
|
await this._client._queueChannel.assertQueue(queueName, queueOptions);
|
|
95
100
|
}
|