@autofleet/rabbit 4.0.2 → 4.1.0
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/dist/index.d.ts +63 -72
- package/dist/index.js +378 -393
- package/dist/index.js.map +1 -1
- package/dist/lib/consts.d.ts +2 -2
- package/dist/lib/consts.js.map +1 -1
- package/dist/lib/redis.d.ts +2 -1
- package/dist/lib/redis.js +2 -8
- package/dist/lib/redis.js.map +1 -1
- package/dist/lib/types.d.ts +11 -6
- package/dist/lib/types.js.map +1 -1
- package/dist/lib/utils.d.ts +12 -8
- package/dist/lib/utils.js +15 -13
- package/dist/lib/utils.js.map +1 -1
- package/package.json +3 -5
- package/src/index.ts +475 -538
- package/src/lib/consts.ts +8 -4
- package/src/lib/redis.ts +2 -7
- package/src/lib/types.ts +13 -8
- package/src/lib/utils.ts +27 -14
- package/src/redis-lock.d.ts +5 -3
package/src/index.ts
CHANGED
|
@@ -1,24 +1,27 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { env } from 'node:process';
|
|
2
|
+
import { setImmediate } from 'node:timers/promises';
|
|
3
|
+
import { EventEmitter, once } from 'node:events';
|
|
4
4
|
import moment from 'moment';
|
|
5
5
|
import RedisLock from 'redis-lock';
|
|
6
6
|
import {
|
|
7
|
-
AmqpConnectionManager, ChannelWrapper, connect, CreateChannelOpts,
|
|
7
|
+
type AmqpConnectionManager, type ChannelWrapper, connect, type CreateChannelOpts,
|
|
8
8
|
} from 'amqp-connection-manager';
|
|
9
|
+
// eslint-disable-next-line import/no-unresolved
|
|
10
|
+
import type { PublishOptions } from 'amqp-connection-manager/dist/types/ChannelWrapper';
|
|
9
11
|
import {
|
|
10
12
|
ConfirmChannel, ConsumeMessage, Options, Replies,
|
|
11
13
|
} from 'amqplib';
|
|
12
14
|
import { backOff } from 'exponential-backoff';
|
|
15
|
+
import type { LoggerInstanceManager } from '@autofleet/logger';
|
|
13
16
|
import {
|
|
14
|
-
getCurrentPayload, newTrace, traceTypes, createOrSetRabbitTrace, outbreak,
|
|
17
|
+
getUser, getCurrentPayload, newTrace, traceTypes, createOrSetRabbitTrace, outbreak,
|
|
15
18
|
} from '@autofleet/zehut';
|
|
16
19
|
import { randomUUID } from 'node:crypto';
|
|
17
20
|
import logger from './logger';
|
|
18
21
|
import RabbitError from './lib/rabbitError';
|
|
19
22
|
import getRedisInstance, { RedisConfig } from './lib/redis';
|
|
20
23
|
import {
|
|
21
|
-
assertExchangeFanout, getAssertVhostExponentialBackoffConfig, rand,
|
|
24
|
+
assertExchangeFanout, createDeferredPromise, getAssertVhostExponentialBackoffConfig, rand,
|
|
22
25
|
} from './lib/utils';
|
|
23
26
|
import {
|
|
24
27
|
AUTOMATION_ID_HEADER,
|
|
@@ -26,69 +29,66 @@ import {
|
|
|
26
29
|
DEFAULT_OPTIONS,
|
|
27
30
|
RETRY_HEADER,
|
|
28
31
|
TRACING_HEADER,
|
|
29
|
-
USER_OBJECT,
|
|
30
32
|
USER_TRACING_HEADER,
|
|
31
33
|
} from './lib/consts';
|
|
32
34
|
import {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
RedisLockType,
|
|
39
|
-
ExchangesCache,
|
|
35
|
+
type AssertExchangePromisesDictionary,
|
|
36
|
+
type CallbackFunction,
|
|
37
|
+
type ConnectionData,
|
|
38
|
+
type ConsumeMessageOrNull,
|
|
39
|
+
type ConsumeOptions,
|
|
40
40
|
CONSUMER_DEFAULT_OPTIONS,
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
type CustomMessageHeaders,
|
|
42
|
+
type ExchangesCache,
|
|
43
|
+
type Message,
|
|
44
|
+
type NackOptions,
|
|
45
|
+
type QueuesCache,
|
|
46
|
+
type QueueSetupPromisesDictionary,
|
|
44
47
|
} from './lib/types';
|
|
45
48
|
|
|
46
|
-
// const debug = nodeDebug('af-rabbitmq')
|
|
47
|
-
const debug = logger.debug.bind(logger);
|
|
48
|
-
|
|
49
49
|
const PUBLISH_TIMEOUT = 1000 * 10;
|
|
50
50
|
|
|
51
|
-
// TODO: [QUORUM-PHASE-3] Delete
|
|
51
|
+
// TODO: [QUORUM-PHASE-3] Delete these env vars
|
|
52
52
|
const {
|
|
53
53
|
DISABLE_QUORUM_QUEUES_CONSUME,
|
|
54
54
|
DISABLE_QUORUM_QUEUES_PUBLISH,
|
|
55
|
-
} =
|
|
55
|
+
} = env;
|
|
56
56
|
|
|
57
57
|
export interface IAfRabbitMq {
|
|
58
|
-
ack:
|
|
59
|
-
nack
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
58
|
+
ack(channel: ConfirmChannel, msg: ConsumeMessageOrNull, shouldUpdateRedisTimestamp?: boolean, releaseLock?: (() => Promise<void>) | null): (userMsg: ConsumeMessage) => Promise<void>;
|
|
59
|
+
nack(
|
|
60
|
+
channel: ConfirmChannel,
|
|
61
|
+
queue: string,
|
|
62
|
+
options: ConsumeOptions,
|
|
63
|
+
deadQueueOptions: Options.AssertQueue,
|
|
64
|
+
msg: ConsumeMessageOrNull,
|
|
65
|
+
releaseLock?: () => Promise<void>,
|
|
66
|
+
): (userMsg: ConsumeMessageOrNull, nackOptions?: NackOptions) => Promise<void> ;
|
|
67
|
+
assertChannel(options?: assertChannelOpts): Promise<ChannelWrapper>;
|
|
68
|
+
assertExchange(exchangeName: string, connection: ConnectionData): Promise<Replies.AssertExchange>
|
|
69
|
+
assertQueue(queueName: string, options?: Options.AssertQueue | null): Promise<Replies.AssertQueue>;
|
|
70
|
+
consume(queue: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<void>;
|
|
71
|
+
consumeFromExchange(queue: string, exchange: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<void>
|
|
72
|
+
publish(exchange: string, content: any, customHeaders?: PublishOptions['headers']): Promise<void>
|
|
73
|
+
sendToQueue(queue: string, content: any, options?: Options.AssertQueue | null, customHeaders?: PublishOptions['headers']): Promise<boolean | undefined>;
|
|
74
|
+
redisClient?: ReturnType<typeof getRedisInstance>;
|
|
72
75
|
}
|
|
73
76
|
|
|
74
77
|
export interface AfRabbitOptions {
|
|
75
78
|
disableReconnect?: boolean;
|
|
76
|
-
|
|
77
79
|
/**
|
|
78
80
|
* When you want your own grace-full shutdown, set this to true.
|
|
79
81
|
* @default false
|
|
80
82
|
*/
|
|
81
83
|
dontGracefulShutdown?: boolean;
|
|
82
|
-
|
|
83
84
|
/**
|
|
84
|
-
*
|
|
85
|
+
* don't retry on creation error
|
|
85
86
|
* @default false
|
|
86
87
|
*/
|
|
87
88
|
dontRetryAssert?: boolean;
|
|
88
|
-
|
|
89
89
|
rabbitHost?: string;
|
|
90
|
-
|
|
91
90
|
vhost?: string;
|
|
91
|
+
logger?: LoggerInstanceManager;
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
type newChannelOpts = {
|
|
@@ -113,13 +113,12 @@ type AfConsumer = {
|
|
|
113
113
|
const HEARTBEAT = '60';
|
|
114
114
|
|
|
115
115
|
class RabbitMq implements IAfRabbitMq {
|
|
116
|
-
static parseMsg(msg:
|
|
117
|
-
let
|
|
118
|
-
content = content.toString();
|
|
116
|
+
static parseMsg(msg: ConsumeMessage): Message {
|
|
117
|
+
let content = msg.content.toString();
|
|
119
118
|
|
|
120
119
|
try {
|
|
121
120
|
content = JSON.parse(content);
|
|
122
|
-
} catch
|
|
121
|
+
} catch { /* ignore error */ }
|
|
123
122
|
|
|
124
123
|
return {
|
|
125
124
|
...msg,
|
|
@@ -133,11 +132,10 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
133
132
|
}
|
|
134
133
|
}
|
|
135
134
|
|
|
136
|
-
static getPublishOptions(customHeaders: CustomMessageHeaders = {}) {
|
|
137
|
-
const
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
const outbreakTrace = outbreak.getCurrentContext();
|
|
135
|
+
static getPublishOptions(customHeaders: CustomMessageHeaders = {}): PublishOptions {
|
|
136
|
+
const user = getUser();
|
|
137
|
+
const traceId = getCurrentPayload()?.context?.get(TRACING_HEADER) || outbreak.getCurrentContext()?.context?.get(TRACING_HEADER);
|
|
138
|
+
|
|
141
139
|
return {
|
|
142
140
|
timestamp: moment().unix(),
|
|
143
141
|
timeout: PUBLISH_TIMEOUT,
|
|
@@ -145,113 +143,110 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
145
143
|
creationTimestamp: moment().valueOf(),
|
|
146
144
|
...customHeaders,
|
|
147
145
|
[USER_TRACING_HEADER]: user?.id,
|
|
148
|
-
[TRACING_HEADER]: traceId
|
|
146
|
+
[TRACING_HEADER]: traceId,
|
|
149
147
|
},
|
|
150
148
|
};
|
|
151
149
|
}
|
|
152
150
|
|
|
153
|
-
DISCONNECT_MSG = 'rabbit: connection disconnect';
|
|
154
|
-
|
|
155
|
-
RECONNECT_MSG = 'rabbit: connection disconnect - reconnecting';
|
|
151
|
+
readonly DISCONNECT_MSG = 'rabbit: connection disconnect';
|
|
156
152
|
|
|
157
|
-
|
|
153
|
+
readonly RECONNECT_MSG = 'rabbit: connection disconnect - reconnecting';
|
|
158
154
|
|
|
159
|
-
|
|
155
|
+
publishChannel: ChannelWrapper | null = null;
|
|
160
156
|
|
|
161
|
-
|
|
157
|
+
publishChannelSetupPromise: Promise<ChannelWrapper> | null = null;
|
|
162
158
|
|
|
163
|
-
publishConnection: ConnectionData
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
159
|
+
readonly publishConnection: ConnectionData = {
|
|
160
|
+
amqpConnection: null,
|
|
161
|
+
creatingConnection: false,
|
|
162
|
+
connectionCreatedEventName: 'publishConnectionCreated',
|
|
163
|
+
connectionFailedEventName: 'publishConnectionFailed',
|
|
164
|
+
blockReconnect: false,
|
|
165
|
+
};
|
|
168
166
|
|
|
169
|
-
|
|
167
|
+
readonly consumeConnection: ConnectionData = {
|
|
168
|
+
amqpConnection: null,
|
|
169
|
+
creatingConnection: false,
|
|
170
|
+
connectionCreatedEventName: 'consumeConnectionCreated',
|
|
171
|
+
connectionFailedEventName: 'consumeConnectionFailed',
|
|
172
|
+
blockReconnect: false,
|
|
173
|
+
};
|
|
170
174
|
|
|
171
|
-
|
|
175
|
+
readonly em: EventEmitter = new EventEmitter();
|
|
172
176
|
|
|
173
|
-
|
|
177
|
+
readonly exchanges: ExchangesCache = {};
|
|
174
178
|
|
|
175
|
-
|
|
179
|
+
readonly queues: QueuesCache = {};
|
|
176
180
|
|
|
177
|
-
|
|
181
|
+
readonly queueSetupPromises: QueueSetupPromisesDictionary = {};
|
|
178
182
|
|
|
179
|
-
|
|
183
|
+
readonly assertExchangePromises: AssertExchangePromisesDictionary = {};
|
|
180
184
|
|
|
181
|
-
redisClient
|
|
185
|
+
readonly redisClient?: ReturnType<typeof getRedisInstance>;
|
|
182
186
|
|
|
183
|
-
redisLock?:
|
|
187
|
+
readonly redisLock?: ReturnType<typeof RedisLock>;
|
|
184
188
|
|
|
185
189
|
/** Array of consumers tags used for canceling consumption */
|
|
186
|
-
consumersTags: Map<string, { channel: ConfirmChannel; consumerTag: string }
|
|
190
|
+
readonly consumersTags: Map<string, { channel: ConfirmChannel; consumerTag: string }> = new Map<string, { channel: ConfirmChannel; consumerTag: string }>();
|
|
187
191
|
|
|
188
|
-
private consumersToRegister: Array<AfConsumer> = [];
|
|
192
|
+
private readonly consumersToRegister: Array<AfConsumer> = [];
|
|
189
193
|
|
|
190
194
|
private doesVHostExist = false;
|
|
191
195
|
|
|
192
|
-
private vhost = 'quorum-vhost';
|
|
196
|
+
private readonly vhost = 'quorum-vhost';
|
|
193
197
|
|
|
194
198
|
private gracefulShutdownStarted = false;
|
|
195
199
|
|
|
196
200
|
// TODO:[QUORUM-PHASE-3] Delete the old properties that we use for the old consumers and publishers
|
|
197
|
-
oldPublishChannel: ChannelWrapper | null;
|
|
201
|
+
oldPublishChannel: ChannelWrapper | null = null;
|
|
198
202
|
|
|
199
|
-
oldPublishChannelSetupPromise: Promise<ChannelWrapper> | null;
|
|
203
|
+
oldPublishChannelSetupPromise: Promise<ChannelWrapper> | null = null;
|
|
200
204
|
|
|
201
|
-
|
|
205
|
+
readonly oldPublishConnection: ConnectionData = {
|
|
206
|
+
amqpConnection: null,
|
|
207
|
+
creatingConnection: false,
|
|
208
|
+
connectionCreatedEventName: 'oldPublishConnectionCreated',
|
|
209
|
+
connectionFailedEventName: 'oldPublishConnectionFailed',
|
|
210
|
+
blockReconnect: false,
|
|
211
|
+
};
|
|
202
212
|
|
|
203
|
-
|
|
213
|
+
readonly oldConsumeConnection: ConnectionData = {
|
|
214
|
+
amqpConnection: null,
|
|
215
|
+
creatingConnection: false,
|
|
216
|
+
connectionCreatedEventName: 'oldConsumeConnectionCreated',
|
|
217
|
+
connectionFailedEventName: 'oldConsumeConnectionFailed',
|
|
218
|
+
blockReconnect: false,
|
|
219
|
+
};
|
|
204
220
|
|
|
205
|
-
|
|
221
|
+
readonly oldEm: EventEmitter = new EventEmitter();
|
|
206
222
|
|
|
207
|
-
|
|
223
|
+
readonly oldExchanges: ExchangesCache = {};
|
|
208
224
|
|
|
209
|
-
|
|
225
|
+
readonly oldQueues: QueuesCache = {};
|
|
210
226
|
|
|
211
|
-
|
|
227
|
+
readonly oldQueueSetupPromises: QueueSetupPromisesDictionary = {};
|
|
212
228
|
|
|
213
|
-
|
|
229
|
+
readonly oldAssertExchangePromises: AssertExchangePromisesDictionary = {};
|
|
214
230
|
|
|
215
|
-
|
|
231
|
+
readonly oldConsumersTags: Map<string, { channel: ConfirmChannel; consumerTag: string }> = new Map<string, { channel: ConfirmChannel; consumerTag: string }>();
|
|
216
232
|
|
|
217
|
-
|
|
233
|
+
private readonly oldConsumersToRegister: Array<AfConsumer> = [];
|
|
218
234
|
|
|
219
|
-
|
|
235
|
+
#logger: LoggerInstanceManager;
|
|
220
236
|
|
|
221
|
-
|
|
237
|
+
constructor(public readonly options: AfRabbitOptions = {}, private readonly redisConfig?: RedisConfig) {
|
|
238
|
+
this.#logger = options?.logger || logger;
|
|
222
239
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
connectionFailedEventName: 'publishConnectionFailed',
|
|
232
|
-
blockReconnect: false,
|
|
233
|
-
};
|
|
234
|
-
this.consumeConnection = {
|
|
235
|
-
amqpConnection: null,
|
|
236
|
-
creatingConnection: false,
|
|
237
|
-
connectionCreatedEventName: 'consumeConnectionCreated',
|
|
238
|
-
connectionFailedEventName: 'consumeConnectionFailed',
|
|
239
|
-
blockReconnect: false,
|
|
240
|
-
};
|
|
241
|
-
this.creatingConnection = false;
|
|
242
|
-
this.exchanges = {};
|
|
243
|
-
this.queues = {};
|
|
244
|
-
this.queueSetupPromises = {};
|
|
245
|
-
this.assertExchangePromises = {};
|
|
246
|
-
this.consumersToRegister = [];
|
|
247
|
-
this.options = options;
|
|
248
|
-
|
|
249
|
-
this.redisClient = redisConfig && getRedisInstance(redisConfig);
|
|
250
|
-
if (this.redisClient) {
|
|
251
|
-
this.redisLock = promisify(RedisLock(this.redisClient)) as RedisLockType;
|
|
240
|
+
if (redisConfig) {
|
|
241
|
+
this.redisClient = getRedisInstance(redisConfig).on('error', (err) => {
|
|
242
|
+
this.#logger.error('rabbit: Redis error', { err, redisConfig });
|
|
243
|
+
});
|
|
244
|
+
this.redisClient.connect().catch((err) => {
|
|
245
|
+
this.#logger.error('rabbit: Failed to connect to Redis', { err, redisConfig });
|
|
246
|
+
});
|
|
247
|
+
this.redisLock = RedisLock(this.redisClient);
|
|
252
248
|
}
|
|
253
|
-
this.
|
|
254
|
-
logger.info(`rabbit: [gracefully-shutdown] adding gracefully shutdown for process.pid ${process.pid}`);
|
|
249
|
+
this.#logger.info(`rabbit: [gracefully-shutdown] adding gracefully shutdown for process.pid ${process.pid}`);
|
|
255
250
|
if (!this.options?.dontGracefulShutdown) {
|
|
256
251
|
process.on('SIGTERM', async () => {
|
|
257
252
|
await this.gracefulShutdown('SIGTERM');
|
|
@@ -260,32 +255,10 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
260
255
|
await this.gracefulShutdown('SIGINT');
|
|
261
256
|
});
|
|
262
257
|
}
|
|
258
|
+
}
|
|
263
259
|
|
|
264
|
-
|
|
265
|
-
this.
|
|
266
|
-
this.oldPublishChannel = null;
|
|
267
|
-
this.oldPublishChannelSetupPromise = null;
|
|
268
|
-
this.oldPublishConnection = {
|
|
269
|
-
amqpConnection: null,
|
|
270
|
-
creatingConnection: false,
|
|
271
|
-
connectionCreatedEventName: 'oldPublishConnectionCreated',
|
|
272
|
-
connectionFailedEventName: 'oldPublishConnectionFailed',
|
|
273
|
-
blockReconnect: false,
|
|
274
|
-
};
|
|
275
|
-
this.oldConsumeConnection = {
|
|
276
|
-
amqpConnection: null,
|
|
277
|
-
creatingConnection: false,
|
|
278
|
-
connectionCreatedEventName: 'oldConsumeConnectionCreated',
|
|
279
|
-
connectionFailedEventName: 'oldConsumeConnectionFailed',
|
|
280
|
-
blockReconnect: false,
|
|
281
|
-
};
|
|
282
|
-
this.oldCreatingConnection = false;
|
|
283
|
-
this.oldExchanges = {};
|
|
284
|
-
this.oldQueues = {};
|
|
285
|
-
this.oldQueueSetupPromises = {};
|
|
286
|
-
this.oldAssertExchangePromises = {};
|
|
287
|
-
this.oldConsumersToRegister = [];
|
|
288
|
-
this.oldConsumersTags = new Map<string, { channel: ConfirmChannel; consumerTag: string }>();
|
|
260
|
+
private getRedisKey(key: string): string {
|
|
261
|
+
return `${this.redisConfig?.prefix || ''}${key}`;
|
|
289
262
|
}
|
|
290
263
|
|
|
291
264
|
private assertVHost = async () => {
|
|
@@ -313,12 +286,12 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
313
286
|
|
|
314
287
|
if (response.status === 200) {
|
|
315
288
|
this.doesVHostExist = true;
|
|
316
|
-
logger.info('Vhost exists', { vhost: this.vhost });
|
|
289
|
+
this.#logger.info('Vhost exists', { vhost: this.vhost });
|
|
317
290
|
return;
|
|
318
291
|
}
|
|
319
292
|
|
|
320
293
|
if (response.status !== 404) {
|
|
321
|
-
logger.error('Failed to check vhost', { response });
|
|
294
|
+
this.#logger.error('Failed to check vhost', { response });
|
|
322
295
|
throw new RabbitError('Failed to check vhost');
|
|
323
296
|
}
|
|
324
297
|
|
|
@@ -329,25 +302,26 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
329
302
|
});
|
|
330
303
|
|
|
331
304
|
if (!createResponse.ok) {
|
|
332
|
-
logger.error('Failed to create vhost', { response: createResponse });
|
|
305
|
+
this.#logger.error('Failed to create vhost', { response: createResponse });
|
|
333
306
|
throw new RabbitError('Failed to create vhost');
|
|
334
307
|
}
|
|
335
308
|
|
|
336
309
|
this.doesVHostExist = true;
|
|
337
|
-
logger.info('Vhost created', { vhost: this.vhost });
|
|
310
|
+
this.#logger.info('Vhost created', { vhost: this.vhost });
|
|
338
311
|
} catch (error) {
|
|
339
|
-
logger.error('Failed to check or create vhost', { error });
|
|
312
|
+
this.#logger.error('Failed to check or create vhost', { error });
|
|
340
313
|
throw error;
|
|
341
314
|
}
|
|
342
315
|
};
|
|
343
316
|
|
|
344
317
|
private shouldConsumeMessageByTimestamp = async (msg: ConsumeMessageOrNull) => {
|
|
345
318
|
if (msg) {
|
|
346
|
-
const {
|
|
319
|
+
const { headers } = msg.properties;
|
|
347
320
|
const timestamp = headers?.creationTimestamp;
|
|
348
321
|
|
|
349
322
|
if (timestamp && headers?.redisTimestampValidationKey && this.redisClient) {
|
|
350
|
-
const
|
|
323
|
+
const key = this.getRedisKey(headers.redisTimestampValidationKey);
|
|
324
|
+
const lastMessageTimestamp = await this.redisClient.get(key);
|
|
351
325
|
return !lastMessageTimestamp || (parseInt(lastMessageTimestamp, 10) <= parseInt(timestamp, 10));
|
|
352
326
|
}
|
|
353
327
|
return true;
|
|
@@ -355,16 +329,22 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
355
329
|
return false;
|
|
356
330
|
}
|
|
357
331
|
|
|
358
|
-
public ack = (
|
|
332
|
+
public ack = (
|
|
333
|
+
channel: ConfirmChannel,
|
|
334
|
+
msg: ConsumeMessageOrNull,
|
|
335
|
+
shouldUpdateRedisTimestamp = false,
|
|
336
|
+
releaseLock: (() => Promise<void>) | null = null,
|
|
337
|
+
) => async (userMsg: ConsumeMessage) : Promise<void> => { // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
359
338
|
if (msg) {
|
|
360
|
-
debug('rabbit acking message', { deliveryTag: msg.fields.deliveryTag });
|
|
339
|
+
this.#logger.debug('rabbit acking message', { deliveryTag: msg.fields.deliveryTag });
|
|
361
340
|
await channel.ack(msg);
|
|
362
|
-
const {
|
|
341
|
+
const { headers } = msg.properties;
|
|
363
342
|
const timestamp = headers?.creationTimestamp;
|
|
364
343
|
|
|
365
344
|
if (shouldUpdateRedisTimestamp && timestamp && headers?.redisTimestampValidationKey && this.redisClient) {
|
|
366
345
|
const parsedTimestamp = parseInt(timestamp, 10);
|
|
367
|
-
|
|
346
|
+
const key = this.getRedisKey(headers.redisTimestampValidationKey);
|
|
347
|
+
await this.redisClient.set(key, parsedTimestamp, { EX: 3600 });
|
|
368
348
|
await this.unlockRedisIfNeeded(releaseLock);
|
|
369
349
|
}
|
|
370
350
|
}
|
|
@@ -373,142 +353,123 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
373
353
|
public nack = (
|
|
374
354
|
channel: ConfirmChannel,
|
|
375
355
|
queue: string,
|
|
376
|
-
options:
|
|
356
|
+
options: ConsumeOptions,
|
|
377
357
|
deadQueueOptions: Options.AssertQueue,
|
|
378
358
|
msg: ConsumeMessageOrNull,
|
|
379
|
-
releaseLock
|
|
359
|
+
releaseLock?: (() => Promise<void>) | null,
|
|
380
360
|
) => async (
|
|
381
361
|
userMsg: ConsumeMessageOrNull,
|
|
382
362
|
{
|
|
383
363
|
skipRetry = false,
|
|
384
364
|
}: NackOptions = { },
|
|
385
|
-
)
|
|
365
|
+
): Promise<void> => {
|
|
386
366
|
await this.unlockRedisIfNeeded(releaseLock);
|
|
387
|
-
if (channel
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
&& (
|
|
391
|
-
!msg.properties.headers?.[RETRY_HEADER]
|
|
392
|
-
|| parseInt(msg.properties.headers[RETRY_HEADER], 10) < options.retries
|
|
393
|
-
)
|
|
394
|
-
) {
|
|
395
|
-
await this.sendToQueue(queue, RabbitMq.parseMsg(msg).content, options, {
|
|
396
|
-
...msg.properties.headers,
|
|
397
|
-
[RETRY_HEADER]: msg.properties.headers?.[RETRY_HEADER]
|
|
398
|
-
? msg.properties.headers[RETRY_HEADER] + 1
|
|
399
|
-
: 1,
|
|
400
|
-
});
|
|
401
|
-
} else {
|
|
402
|
-
const deadQueue = `${queue}-dead`;
|
|
403
|
-
await this.sendToQueue(deadQueue, RabbitMq.parseMsg(msg).content, deadQueueOptions, {
|
|
404
|
-
...msg.properties.headers,
|
|
405
|
-
[RETRY_HEADER]: msg.properties.headers?.[RETRY_HEADER]
|
|
406
|
-
? msg.properties.headers[RETRY_HEADER] + 1
|
|
407
|
-
: 1,
|
|
408
|
-
});
|
|
409
|
-
}
|
|
410
|
-
debug('rabbit nacking message', { deliveryTag: msg.fields.deliveryTag });
|
|
411
|
-
await channel.ack(msg);
|
|
412
|
-
} else {
|
|
413
|
-
logger.error('no channel or msg', {
|
|
414
|
-
msg,
|
|
415
|
-
});
|
|
367
|
+
if (!channel || !msg) {
|
|
368
|
+
this.#logger.error('no channel or msg', { msg });
|
|
369
|
+
return;
|
|
416
370
|
}
|
|
371
|
+
const currentRetryHeader = Number.parseInt(msg.properties.headers?.[RETRY_HEADER] || '0', 10) || 0;
|
|
372
|
+
const sendToDeadQueue = skipRetry || currentRetryHeader >= options.retries!;
|
|
373
|
+
await this.sendToQueue(`${queue}${sendToDeadQueue ? '-dead' : ''}`, RabbitMq.parseMsg(msg).content, sendToDeadQueue ? deadQueueOptions : options, {
|
|
374
|
+
...msg.properties.headers,
|
|
375
|
+
[RETRY_HEADER]: currentRetryHeader + 1,
|
|
376
|
+
});
|
|
377
|
+
this.#logger.debug('rabbit nacking message', { deliveryTag: msg.fields.deliveryTag });
|
|
378
|
+
await channel.ack(msg);
|
|
417
379
|
}
|
|
418
380
|
|
|
419
|
-
async getConnection(connection: ConnectionData) {
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
if (
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
439
|
-
// @ts-ignore
|
|
440
|
-
return resolve(connectionLocal);
|
|
441
|
-
}
|
|
442
|
-
debug('rabbit: connection - reconnecting');
|
|
381
|
+
async getConnection(connection: ConnectionData): Promise<AmqpConnectionManager> {
|
|
382
|
+
const {
|
|
383
|
+
amqpConnection: connectionLocal,
|
|
384
|
+
creatingConnection,
|
|
385
|
+
connectionCreatedEventName,
|
|
386
|
+
connectionFailedEventName,
|
|
387
|
+
blockReconnect,
|
|
388
|
+
} = connection;
|
|
389
|
+
|
|
390
|
+
if (blockReconnect) {
|
|
391
|
+
this.#logger.debug('rabbit: block reconnect');
|
|
392
|
+
// @ts-expect-error we are returning undefined while the function clearly expects a connection.
|
|
393
|
+
return undefined;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
if (connectionLocal !== null) {
|
|
397
|
+
if (this.options?.disableReconnect || connectionLocal?.isConnected()) {
|
|
398
|
+
this.#logger.debug('rabbit: connection - is connected');
|
|
399
|
+
return connectionLocal;
|
|
443
400
|
}
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
401
|
+
this.#logger.debug('rabbit: connection - reconnecting');
|
|
402
|
+
}
|
|
403
|
+
if (creatingConnection) {
|
|
404
|
+
this.#logger.debug('rabbit: creating connection emi');
|
|
405
|
+
const [event, value] = await Promise.race([connectionCreatedEventName, connectionFailedEventName].map((e) => once(this.em, e).then(([result]) => [e, result] as const)));
|
|
406
|
+
if (event === connectionCreatedEventName) {
|
|
407
|
+
return value;
|
|
449
408
|
}
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
};
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
const newConnection: AmqpConnectionManager = await connect(defaultUrls, {
|
|
467
|
-
findServers,
|
|
468
|
-
});
|
|
409
|
+
throw value;
|
|
410
|
+
}
|
|
411
|
+
connection.creatingConnection = true;
|
|
412
|
+
let isResolved = false;
|
|
413
|
+
|
|
414
|
+
// It is import to use it as a function and not as a variable
|
|
415
|
+
// because of k8s changes the env variables
|
|
416
|
+
// and we want to use the new values
|
|
417
|
+
const findServers = () => {
|
|
418
|
+
const userName = process.env.RABBITMQ_USERNAME || 'guest';
|
|
419
|
+
const password = process.env.RABBITMQ_PASSWORD || 'guest';
|
|
420
|
+
const host = this.options?.rabbitHost || process.env.RABBITMQ_SERVICE_HOST || 'localhost';
|
|
421
|
+
|
|
422
|
+
this.#logger.debug('rabbit: creating connection', { host, userName, HEARTBEAT });
|
|
423
|
+
return [`amqp://${userName}:${password}@${host}/${this.vhost}?heartbeat=${HEARTBEAT}`];
|
|
424
|
+
};
|
|
469
425
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
if (!isResolved) {
|
|
474
|
-
isResolved = true;
|
|
475
|
-
reject(err);
|
|
476
|
-
this.em.emit(connectionFailedEventName, err);
|
|
477
|
-
}
|
|
478
|
-
});
|
|
426
|
+
const defaultUrls = findServers();
|
|
427
|
+
const newConnection: AmqpConnectionManager = connect(defaultUrls, { findServers });
|
|
428
|
+
connection.amqpConnection = newConnection;
|
|
479
429
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
this.em.emit(connectionFailedEventName, err);
|
|
490
|
-
}
|
|
491
|
-
});
|
|
492
|
-
|
|
493
|
-
newConnection.on('disconnect', ({ err }) => {
|
|
494
|
-
this.consumersTags.clear();
|
|
495
|
-
debug('rabbit: connection closed');
|
|
496
|
-
if (this.options?.disableReconnect) {
|
|
497
|
-
logger.error(`${this.DISCONNECT_MSG}${err && ` - ${err}`}`);
|
|
498
|
-
connection.blockReconnect = true;
|
|
499
|
-
} else {
|
|
500
|
-
logger.error(`${this.RECONNECT_MSG}${err && ` - ${err}`}`);
|
|
501
|
-
}
|
|
502
|
-
});
|
|
430
|
+
const { promise, reject, resolve } = createDeferredPromise<AmqpConnectionManager>();
|
|
431
|
+
newConnection.on('error', (err) => {
|
|
432
|
+
this.#logger.error('rabbit: connection error', { err });
|
|
433
|
+
if (!isResolved) {
|
|
434
|
+
isResolved = true;
|
|
435
|
+
reject(err);
|
|
436
|
+
this.em.emit(connectionFailedEventName, err);
|
|
437
|
+
}
|
|
438
|
+
});
|
|
503
439
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
this.
|
|
440
|
+
newConnection.on('connectFailed', (err) => {
|
|
441
|
+
this.consumersTags.clear();
|
|
442
|
+
if (typeof err.url === 'string') {
|
|
443
|
+
err.url = this.maskURL(err.url);
|
|
444
|
+
}
|
|
445
|
+
this.#logger.error('rabbit: connection connectFailed', { err, advice: 'Check if the vhost exist', vhost: this.vhost });
|
|
446
|
+
if (!isResolved) {
|
|
508
447
|
isResolved = true;
|
|
509
|
-
|
|
510
|
-
|
|
448
|
+
reject(err);
|
|
449
|
+
this.em.emit(connectionFailedEventName, err);
|
|
450
|
+
}
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
newConnection.on('disconnect', ({ err }) => {
|
|
454
|
+
this.consumersTags.clear();
|
|
455
|
+
this.#logger.debug('rabbit: connection closed');
|
|
456
|
+
if (this.options?.disableReconnect) {
|
|
457
|
+
this.#logger.error(`${this.DISCONNECT_MSG}${err && ` - ${err}`}`);
|
|
458
|
+
connection.blockReconnect = true;
|
|
459
|
+
} else {
|
|
460
|
+
this.#logger.error(`${this.RECONNECT_MSG}${err && ` - ${err}`}`);
|
|
461
|
+
}
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
newConnection.once('connect', async () => {
|
|
465
|
+
this.#logger.debug('rabbit: connection established');
|
|
466
|
+
connection.creatingConnection = false;
|
|
467
|
+
this.em.emit(connectionCreatedEventName, newConnection);
|
|
468
|
+
isResolved = true;
|
|
469
|
+
resolve(newConnection);
|
|
511
470
|
});
|
|
471
|
+
|
|
472
|
+
return promise;
|
|
512
473
|
}
|
|
513
474
|
|
|
514
475
|
async getNewChannel({
|
|
@@ -516,90 +477,92 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
516
477
|
onClose = null,
|
|
517
478
|
options = {},
|
|
518
479
|
connection,
|
|
519
|
-
}: newChannelOpts) {
|
|
480
|
+
}: newChannelOpts): Promise<ChannelWrapper> {
|
|
520
481
|
let localConnection!: AmqpConnectionManager;
|
|
521
482
|
try {
|
|
522
483
|
localConnection = await this.getConnection(connection);
|
|
523
484
|
} catch (e) {
|
|
524
|
-
logger.error(`rabbit: error on get connection for new channel ${name} `, { e });
|
|
485
|
+
this.#logger.error(`rabbit: error on get connection for new channel ${name} `, { e });
|
|
525
486
|
throw e;
|
|
526
487
|
}
|
|
527
488
|
const channel = localConnection?.createChannel({ ...options });
|
|
528
489
|
once(channel, 'close').then((args) => {
|
|
529
|
-
logger.error(`rabbit: channel ${name} closed`);
|
|
490
|
+
this.#logger.error(`rabbit: channel ${name} closed`);
|
|
530
491
|
onClose?.(args);
|
|
531
492
|
});
|
|
532
493
|
try {
|
|
533
494
|
await once(channel, 'connect');
|
|
534
|
-
debug(`rabbit: channel ${name} CONNECTED`);
|
|
495
|
+
this.#logger.debug(`rabbit: channel ${name} CONNECTED`);
|
|
535
496
|
return channel;
|
|
536
497
|
} catch (err) {
|
|
537
|
-
logger.error(`rabbit: channel error ${name} error`, { err });
|
|
498
|
+
this.#logger.error(`rabbit: channel error ${name} error`, { err });
|
|
538
499
|
throw err;
|
|
539
500
|
}
|
|
540
501
|
}
|
|
541
502
|
|
|
542
503
|
async assertChannel({ force = false, connection }: assertChannelOpts): Promise<ChannelWrapper> {
|
|
543
|
-
if (
|
|
544
|
-
this.publishChannelSetupPromise
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
504
|
+
if (this.publishChannelSetupPromise) {
|
|
505
|
+
return this.publishChannelSetupPromise;
|
|
506
|
+
}
|
|
507
|
+
const { promise, resolve, reject } = createDeferredPromise<ChannelWrapper>();
|
|
508
|
+
this.publishChannelSetupPromise = promise;
|
|
509
|
+
if (this.publishChannel && !force) {
|
|
510
|
+
resolve(this.publishChannel);
|
|
511
|
+
return promise;
|
|
512
|
+
}
|
|
548
513
|
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
});
|
|
554
|
-
if (this.publishConnection === connection) {
|
|
555
|
-
this.publishChannel = channel;
|
|
556
|
-
}
|
|
557
|
-
resolve(channel);
|
|
558
|
-
} catch (e) {
|
|
559
|
-
reject(e);
|
|
560
|
-
}
|
|
514
|
+
try {
|
|
515
|
+
const channel = await this.getNewChannel({ connection });
|
|
516
|
+
channel.on('error', (err) => {
|
|
517
|
+
this.#logger.error('rabbit: channel error', { err });
|
|
561
518
|
});
|
|
519
|
+
if (this.publishConnection === connection) {
|
|
520
|
+
this.publishChannel = channel;
|
|
521
|
+
}
|
|
522
|
+
resolve(channel);
|
|
523
|
+
} catch (e) {
|
|
524
|
+
reject(e);
|
|
562
525
|
}
|
|
563
|
-
return
|
|
526
|
+
return promise;
|
|
564
527
|
}
|
|
565
528
|
|
|
566
|
-
async assertExchange(exchangeName: string, connection: ConnectionData) {
|
|
529
|
+
async assertExchange(exchangeName: string, connection: ConnectionData): Promise<Replies.AssertExchange> {
|
|
567
530
|
const channel: ChannelWrapper = await this.assertChannel({ connection });
|
|
568
531
|
|
|
569
532
|
if (this.exchanges[exchangeName]) {
|
|
570
533
|
delete this.assertExchangePromises[exchangeName];
|
|
571
|
-
return this.exchanges[exchangeName]
|
|
534
|
+
return this.exchanges[exchangeName]!;
|
|
572
535
|
}
|
|
573
536
|
|
|
574
537
|
if (this.assertExchangePromises[exchangeName]) {
|
|
575
|
-
return this.assertExchangePromises[exchangeName]
|
|
538
|
+
return this.assertExchangePromises[exchangeName]!;
|
|
576
539
|
}
|
|
577
540
|
|
|
578
541
|
this.assertExchangePromises[exchangeName] = assertExchangeFanout(channel, exchangeName);
|
|
579
542
|
this.exchanges[exchangeName] = await this.assertExchangePromises[exchangeName];
|
|
580
|
-
return this.exchanges[exchangeName]
|
|
543
|
+
return this.exchanges[exchangeName]!;
|
|
581
544
|
}
|
|
582
545
|
|
|
583
|
-
async getQueueLength(queue: string) {
|
|
546
|
+
async getQueueLength(queue: string): Promise<Replies.AssertQueue> {
|
|
584
547
|
RabbitMq.validateName('queue', queue);
|
|
585
548
|
const { publishChannel: channel } = this;
|
|
586
549
|
if (!channel) {
|
|
587
550
|
throw new RabbitError('channel is not defined');
|
|
588
551
|
}
|
|
589
|
-
debug('rabbit: getting queue length', { queue, connected: this.publishConnection.amqpConnection?.isConnected() });
|
|
552
|
+
this.#logger.debug('rabbit: getting queue length', { queue, connected: this.publishConnection.amqpConnection?.isConnected() });
|
|
590
553
|
return channel?.checkQueue(queue);
|
|
591
554
|
}
|
|
592
555
|
|
|
593
|
-
private async deleteQueue(queue: string, connection: ConnectionData) {
|
|
556
|
+
private async deleteQueue(queue: string, connection: ConnectionData): Promise<Replies.DeleteQueue> {
|
|
594
557
|
RabbitMq.validateName('queue', queue);
|
|
595
558
|
const channel: ChannelWrapper = await this.assertChannel({ connection });
|
|
596
|
-
logger.info('rabbit: deleting queue', { queue });
|
|
559
|
+
this.#logger.info('rabbit: deleting queue', { queue });
|
|
597
560
|
const deleteQueueRes = await channel.deleteQueue(queue);
|
|
598
|
-
debug('queue deleted', deleteQueueRes);
|
|
561
|
+
this.#logger.debug('queue deleted', deleteQueueRes);
|
|
599
562
|
return deleteQueueRes;
|
|
600
563
|
}
|
|
601
564
|
|
|
602
|
-
async bindQueue(queue: string, exchange: string) {
|
|
565
|
+
async bindQueue(queue: string, exchange: string): Promise<void> {
|
|
603
566
|
const channel: ChannelWrapper = await this.assertChannel({ connection: this.publishConnection });
|
|
604
567
|
await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.bindQueue(queue, exchange, ''));
|
|
605
568
|
return channel.bindQueue(queue, exchange, '');
|
|
@@ -619,22 +582,22 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
619
582
|
};
|
|
620
583
|
try {
|
|
621
584
|
const channel: ChannelWrapper = await this.assertChannel({ connection });
|
|
622
|
-
debug('assertQueue->channel.addSetup', { queueName });
|
|
585
|
+
this.#logger.debug('assertQueue->channel.addSetup', { queueName });
|
|
623
586
|
await channel.addSetup(async (setupChannel: ConfirmChannel) => {
|
|
624
587
|
await setupChannel.assertQueue(queueName, localeOptions);
|
|
625
588
|
});
|
|
626
|
-
debug('assertQueue->channel.assertQueue', { queueName });
|
|
589
|
+
this.#logger.debug('assertQueue->channel.assertQueue', { queueName });
|
|
627
590
|
queue = await channel.assertQueue(queueName, localeOptions);
|
|
628
591
|
} catch (e) {
|
|
629
|
-
logger.error('rabbit: assertQueue error', { queueName, options, error: e });
|
|
592
|
+
this.#logger.error('rabbit: assertQueue error', { queueName, options, error: e });
|
|
630
593
|
if (!this.options?.dontRetryAssert) {
|
|
631
|
-
debug('retrying assertQueue', { queueName });
|
|
594
|
+
this.#logger.debug('retrying assertQueue', { queueName });
|
|
632
595
|
const channel = await this.assertChannel({ force: true, connection });
|
|
633
596
|
await this.deleteQueue(queueName, connection);
|
|
634
597
|
|
|
635
|
-
debug('retrying assertQueue->channel.addSetup', { queueName });
|
|
598
|
+
this.#logger.debug('retrying assertQueue->channel.addSetup', { queueName });
|
|
636
599
|
await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.assertQueue(queueName, localeOptions));
|
|
637
|
-
debug('retrying assertQueue->channel.assertQueue', { queueName });
|
|
600
|
+
this.#logger.debug('retrying assertQueue->channel.assertQueue', { queueName });
|
|
638
601
|
queue = await channel.assertQueue(queueName, localeOptions);
|
|
639
602
|
} else {
|
|
640
603
|
throw e;
|
|
@@ -661,25 +624,21 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
661
624
|
return false;
|
|
662
625
|
}
|
|
663
626
|
|
|
664
|
-
async assertQueue(queueName: string, options?: Options.AssertQueue): Promise<
|
|
627
|
+
async assertQueue(queueName: string, options?: Options.AssertQueue): Promise<Replies.AssertQueue> {
|
|
665
628
|
RabbitMq.validateName('queue', queueName);
|
|
666
629
|
if (this.queues[queueName]) {
|
|
667
630
|
delete this.queueSetupPromises[queueName];
|
|
668
|
-
return this.queues[queueName]
|
|
631
|
+
return this.queues[queueName]!;
|
|
669
632
|
}
|
|
670
633
|
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
this.queueSetupPromises[queueName] = this.setupQueue(queueName, options);
|
|
676
|
-
return this.queueSetupPromises[queueName];
|
|
634
|
+
this.queueSetupPromises[queueName] ||= this.setupQueue(queueName, options);
|
|
635
|
+
return this.queueSetupPromises[queueName]!;
|
|
677
636
|
}
|
|
678
637
|
|
|
679
|
-
private saveConsumer(queue: string, callback: CallbackFunction, options: ConsumeOptions | undefined) {
|
|
638
|
+
private saveConsumer(queue: string, callback: CallbackFunction, options: ConsumeOptions | undefined): void {
|
|
680
639
|
const isConsumerExist: boolean = this.consumersToRegister.some((consumer) => consumer.queue === queue);
|
|
681
640
|
if (!isConsumerExist) {
|
|
682
|
-
logger.info(`rabbit: consumer: ${queue} saved in consumer array`);
|
|
641
|
+
this.#logger.info(`rabbit: consumer: ${queue} saved in consumer array`);
|
|
683
642
|
this.consumersToRegister.push({
|
|
684
643
|
queue,
|
|
685
644
|
callback,
|
|
@@ -689,7 +648,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
689
648
|
}
|
|
690
649
|
|
|
691
650
|
// Used by the microservices to consume messages from the queue
|
|
692
|
-
async consume(queue: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<
|
|
651
|
+
async consume(queue: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<void> {
|
|
693
652
|
this.saveConsumerOld(queue, callback, options);
|
|
694
653
|
|
|
695
654
|
// TODO: [QUORUM-PHASE-3] Use only the implementation of consumeNew and delete consumeNew and consumeOld
|
|
@@ -703,16 +662,16 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
703
662
|
}
|
|
704
663
|
|
|
705
664
|
// TODO: [QUORUM-PHASE-3] Delete consumeNew we do not use it anymore
|
|
706
|
-
async consumeNew(queue: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<
|
|
665
|
+
async consumeNew(queue: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<void> {
|
|
707
666
|
await this.consumeFromRabbit(queue, callback, options);
|
|
708
667
|
}
|
|
709
668
|
|
|
710
669
|
// TODO: [QUORUM-PHASE-3] Delete consumeOld we do not use it anymore
|
|
711
|
-
async consumeOld(queue: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<
|
|
670
|
+
async consumeOld(queue: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<void> {
|
|
712
671
|
await this.consumeFromRabbitOld(queue, callback, options);
|
|
713
672
|
}
|
|
714
673
|
|
|
715
|
-
private async lockRedisIfNeeded(msg:
|
|
674
|
+
private async lockRedisIfNeeded(msg: ReturnType<typeof RabbitMq.parseMsg>, options: ConsumeOptions): Promise<(() => Promise<void>) | null> {
|
|
716
675
|
const { properties: { headers } } = msg;
|
|
717
676
|
const timestamp = headers?.creationTimestamp;
|
|
718
677
|
let releaseLock = null;
|
|
@@ -726,13 +685,13 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
726
685
|
return releaseLock;
|
|
727
686
|
}
|
|
728
687
|
|
|
729
|
-
private async unlockRedisIfNeeded(releaseLock
|
|
688
|
+
private async unlockRedisIfNeeded(releaseLock?: (() => Promise<void>) | null): Promise<void> {
|
|
730
689
|
if (this.redisLock && releaseLock) {
|
|
731
690
|
await releaseLock();
|
|
732
691
|
}
|
|
733
692
|
}
|
|
734
693
|
|
|
735
|
-
private async consumeFromRabbit(queue: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<
|
|
694
|
+
private async consumeFromRabbit(queue: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<void> {
|
|
736
695
|
const optionsWithDefaults = { ...DEFAULT_OPTIONS, ...options };
|
|
737
696
|
RabbitMq.validateName('queue', queue);
|
|
738
697
|
const uniqueId = randomUUID();
|
|
@@ -743,11 +702,11 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
743
702
|
if (!this.redisLock) {
|
|
744
703
|
throw new RabbitError('Usage of consumeWithLock requires RedisInstance');
|
|
745
704
|
}
|
|
746
|
-
logger.info(`rabbit: Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
|
|
705
|
+
this.#logger.info(`rabbit: Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
|
|
747
706
|
}
|
|
748
707
|
const channel = await this.getNewChannel({ connection: this.consumeConnection });
|
|
749
708
|
return channel.addSetup(async (confirmChannel: ConfirmChannel) => {
|
|
750
|
-
|
|
709
|
+
await this.assertQueue(queue, optionsWithDefaults);
|
|
751
710
|
await confirmChannel.prefetch(limit, false);
|
|
752
711
|
const { consumerTag } = await confirmChannel.consume(
|
|
753
712
|
queue,
|
|
@@ -756,9 +715,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
756
715
|
return null;
|
|
757
716
|
}
|
|
758
717
|
|
|
759
|
-
const traceId = msg.properties.headers
|
|
760
|
-
const userId = msg.properties.headers![USER_TRACING_HEADER];
|
|
761
|
-
const automationId = msg.properties.headers![AUTOMATION_ID_HEADER];
|
|
718
|
+
const { [TRACING_HEADER]: traceId, [USER_TRACING_HEADER]: userId, [AUTOMATION_ID_HEADER]: automationId } = msg.properties.headers ?? {};
|
|
762
719
|
const parsedMessage = RabbitMq.parseMsg(msg);
|
|
763
720
|
const releaseLock = await this.lockRedisIfNeeded(parsedMessage, optionsWithDefaults);
|
|
764
721
|
const trace = newTrace(traceTypes.RABBIT);
|
|
@@ -773,13 +730,13 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
773
730
|
createOrSetRabbitTrace(outbreakTrace, userId),
|
|
774
731
|
]);
|
|
775
732
|
} catch (e) {
|
|
776
|
-
logger.error('rabbit: failed to setRabbitTrace', { userId, e });
|
|
733
|
+
this.#logger.error('rabbit: failed to setRabbitTrace', { userId, e });
|
|
777
734
|
return this.nack(confirmChannel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg);
|
|
778
735
|
}
|
|
779
736
|
}
|
|
780
737
|
|
|
781
738
|
if (traceId) {
|
|
782
|
-
|
|
739
|
+
trace?.context?.set(TRACING_HEADER, traceId);
|
|
783
740
|
(outbreakTrace as any)?.context.set(TRACING_HEADER, traceId);
|
|
784
741
|
}
|
|
785
742
|
|
|
@@ -803,44 +760,44 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
803
760
|
return;
|
|
804
761
|
}
|
|
805
762
|
messageAcked = true;
|
|
806
|
-
|
|
763
|
+
await this.ack(confirmChannel, msg, true, releaseLock)(msg);
|
|
807
764
|
};
|
|
808
765
|
|
|
809
766
|
const localNack = async (_: ConsumeMessageOrNull, nackOptions: NackOptions = {}) => {
|
|
810
767
|
if (messageAcked) {
|
|
811
768
|
return;
|
|
812
769
|
}
|
|
813
|
-
debug('rabbit localNack', { messageAcked, uniqueId, deliveryTag: msg.fields.deliveryTag });
|
|
770
|
+
this.#logger.debug('rabbit localNack', { messageAcked, uniqueId, deliveryTag: msg.fields.deliveryTag });
|
|
814
771
|
messageAcked = true;
|
|
815
|
-
|
|
772
|
+
await this.nack(confirmChannel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg, nackOptions);
|
|
816
773
|
};
|
|
817
774
|
|
|
818
775
|
try {
|
|
819
|
-
await callback(
|
|
776
|
+
return await callback(
|
|
820
777
|
parsedMessage,
|
|
821
778
|
localAck,
|
|
822
779
|
localNack,
|
|
823
780
|
);
|
|
824
781
|
} catch (e) {
|
|
825
|
-
|
|
782
|
+
return localNack(msg);
|
|
826
783
|
}
|
|
827
784
|
}, CONSUMER_DEFAULT_OPTIONS,
|
|
828
785
|
);
|
|
829
786
|
if (!consumerTag) {
|
|
830
|
-
logger.error(`rabbit: failed to consume from queue ${queue}`);
|
|
787
|
+
this.#logger.error(`rabbit: failed to consume from queue ${queue}`);
|
|
831
788
|
} else {
|
|
832
|
-
logger.info(`rabbit: adding tag ${consumerTag} to the array.`);
|
|
789
|
+
this.#logger.info(`rabbit: adding tag ${consumerTag} to the array.`);
|
|
833
790
|
this.consumersTags.set(queue, { channel: confirmChannel, consumerTag });
|
|
834
791
|
}
|
|
835
792
|
});
|
|
836
793
|
}
|
|
837
794
|
|
|
838
795
|
// Used by the microservices to consume messages from the exchange
|
|
839
|
-
async consumeFromExchange(queue: string, exchange: string, callback: CallbackFunction, options?: ConsumeOptions) : Promise<
|
|
796
|
+
async consumeFromExchange(queue: string, exchange: string, callback: CallbackFunction, options?: ConsumeOptions) : Promise<void> {
|
|
840
797
|
const optionsWithDefaults = { ...DEFAULT_OPTIONS, ...options };
|
|
841
798
|
RabbitMq.validateName('exchange', exchange);
|
|
842
799
|
RabbitMq.validateName('queue', queue);
|
|
843
|
-
const { limit
|
|
800
|
+
const { limit } = optionsWithDefaults;
|
|
844
801
|
// TODO: [QUORUM-PHASE-3] Delete the if statement after all the queues are created as quorum queues
|
|
845
802
|
if (options?.isQuorumQueue !== false && DISABLE_QUORUM_QUEUES_CONSUME !== 'true') {
|
|
846
803
|
await this.saveConsumer(queue, callback, options);
|
|
@@ -890,28 +847,22 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
890
847
|
|
|
891
848
|
// Used by the microservices to publish messages to the exchange
|
|
892
849
|
// TODO: [QUORUM-PHASE-3] isQuorumQueue flag is not needed anymore because all the queues are created as quorum queues
|
|
893
|
-
async publish(exchange: string, content: any, customHeaders?:
|
|
850
|
+
async publish(exchange: string, content: any, customHeaders?: PublishOptions['headers'], isQuorumQueue = true): Promise<void> {
|
|
851
|
+
await setImmediate();
|
|
894
852
|
if (isQuorumQueue && DISABLE_QUORUM_QUEUES_PUBLISH !== 'true') {
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
Buffer.from(JSON.stringify(content)),
|
|
902
|
-
RabbitMq.getPublishOptions(customHeaders));
|
|
903
|
-
});
|
|
853
|
+
await this.assertVHost();
|
|
854
|
+
RabbitMq.validateName('exchange', exchange);
|
|
855
|
+
const channel: ChannelWrapper = await this.assertChannel({ connection: this.publishConnection });
|
|
856
|
+
await this.assertExchange(exchange, this.publishConnection);
|
|
857
|
+
await channel.publish(exchange, '', Buffer.from(JSON.stringify(content)), RabbitMq.getPublishOptions(customHeaders));
|
|
858
|
+
return;
|
|
904
859
|
}
|
|
905
860
|
|
|
906
861
|
// TODO: [QUORUM-PHASE-3] Delete the old implementation
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
await channel.publish(exchange, '',
|
|
912
|
-
Buffer.from(JSON.stringify(content)),
|
|
913
|
-
RabbitMq.getPublishOptions(customHeaders));
|
|
914
|
-
});
|
|
862
|
+
RabbitMq.validateName('exchange', exchange);
|
|
863
|
+
const channel: ChannelWrapper = await this.assertChannelOld({ connection: this.oldPublishConnection });
|
|
864
|
+
await this.assertExchangeOld(exchange, this.oldPublishConnection);
|
|
865
|
+
await channel.publish(exchange, '', Buffer.from(JSON.stringify(content)), RabbitMq.getPublishOptions(customHeaders));
|
|
915
866
|
}
|
|
916
867
|
|
|
917
868
|
// Used by the microservices to send messages to the queue
|
|
@@ -919,8 +870,8 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
919
870
|
async sendToQueue(
|
|
920
871
|
queue: string,
|
|
921
872
|
content: any,
|
|
922
|
-
options?:
|
|
923
|
-
customHeaders?:
|
|
873
|
+
options?: Options.AssertQueue,
|
|
874
|
+
customHeaders?: PublishOptions['headers'],
|
|
924
875
|
isQuorumQueue = true,
|
|
925
876
|
): Promise<boolean | undefined> {
|
|
926
877
|
if (isQuorumQueue && DISABLE_QUORUM_QUEUES_PUBLISH !== 'true') {
|
|
@@ -928,7 +879,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
928
879
|
await this.assertVHost();
|
|
929
880
|
await this.assertChannel({ connection: this.publishConnection });
|
|
930
881
|
} catch (e) {
|
|
931
|
-
logger.error(`rabbit sendToQueue: failed to send assert channel when sending to queue ${queue}`, { e });
|
|
882
|
+
this.#logger.error(`rabbit sendToQueue: failed to send assert channel when sending to queue ${queue}`, { e });
|
|
932
883
|
throw e;
|
|
933
884
|
}
|
|
934
885
|
|
|
@@ -936,26 +887,24 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
936
887
|
RabbitMq.validateName('queue', queue);
|
|
937
888
|
await this.assertQueue(queue, options);
|
|
938
889
|
} catch (e) {
|
|
939
|
-
logger.error(`rabbit sendToQueue: failed to assert queue ${queue}`, { e });
|
|
890
|
+
this.#logger.error(`rabbit sendToQueue: failed to assert queue ${queue}`, { e });
|
|
940
891
|
throw e;
|
|
941
892
|
}
|
|
942
893
|
|
|
943
894
|
try {
|
|
944
|
-
const res = await this.publishChannel?.sendToQueue(queue,
|
|
945
|
-
|
|
946
|
-
RabbitMq.getPublishOptions(customHeaders));
|
|
947
|
-
debug(`rabbit: sending to queue ${queue}`, { res });
|
|
895
|
+
const res = await this.publishChannel?.sendToQueue(queue, Buffer.from(JSON.stringify(content)), RabbitMq.getPublishOptions(customHeaders));
|
|
896
|
+
this.#logger.debug(`rabbit: sending to queue ${queue}`, { res });
|
|
948
897
|
return res;
|
|
949
898
|
} catch (e) {
|
|
950
899
|
const isConnected = await this.isConnected();
|
|
951
|
-
logger.error(`rabbit sendToQueue: failed to send to queue ${queue}, isConnected: ${isConnected}`, { e });
|
|
900
|
+
this.#logger.error(`rabbit sendToQueue: failed to send to queue ${queue}, isConnected: ${isConnected}`, { e });
|
|
952
901
|
throw e;
|
|
953
902
|
}
|
|
954
903
|
} else {
|
|
955
904
|
try {
|
|
956
905
|
await this.assertChannelOld({ connection: this.oldPublishConnection });
|
|
957
906
|
} catch (e) {
|
|
958
|
-
logger.error(`rabbit sendToQueue: failed to send assert channel when sending to queue ${queue}`, { e });
|
|
907
|
+
this.#logger.error(`rabbit sendToQueue: failed to send assert channel when sending to queue ${queue}`, { e });
|
|
959
908
|
throw e;
|
|
960
909
|
}
|
|
961
910
|
|
|
@@ -963,19 +912,17 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
963
912
|
RabbitMq.validateName('queue', queue);
|
|
964
913
|
await this.assertQueueOld(queue, options);
|
|
965
914
|
} catch (e) {
|
|
966
|
-
logger.error(`rabbit sendToQueue: failed to assert queue ${queue}`, { e });
|
|
915
|
+
this.#logger.error(`rabbit sendToQueue: failed to assert queue ${queue}`, { e });
|
|
967
916
|
throw e;
|
|
968
917
|
}
|
|
969
918
|
|
|
970
919
|
try {
|
|
971
|
-
const res = await this.oldPublishChannel?.sendToQueue(queue,
|
|
972
|
-
|
|
973
|
-
RabbitMq.getPublishOptions(customHeaders));
|
|
974
|
-
debug(`rabbit: sending to queue ${queue}`, { res });
|
|
920
|
+
const res = await this.oldPublishChannel?.sendToQueue(queue, Buffer.from(JSON.stringify(content)), RabbitMq.getPublishOptions(customHeaders));
|
|
921
|
+
this.#logger.debug(`rabbit: sending to queue ${queue}`, { res });
|
|
975
922
|
return res;
|
|
976
923
|
} catch (e) {
|
|
977
924
|
const isConnected = await this.isConnectedOld();
|
|
978
|
-
logger.error(`rabbit sendToQueue: failed to send to queue ${queue}, isConnected: ${isConnected}`, { e });
|
|
925
|
+
this.#logger.error(`rabbit sendToQueue: failed to send to queue ${queue}, isConnected: ${isConnected}`, { e });
|
|
979
926
|
throw e;
|
|
980
927
|
}
|
|
981
928
|
}
|
|
@@ -986,26 +933,23 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
986
933
|
// TODO:[QUORUM-PHASE-3] Remove the condition
|
|
987
934
|
if (!this.gracefulShutdownStarted) {
|
|
988
935
|
if (DISABLE_QUORUM_QUEUES_CONSUME !== 'true' || DISABLE_QUORUM_QUEUES_PUBLISH !== 'true') {
|
|
989
|
-
debug('rabbit: start is connected');
|
|
936
|
+
this.#logger.debug('rabbit: start is connected');
|
|
990
937
|
const [consumeConnection, publishConnection] = await Promise.all([
|
|
991
938
|
this.getConnection(this.consumeConnection),
|
|
992
939
|
this.getConnection(this.publishConnection),
|
|
993
940
|
]);
|
|
994
941
|
isConnected = consumeConnection.isConnected() && publishConnection.isConnected();
|
|
995
942
|
if (!isConnected) {
|
|
996
|
-
logger.error('rabbit: isConnected - false');
|
|
943
|
+
this.#logger.error('rabbit: isConnected - false');
|
|
997
944
|
return false;
|
|
998
945
|
}
|
|
999
946
|
try {
|
|
1000
|
-
const unRegisteredConsumers = this.consumersToRegister.filter((c
|
|
1001
|
-
const doesConsumerExist = this.consumersTags.get(c.queue);
|
|
1002
|
-
return !doesConsumerExist;
|
|
1003
|
-
});
|
|
947
|
+
const unRegisteredConsumers = this.consumersToRegister.filter((c) => !this.consumersTags.get(c.queue));
|
|
1004
948
|
|
|
1005
949
|
if (unRegisteredConsumers.length > 0) {
|
|
1006
950
|
const queueNames = unRegisteredConsumers.map((c) => c.queue);
|
|
1007
951
|
|
|
1008
|
-
logger.error('rabbit: found unregistered consumers for queues', {
|
|
952
|
+
this.#logger.error('rabbit: found unregistered consumers for queues', {
|
|
1009
953
|
count: queueNames.length,
|
|
1010
954
|
queues: queueNames,
|
|
1011
955
|
});
|
|
@@ -1015,10 +959,10 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
1015
959
|
await channel.waitForConnect();
|
|
1016
960
|
|
|
1017
961
|
await Promise.all(
|
|
1018
|
-
this.consumersToRegister.map((c
|
|
962
|
+
this.consumersToRegister.map((c) => channel.checkQueue(c.queue)),
|
|
1019
963
|
);
|
|
1020
964
|
} catch (e: RabbitError | any) {
|
|
1021
|
-
logger.error('rabbit: isConnected - false', { msg: e.message });
|
|
965
|
+
this.#logger.error('rabbit: isConnected - false', { msg: e.message });
|
|
1022
966
|
return false;
|
|
1023
967
|
}
|
|
1024
968
|
}
|
|
@@ -1026,20 +970,20 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
1026
970
|
isConnected = await this.isConnectedOld();
|
|
1027
971
|
}
|
|
1028
972
|
|
|
1029
|
-
logger.debug(`rabbit: isConnected - ${isConnected}`);
|
|
973
|
+
this.#logger.debug(`rabbit: isConnected - ${isConnected}`);
|
|
1030
974
|
return isConnected;
|
|
1031
975
|
}
|
|
1032
976
|
|
|
1033
|
-
async gracefulShutdown(signal: string)
|
|
977
|
+
async gracefulShutdown(signal: string): Promise<void> {
|
|
1034
978
|
// TODO: [QUORUM-PHASE-3] Delete the old implementation they are not needed anymore
|
|
1035
979
|
this.gracefulShutdownStarted = true;
|
|
1036
980
|
const tagsNumber = this.consumersTags.size + this.oldConsumersTags.size;
|
|
1037
|
-
logger.info(`rabbit: [gracefully-shutdown] received ${signal}! canceling #${tagsNumber} tags...`);
|
|
981
|
+
this.#logger.info(`rabbit: [gracefully-shutdown] received ${signal}! canceling #${tagsNumber} tags...`);
|
|
1038
982
|
const cancelTagPromises = [...this.consumersTags].map(
|
|
1039
|
-
([
|
|
983
|
+
([, { channel, consumerTag }]) => channel.cancel(consumerTag),
|
|
1040
984
|
);
|
|
1041
985
|
const cancelTagPromisesOld = [...this.oldConsumersTags].map(
|
|
1042
|
-
([
|
|
986
|
+
([, { channel, consumerTag }]) => channel.cancel(consumerTag),
|
|
1043
987
|
);
|
|
1044
988
|
// Clean the array to avoid race
|
|
1045
989
|
this.consumersTags.clear();
|
|
@@ -1047,13 +991,13 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
1047
991
|
const results = await Promise.allSettled([...cancelTagPromises, ...cancelTagPromisesOld]);
|
|
1048
992
|
const rejected = results.filter((p) => p.status === 'rejected');
|
|
1049
993
|
if (rejected.length > 0) {
|
|
1050
|
-
logger.warn(`rabbit: [gracefully-shutdown] #${rejected.length}/${tagsNumber} tags failed to cancel: ${rejected}`);
|
|
994
|
+
this.#logger.warn(`rabbit: [gracefully-shutdown] #${rejected.length}/${tagsNumber} tags failed to cancel: ${rejected}`);
|
|
1051
995
|
} else {
|
|
1052
|
-
logger.info('rabbit: [gracefully-shutdown] all tags successfully canceled.');
|
|
996
|
+
this.#logger.info('rabbit: [gracefully-shutdown] all tags successfully canceled.');
|
|
1053
997
|
}
|
|
1054
998
|
}
|
|
1055
999
|
|
|
1056
|
-
private async consumeFromRabbitOld(queue: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<
|
|
1000
|
+
private async consumeFromRabbitOld(queue: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<void> {
|
|
1057
1001
|
const optionsWithDefaults = { ...DEFAULT_OPTIONS, ...options };
|
|
1058
1002
|
RabbitMq.validateName('queue', queue);
|
|
1059
1003
|
const uniqueId = randomUUID();
|
|
@@ -1064,11 +1008,11 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
1064
1008
|
if (!this.redisLock) {
|
|
1065
1009
|
throw new RabbitError('Usage of consumeWithLock requires RedisInstance');
|
|
1066
1010
|
}
|
|
1067
|
-
logger.info(`rabbit: Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
|
|
1011
|
+
this.#logger.info(`rabbit: Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
|
|
1068
1012
|
}
|
|
1069
1013
|
const channel = await this.getNewChannelOld({ connection: this.oldConsumeConnection });
|
|
1070
1014
|
return channel.addSetup(async (confirmChannel: ConfirmChannel) => {
|
|
1071
|
-
|
|
1015
|
+
await this.assertQueueOld(queue, optionsWithDefaults);
|
|
1072
1016
|
await confirmChannel.prefetch(limit, false);
|
|
1073
1017
|
const { consumerTag } = await confirmChannel.consume(
|
|
1074
1018
|
queue,
|
|
@@ -1077,9 +1021,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
1077
1021
|
return null;
|
|
1078
1022
|
}
|
|
1079
1023
|
|
|
1080
|
-
const traceId = msg.properties.headers
|
|
1081
|
-
const userId = msg.properties.headers![USER_TRACING_HEADER];
|
|
1082
|
-
const automationId = msg.properties.headers![AUTOMATION_ID_HEADER];
|
|
1024
|
+
const { [TRACING_HEADER]: traceId, [USER_TRACING_HEADER]: userId, [AUTOMATION_ID_HEADER]: automationId } = msg.properties.headers ?? {};
|
|
1083
1025
|
const parsedMessage = RabbitMq.parseMsg(msg);
|
|
1084
1026
|
const releaseLock = await this.lockRedisIfNeeded(parsedMessage, optionsWithDefaults);
|
|
1085
1027
|
const trace = newTrace(traceTypes.RABBIT);
|
|
@@ -1094,13 +1036,13 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
1094
1036
|
createOrSetRabbitTrace(outbreakTrace, userId),
|
|
1095
1037
|
]);
|
|
1096
1038
|
} catch (e) {
|
|
1097
|
-
logger.error('rabbit: failed to setRabbitTrace', { userId, e });
|
|
1039
|
+
this.#logger.error('rabbit: failed to setRabbitTrace', { userId, e });
|
|
1098
1040
|
return this.nack(confirmChannel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg);
|
|
1099
1041
|
}
|
|
1100
1042
|
}
|
|
1101
1043
|
|
|
1102
1044
|
if (traceId) {
|
|
1103
|
-
|
|
1045
|
+
trace?.context?.set(TRACING_HEADER, traceId);
|
|
1104
1046
|
(outbreakTrace as any)?.context.set(TRACING_HEADER, traceId);
|
|
1105
1047
|
}
|
|
1106
1048
|
|
|
@@ -1124,33 +1066,33 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
1124
1066
|
return;
|
|
1125
1067
|
}
|
|
1126
1068
|
messageAcked = true;
|
|
1127
|
-
|
|
1069
|
+
await this.ack(confirmChannel, msg, true, releaseLock)(msg);
|
|
1128
1070
|
};
|
|
1129
1071
|
|
|
1130
1072
|
const localNack = async (_: ConsumeMessageOrNull, nackOptions: NackOptions = {}) => {
|
|
1131
1073
|
if (messageAcked) {
|
|
1132
1074
|
return;
|
|
1133
1075
|
}
|
|
1134
|
-
debug('rabbit localNack', { messageAcked, uniqueId, deliveryTag: msg.fields.deliveryTag });
|
|
1076
|
+
this.#logger.debug('rabbit localNack', { messageAcked, uniqueId, deliveryTag: msg.fields.deliveryTag });
|
|
1135
1077
|
messageAcked = true;
|
|
1136
|
-
|
|
1078
|
+
await this.nack(confirmChannel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg, nackOptions);
|
|
1137
1079
|
};
|
|
1138
1080
|
|
|
1139
1081
|
try {
|
|
1140
|
-
await callback(
|
|
1082
|
+
return await callback(
|
|
1141
1083
|
parsedMessage,
|
|
1142
1084
|
localAck,
|
|
1143
1085
|
localNack,
|
|
1144
1086
|
);
|
|
1145
1087
|
} catch (e) {
|
|
1146
|
-
|
|
1088
|
+
return localNack(msg);
|
|
1147
1089
|
}
|
|
1148
1090
|
}, CONSUMER_DEFAULT_OPTIONS,
|
|
1149
1091
|
);
|
|
1150
1092
|
if (!consumerTag) {
|
|
1151
|
-
logger.error(`rabbit: failed to consume from queue ${queue} old`);
|
|
1093
|
+
this.#logger.error(`rabbit: failed to consume from queue ${queue} old`);
|
|
1152
1094
|
} else {
|
|
1153
|
-
logger.info(`rabbit: adding tag ${consumerTag} to the array old`);
|
|
1095
|
+
this.#logger.info(`rabbit: adding tag ${consumerTag} to the array old`);
|
|
1154
1096
|
this.oldConsumersTags.set(queue, { channel: confirmChannel, consumerTag });
|
|
1155
1097
|
}
|
|
1156
1098
|
});
|
|
@@ -1162,12 +1104,12 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
1162
1104
|
onClose = null,
|
|
1163
1105
|
options = {},
|
|
1164
1106
|
connection,
|
|
1165
|
-
}: newChannelOpts) {
|
|
1107
|
+
}: newChannelOpts): Promise<ChannelWrapper> {
|
|
1166
1108
|
let localConnection!: AmqpConnectionManager;
|
|
1167
1109
|
try {
|
|
1168
1110
|
localConnection = await this.getConnectionOld(connection);
|
|
1169
1111
|
} catch (e) {
|
|
1170
|
-
logger.error(`rabbit: error on get connection for new channel ${name} `, { e });
|
|
1112
|
+
this.#logger.error(`rabbit: error on get connection for new channel ${name} `, { e });
|
|
1171
1113
|
throw e;
|
|
1172
1114
|
}
|
|
1173
1115
|
|
|
@@ -1177,116 +1119,116 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
1177
1119
|
|
|
1178
1120
|
const channel = localConnection?.createChannel({ ...options });
|
|
1179
1121
|
once(channel, 'close').then((args) => {
|
|
1180
|
-
logger.error(`rabbit: channel ${name} closed`);
|
|
1122
|
+
this.#logger.error(`rabbit: channel ${name} closed`);
|
|
1181
1123
|
onClose?.(args);
|
|
1182
1124
|
});
|
|
1183
1125
|
try {
|
|
1184
1126
|
await once(channel, 'connect');
|
|
1185
|
-
debug(`rabbit: channel ${name} CONNECTED`);
|
|
1127
|
+
this.#logger.debug(`rabbit: channel ${name} CONNECTED`);
|
|
1186
1128
|
return channel;
|
|
1187
1129
|
} catch (err) {
|
|
1188
|
-
logger.error(`rabbit: channel error ${name} error`, { err });
|
|
1130
|
+
this.#logger.error(`rabbit: channel error ${name} error`, { err });
|
|
1189
1131
|
throw err;
|
|
1190
1132
|
}
|
|
1191
1133
|
}
|
|
1192
1134
|
|
|
1193
|
-
async getConnectionOld(connection: ConnectionData) {
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1135
|
+
async getConnectionOld(connection: ConnectionData): Promise<AmqpConnectionManager> {
|
|
1136
|
+
const {
|
|
1137
|
+
amqpConnection: connectionLocal,
|
|
1138
|
+
creatingConnection,
|
|
1139
|
+
connectionCreatedEventName,
|
|
1140
|
+
connectionFailedEventName,
|
|
1141
|
+
blockReconnect,
|
|
1142
|
+
} = connection;
|
|
1143
|
+
|
|
1144
|
+
if (blockReconnect) {
|
|
1145
|
+
this.#logger.debug('rabbit: block reconnect');
|
|
1146
|
+
// @ts-expect-error we are returning undefined while the function clearly expects a connection.
|
|
1147
|
+
return undefined;
|
|
1148
|
+
}
|
|
1149
|
+
if (connectionLocal !== null) {
|
|
1150
|
+
if (this.options?.disableReconnect || connectionLocal?.isConnected()) {
|
|
1151
|
+
this.#logger.debug('rabbit: connection - is connected');
|
|
1205
1152
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
1206
1153
|
// @ts-ignore
|
|
1207
|
-
return
|
|
1208
|
-
}
|
|
1209
|
-
if (connectionLocal !== null) {
|
|
1210
|
-
if (this.options?.disableReconnect || connectionLocal?.isConnected()) {
|
|
1211
|
-
debug('rabbit: connection - is connected');
|
|
1212
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
1213
|
-
// @ts-ignore
|
|
1214
|
-
return resolve(connectionLocal);
|
|
1215
|
-
}
|
|
1216
|
-
debug('rabbit: connection - reconnecting');
|
|
1154
|
+
return connectionLocal;
|
|
1217
1155
|
}
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1156
|
+
this.#logger.debug('rabbit: connection - reconnecting');
|
|
1157
|
+
}
|
|
1158
|
+
if (creatingConnection) {
|
|
1159
|
+
const [event, value] = await Promise.race([connectionCreatedEventName, connectionFailedEventName].map((e) => once(this.oldEm, e).then(([result]) => [e, result] as const)));
|
|
1160
|
+
if (event === connectionCreatedEventName) {
|
|
1161
|
+
return value;
|
|
1223
1162
|
}
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
// because of k8s changes the env variables
|
|
1229
|
-
// and we want to use the new values
|
|
1230
|
-
const findServers = () => {
|
|
1231
|
-
const userName = process.env.RABBITMQ_USERNAME || 'guest';
|
|
1232
|
-
const password = process.env.RABBITMQ_PASSWORD || 'guest';
|
|
1233
|
-
const host = this.options?.rabbitHost || process.env.RABBITMQ_SERVICE_HOST || 'localhost';
|
|
1163
|
+
throw value;
|
|
1164
|
+
}
|
|
1165
|
+
connection.creatingConnection = true;
|
|
1166
|
+
let isResolved = false;
|
|
1234
1167
|
|
|
1235
|
-
|
|
1168
|
+
// It is import to use it as a function and not as a variable
|
|
1169
|
+
// because of k8s changes the env variables
|
|
1170
|
+
// and we want to use the new values
|
|
1171
|
+
const findServers = () => {
|
|
1172
|
+
const userName = process.env.RABBITMQ_USERNAME || 'guest';
|
|
1173
|
+
const password = process.env.RABBITMQ_PASSWORD || 'guest';
|
|
1174
|
+
const host = this.options?.rabbitHost || process.env.RABBITMQ_SERVICE_HOST || 'localhost';
|
|
1236
1175
|
|
|
1237
|
-
|
|
1238
|
-
};
|
|
1176
|
+
this.#logger.debug('rabbit: creating connection', { host, userName, HEARTBEAT });
|
|
1239
1177
|
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
findServers,
|
|
1243
|
-
});
|
|
1178
|
+
return [`amqp://${userName}:${password}@${host}?heartbeat=${HEARTBEAT}`];
|
|
1179
|
+
};
|
|
1244
1180
|
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
logger.error('rabbit: connection error', { err });
|
|
1248
|
-
if (!isResolved) {
|
|
1249
|
-
isResolved = true;
|
|
1250
|
-
reject(err);
|
|
1251
|
-
this.oldEm.emit(connectionFailedEventName, err);
|
|
1252
|
-
}
|
|
1253
|
-
});
|
|
1181
|
+
const defaultUrls = findServers();
|
|
1182
|
+
const newConnection: AmqpConnectionManager = await connect(defaultUrls, { findServers });
|
|
1254
1183
|
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
if (typeof err.url === 'string') {
|
|
1258
|
-
err.url = this.maskURL(err.url);
|
|
1259
|
-
}
|
|
1260
|
-
logger.error('rabbit: connection connectFailed', { err });
|
|
1261
|
-
if (!isResolved) {
|
|
1262
|
-
isResolved = true;
|
|
1263
|
-
reject(err);
|
|
1264
|
-
this.oldEm.emit(connectionFailedEventName, err);
|
|
1265
|
-
}
|
|
1266
|
-
});
|
|
1184
|
+
connection.amqpConnection = newConnection;
|
|
1185
|
+
const { promise, reject, resolve } = createDeferredPromise<AmqpConnectionManager>();
|
|
1267
1186
|
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
}
|
|
1277
|
-
});
|
|
1187
|
+
newConnection.on('error', (err) => {
|
|
1188
|
+
this.#logger.error('rabbit: connection error', { err });
|
|
1189
|
+
if (!isResolved) {
|
|
1190
|
+
isResolved = true;
|
|
1191
|
+
reject(err);
|
|
1192
|
+
this.oldEm.emit(connectionFailedEventName, err);
|
|
1193
|
+
}
|
|
1194
|
+
});
|
|
1278
1195
|
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
this.
|
|
1196
|
+
newConnection.on('connectFailed', (err) => {
|
|
1197
|
+
this.oldConsumersTags.clear();
|
|
1198
|
+
if (typeof err.url === 'string') {
|
|
1199
|
+
err.url = this.maskURL(err.url);
|
|
1200
|
+
}
|
|
1201
|
+
logger.error('rabbit: connection connectFailed', { err });
|
|
1202
|
+
if (!isResolved) {
|
|
1283
1203
|
isResolved = true;
|
|
1284
|
-
|
|
1285
|
-
|
|
1204
|
+
reject(err);
|
|
1205
|
+
this.oldEm.emit(connectionFailedEventName, err);
|
|
1206
|
+
}
|
|
1286
1207
|
});
|
|
1208
|
+
|
|
1209
|
+
newConnection.on('disconnect', ({ err }) => {
|
|
1210
|
+
this.oldConsumersTags.clear();
|
|
1211
|
+
this.#logger.debug('rabbit: connection closed');
|
|
1212
|
+
if (this.options?.disableReconnect) {
|
|
1213
|
+
logger.error(`${this.DISCONNECT_MSG}${err && ` - ${err}`}`);
|
|
1214
|
+
connection.blockReconnect = true;
|
|
1215
|
+
} else {
|
|
1216
|
+
logger.error(`${this.RECONNECT_MSG}${err && ` - ${err}`}`);
|
|
1217
|
+
}
|
|
1218
|
+
});
|
|
1219
|
+
|
|
1220
|
+
newConnection.once('connect', async () => {
|
|
1221
|
+
this.#logger.debug('rabbit: connection established');
|
|
1222
|
+
connection.creatingConnection = false;
|
|
1223
|
+
this.oldEm.emit(connectionCreatedEventName, newConnection);
|
|
1224
|
+
isResolved = true;
|
|
1225
|
+
resolve(newConnection);
|
|
1226
|
+
});
|
|
1227
|
+
|
|
1228
|
+
return promise;
|
|
1287
1229
|
}
|
|
1288
1230
|
|
|
1289
|
-
private saveConsumerOld(queue: string, callback: CallbackFunction, options: ConsumeOptions | undefined) {
|
|
1231
|
+
private saveConsumerOld(queue: string, callback: CallbackFunction, options: ConsumeOptions | undefined): void {
|
|
1290
1232
|
const isConsumerExist: boolean = this.oldConsumersToRegister.some((consumer) => consumer.queue === queue);
|
|
1291
1233
|
if (!isConsumerExist) {
|
|
1292
1234
|
logger.info(`rabbit: consumer: ${queue} saved in consumer array`);
|
|
@@ -1298,19 +1240,15 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
1298
1240
|
}
|
|
1299
1241
|
}
|
|
1300
1242
|
|
|
1301
|
-
async assertQueueOld(queueName: string, options?: Options.AssertQueue): Promise<
|
|
1243
|
+
async assertQueueOld(queueName: string, options?: Options.AssertQueue): Promise<Replies.AssertQueue> {
|
|
1302
1244
|
RabbitMq.validateName('queue', queueName);
|
|
1303
1245
|
if (this.oldQueues[queueName]) {
|
|
1304
1246
|
delete this.oldQueueSetupPromises[queueName];
|
|
1305
|
-
return this.oldQueues[queueName]
|
|
1247
|
+
return this.oldQueues[queueName]!;
|
|
1306
1248
|
}
|
|
1307
1249
|
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
}
|
|
1311
|
-
|
|
1312
|
-
this.oldQueueSetupPromises[queueName] = this.setupQueueOld(queueName, options);
|
|
1313
|
-
return this.oldQueueSetupPromises[queueName];
|
|
1250
|
+
this.oldQueueSetupPromises[queueName] ||= this.setupQueueOld(queueName, options);
|
|
1251
|
+
return this.oldQueueSetupPromises[queueName]!;
|
|
1314
1252
|
}
|
|
1315
1253
|
|
|
1316
1254
|
async setupQueueOld(queueName: string, options?: Options.AssertQueue): Promise<Replies.AssertQueue> {
|
|
@@ -1328,20 +1266,20 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
1328
1266
|
};
|
|
1329
1267
|
try {
|
|
1330
1268
|
const channel: ChannelWrapper = await this.assertChannelOld({ connection });
|
|
1331
|
-
debug('assertQueue->channel.addSetup', { queueName });
|
|
1269
|
+
this.#logger.debug('assertQueue->channel.addSetup', { queueName });
|
|
1332
1270
|
await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.assertQueue(queueName, localeOptions));
|
|
1333
|
-
debug('assertQueue->channel.assertQueue', { queueName });
|
|
1271
|
+
this.#logger.debug('assertQueue->channel.assertQueue', { queueName });
|
|
1334
1272
|
queue = await channel.assertQueue(queueName, localeOptions);
|
|
1335
1273
|
} catch (e) {
|
|
1336
1274
|
logger.error('rabbit: assertQueue error', { queueName, options, error: e });
|
|
1337
1275
|
if (!this.options?.dontRetryAssert) {
|
|
1338
|
-
debug('retrying assertQueue', { queueName });
|
|
1276
|
+
this.#logger.debug('retrying assertQueue', { queueName });
|
|
1339
1277
|
const channel = await this.assertChannelOld({ force: true, connection });
|
|
1340
1278
|
await this.deleteQueueOld(queueName, connection);
|
|
1341
1279
|
|
|
1342
|
-
debug('retrying assertQueue->channel.addSetup', { queueName });
|
|
1280
|
+
this.#logger.debug('retrying assertQueue->channel.addSetup', { queueName });
|
|
1343
1281
|
await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.assertQueue(queueName, localeOptions));
|
|
1344
|
-
debug('retrying assertQueue->channel.assertQueue', { queueName });
|
|
1282
|
+
this.#logger.debug('retrying assertQueue->channel.assertQueue', { queueName });
|
|
1345
1283
|
queue = await channel.assertQueue(queueName, localeOptions);
|
|
1346
1284
|
} else {
|
|
1347
1285
|
throw e;
|
|
@@ -1353,58 +1291,60 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
1353
1291
|
}
|
|
1354
1292
|
|
|
1355
1293
|
async assertChannelOld({ force = false, connection }: assertChannelOpts): Promise<ChannelWrapper> {
|
|
1356
|
-
if (
|
|
1357
|
-
this.oldPublishChannelSetupPromise
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1294
|
+
if (this.oldPublishChannelSetupPromise) {
|
|
1295
|
+
return this.oldPublishChannelSetupPromise;
|
|
1296
|
+
}
|
|
1297
|
+
const { promise, resolve, reject } = createDeferredPromise<ChannelWrapper>();
|
|
1298
|
+
this.oldPublishChannelSetupPromise = promise;
|
|
1299
|
+
if (this.oldPublishChannel && !force) {
|
|
1300
|
+
resolve(this.oldPublishChannel);
|
|
1301
|
+
return promise;
|
|
1302
|
+
}
|
|
1361
1303
|
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
});
|
|
1367
|
-
if (this.oldPublishConnection === connection) {
|
|
1368
|
-
this.oldPublishChannel = channel;
|
|
1369
|
-
}
|
|
1370
|
-
resolve(channel);
|
|
1371
|
-
} catch (e) {
|
|
1372
|
-
reject(e);
|
|
1373
|
-
}
|
|
1304
|
+
try {
|
|
1305
|
+
const channel = await this.getNewChannelOld({ connection });
|
|
1306
|
+
channel.on('error', (err) => {
|
|
1307
|
+
logger.error('rabbit: channel error', { err });
|
|
1374
1308
|
});
|
|
1309
|
+
if (this.oldPublishConnection === connection) {
|
|
1310
|
+
this.oldPublishChannel = channel;
|
|
1311
|
+
}
|
|
1312
|
+
resolve(channel);
|
|
1313
|
+
} catch (e) {
|
|
1314
|
+
reject(e);
|
|
1375
1315
|
}
|
|
1376
|
-
return
|
|
1316
|
+
return promise;
|
|
1377
1317
|
}
|
|
1378
1318
|
|
|
1379
|
-
private async deleteQueueOld(queue: string, connection: ConnectionData) {
|
|
1319
|
+
private async deleteQueueOld(queue: string, connection: ConnectionData): Promise<Replies.DeleteQueue> {
|
|
1380
1320
|
RabbitMq.validateName('queue', queue);
|
|
1381
1321
|
const channel: ChannelWrapper = await this.assertChannelOld({ connection });
|
|
1382
1322
|
logger.info('rabbit: deleting queue', { queue });
|
|
1383
1323
|
const deleteQueueRes = await channel.deleteQueue(queue);
|
|
1384
|
-
debug('queue deleted', deleteQueueRes);
|
|
1324
|
+
this.#logger.debug('queue deleted', deleteQueueRes);
|
|
1385
1325
|
return deleteQueueRes;
|
|
1386
1326
|
}
|
|
1387
1327
|
|
|
1388
|
-
async assertExchangeOld(exchangeName: string, connection: ConnectionData) {
|
|
1328
|
+
async assertExchangeOld(exchangeName: string, connection: ConnectionData): Promise<Replies.AssertExchange> {
|
|
1389
1329
|
const channel: ChannelWrapper = await this.assertChannelOld({ connection });
|
|
1390
1330
|
|
|
1391
1331
|
if (this.oldExchanges[exchangeName]) {
|
|
1392
1332
|
delete this.oldAssertExchangePromises[exchangeName];
|
|
1393
|
-
return this.oldExchanges[exchangeName]
|
|
1333
|
+
return this.oldExchanges[exchangeName]!;
|
|
1394
1334
|
}
|
|
1395
1335
|
|
|
1396
1336
|
if (this.oldAssertExchangePromises[exchangeName]) {
|
|
1397
|
-
return this.oldAssertExchangePromises[exchangeName]
|
|
1337
|
+
return this.oldAssertExchangePromises[exchangeName]!;
|
|
1398
1338
|
}
|
|
1399
1339
|
|
|
1400
1340
|
this.oldAssertExchangePromises[exchangeName] = assertExchangeFanout(channel, exchangeName);
|
|
1401
1341
|
this.oldExchanges[exchangeName] = await this.oldAssertExchangePromises[exchangeName];
|
|
1402
|
-
return this.oldExchanges[exchangeName]
|
|
1342
|
+
return this.oldExchanges[exchangeName]!;
|
|
1403
1343
|
}
|
|
1404
1344
|
|
|
1405
|
-
async isConnectedOld()
|
|
1345
|
+
async isConnectedOld(): Promise<boolean> {
|
|
1406
1346
|
if (!this.gracefulShutdownStarted) {
|
|
1407
|
-
debug('rabbit: start is connected old');
|
|
1347
|
+
this.#logger.debug('rabbit: start is connected old');
|
|
1408
1348
|
const [oldConsumeConnection, oldPublishConnection] = await Promise.all([
|
|
1409
1349
|
this.getConnectionOld(this.oldConsumeConnection),
|
|
1410
1350
|
this.getConnectionOld(this.oldPublishConnection),
|
|
@@ -1416,10 +1356,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
1416
1356
|
}
|
|
1417
1357
|
|
|
1418
1358
|
try {
|
|
1419
|
-
const unRegisteredConsumersOld = this.consumersToRegister.filter((c
|
|
1420
|
-
const doesConsumerExist = this.consumersTags.get(c.queue);
|
|
1421
|
-
return !doesConsumerExist;
|
|
1422
|
-
});
|
|
1359
|
+
const unRegisteredConsumersOld = this.consumersToRegister.filter((c) => !this.consumersTags.get(c.queue));
|
|
1423
1360
|
|
|
1424
1361
|
if (unRegisteredConsumersOld.length > 0) {
|
|
1425
1362
|
const queueNames = unRegisteredConsumersOld.map((c) => c.queue);
|
|
@@ -1431,7 +1368,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
1431
1368
|
throw new RabbitError('Found unregistered consumers old');
|
|
1432
1369
|
}
|
|
1433
1370
|
|
|
1434
|
-
const channelOld
|
|
1371
|
+
const channelOld = await this.assertChannelOld({ connection: this.oldPublishConnection });
|
|
1435
1372
|
await channelOld.waitForConnect();
|
|
1436
1373
|
|
|
1437
1374
|
await Promise.all(
|