@autofleet/rabbit 3.4.0-beta.9 → 3.5.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/.claude/settings.local.json +3 -0
- package/dist/index.d.ts +5 -3
- package/dist/index.js +90 -97
- package/dist/index.js.map +1 -0
- package/dist/lib/celery.js +1 -0
- package/dist/lib/celery.js.map +1 -0
- package/dist/lib/consts.js +1 -0
- package/dist/lib/consts.js.map +1 -0
- package/dist/lib/rabbitError.js +1 -0
- package/dist/lib/rabbitError.js.map +1 -0
- package/dist/lib/redis.js +1 -0
- package/dist/lib/redis.js.map +1 -0
- package/dist/lib/types.d.ts +1 -1
- package/dist/lib/types.js +1 -0
- package/dist/lib/types.js.map +1 -0
- package/dist/lib/utils.js +1 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/logger.js +1 -0
- package/dist/logger.js.map +1 -0
- package/dist/{mock.d.ts → mock/index.d.ts} +1 -1
- package/dist/{mock.js → mock/index.js} +2 -1
- package/dist/mock/index.js.map +1 -0
- package/dist/mock/vitest.d.ts +13 -0
- package/dist/mock/vitest.js +18 -0
- package/dist/mock/vitest.js.map +1 -0
- package/package.json +22 -15
- package/src/index.ts +107 -103
- package/src/lib/types.ts +1 -1
- package/src/{mock.ts → mock/index.ts} +2 -2
- package/src/mock/vitest.ts +24 -0
- package/tsconfig.build.json +5 -0
- package/tsconfig.json +2 -2
- package/vitest.config.ts +16 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mock/index.ts"],"names":[],"mappings":";;AAAA,gDAAgD;AAChD,gBAAc;AAGd,MAAM,QAAQ;IAAd;QACE,QAAG,GAAQ,IAAI,CAAC,EAAE,EAAE,CAAC;QAErB,SAAI,GAAQ,IAAI,CAAC,EAAE,EAAE,CAAC;QAEtB,kBAAa,GAAQ,IAAI,CAAC,EAAE,EAAE,CAAC;QAE/B,mBAAc,GAAQ,IAAI,CAAC,EAAE,EAAE,CAAC;QAEhC,gBAAW,GAAQ,IAAI,CAAC,EAAE,EAAE,CAAC;QAE7B,YAAO,GAAQ,IAAI,CAAC,EAAE,EAAE,CAAC;QAEzB,wBAAmB,GAAQ,IAAI,CAAC,EAAE,EAAE,CAAC;QAErC,YAAO,GAAQ,IAAI,CAAC,EAAE,EAAE,CAAC;QAEzB,gBAAW,GAAQ,IAAI,CAAC,EAAE,EAAE,CAAC;IAC/B,CAAC;CAAA;AAED,kBAAe,QAAQ,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { IAfRabbitMq } from '../index';
|
|
2
|
+
declare class RabbitMq implements IAfRabbitMq {
|
|
3
|
+
ack: import("@vitest/spy").Mock<(...args: any[]) => any>;
|
|
4
|
+
nack: import("@vitest/spy").Mock<(...args: any[]) => any>;
|
|
5
|
+
assertChannel: import("@vitest/spy").Mock<(...args: any[]) => any>;
|
|
6
|
+
assertExchange: import("@vitest/spy").Mock<(...args: any[]) => any>;
|
|
7
|
+
assertQueue: import("@vitest/spy").Mock<(...args: any[]) => any>;
|
|
8
|
+
consume: import("@vitest/spy").Mock<(...args: any[]) => any>;
|
|
9
|
+
consumeFromExchange: import("@vitest/spy").Mock<(...args: any[]) => any>;
|
|
10
|
+
publish: import("@vitest/spy").Mock<(...args: any[]) => any>;
|
|
11
|
+
sendToQueue: import("@vitest/spy").Mock<(...args: any[]) => any>;
|
|
12
|
+
}
|
|
13
|
+
export default RabbitMq;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
class RabbitMq {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.ack = vitest_1.vi.fn();
|
|
7
|
+
this.nack = vitest_1.vi.fn();
|
|
8
|
+
this.assertChannel = vitest_1.vi.fn();
|
|
9
|
+
this.assertExchange = vitest_1.vi.fn();
|
|
10
|
+
this.assertQueue = vitest_1.vi.fn();
|
|
11
|
+
this.consume = vitest_1.vi.fn();
|
|
12
|
+
this.consumeFromExchange = vitest_1.vi.fn();
|
|
13
|
+
this.publish = vitest_1.vi.fn();
|
|
14
|
+
this.sendToQueue = vitest_1.vi.fn();
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
exports.default = RabbitMq;
|
|
18
|
+
//# sourceMappingURL=vitest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vitest.js","sourceRoot":"","sources":["../../src/mock/vitest.ts"],"names":[],"mappings":";;AAAA,mCAA4B;AAG5B,MAAM,QAAQ;IAAd;QACE,QAAG,GAAG,WAAE,CAAC,EAAE,EAAE,CAAC;QAEd,SAAI,GAAG,WAAE,CAAC,EAAE,EAAE,CAAC;QAEf,kBAAa,GAAG,WAAE,CAAC,EAAE,EAAE,CAAC;QAExB,mBAAc,GAAG,WAAE,CAAC,EAAE,EAAE,CAAC;QAEzB,gBAAW,GAAG,WAAE,CAAC,EAAE,EAAE,CAAC;QAEtB,YAAO,GAAG,WAAE,CAAC,EAAE,EAAE,CAAC;QAElB,wBAAmB,GAAG,WAAE,CAAC,EAAE,EAAE,CAAC;QAE9B,YAAO,GAAG,WAAE,CAAC,EAAE,EAAE,CAAC;QAElB,gBAAW,GAAG,WAAE,CAAC,EAAE,EAAE,CAAC;IACxB,CAAC;CAAA;AAED,kBAAe,QAAQ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@autofleet/rabbit",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.5.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"engines": {
|
|
@@ -10,40 +10,47 @@
|
|
|
10
10
|
"postinstall": "echo '\\033[0;31m\nWARNING: in case of migrating to new version of @autofleet/rabbit \nyou might have to delete existing queues or the deployment will fail.\\033[0m\n'",
|
|
11
11
|
"start": "ts-node src/index.ts",
|
|
12
12
|
"example": "ts-node src/example.ts",
|
|
13
|
-
"build": "rm -rf dist && tsc",
|
|
14
|
-
"linter": "
|
|
15
|
-
"test": "
|
|
16
|
-
"test-local": "RABBITMQ_SERVICE_HOST=localhost:5672
|
|
17
|
-
"coverage": "
|
|
13
|
+
"build": "rm -rf dist && tsc -p tsconfig.build.json",
|
|
14
|
+
"linter": "eslint .",
|
|
15
|
+
"test": "vitest",
|
|
16
|
+
"test-local": "RABBITMQ_SERVICE_HOST=localhost:5672 node --inspect-brk ./node_modules/.bin/vitest --testTimeout=10000000000",
|
|
17
|
+
"coverage": "vitest --coverage",
|
|
18
18
|
"dev": "nodemon"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"@autofleet/zehut": "^3.1.2",
|
|
22
|
-
"amqp-connection-manager": "4.1.
|
|
23
|
-
"amqplib": "0.10.
|
|
22
|
+
"amqp-connection-manager": "4.1.14",
|
|
23
|
+
"amqplib": "0.10.5",
|
|
24
24
|
"bluebird": "^3.7.2",
|
|
25
|
-
"moment": "^2.
|
|
25
|
+
"moment": "^2.30.1",
|
|
26
26
|
"redis": "^3.1.2",
|
|
27
27
|
"redis-lock": "^0.1.4"
|
|
28
28
|
},
|
|
29
29
|
"peerDependencies": {
|
|
30
|
-
"@autofleet/logger": "*"
|
|
30
|
+
"@autofleet/logger": "*",
|
|
31
|
+
"jest": "*"
|
|
32
|
+
},
|
|
33
|
+
"peerDependenciesMeta": {
|
|
34
|
+
"jest": {
|
|
35
|
+
"optional": true
|
|
36
|
+
}
|
|
31
37
|
},
|
|
32
38
|
"devDependencies": {
|
|
33
39
|
"@autofleet/logger": "4.0.6",
|
|
34
|
-
"@types/amqplib": "0.
|
|
40
|
+
"@types/amqplib": "0.10.7",
|
|
41
|
+
"@types/bluebird": "^3.5.42",
|
|
35
42
|
"@types/jest": "^29.5.12",
|
|
36
43
|
"@types/node": "^20.14.11",
|
|
37
44
|
"@typescript-eslint/eslint-plugin": "^4.8.1",
|
|
45
|
+
"@vitest/coverage-v8": "^3.1.3",
|
|
38
46
|
"eslint": "^7.13.0",
|
|
39
47
|
"eslint-config-airbnb-typescript": "^12.0.0",
|
|
40
48
|
"eslint-plugin-import": "^2.22.1",
|
|
41
|
-
"jest": "^29.7.0",
|
|
42
49
|
"node-tcp-proxy": "^0.0.28",
|
|
43
|
-
"ts-jest": "^29.2.3",
|
|
44
50
|
"ts-node": "^8.6.2",
|
|
45
|
-
"typescript": "^4.9.5"
|
|
51
|
+
"typescript": "^4.9.5",
|
|
52
|
+
"vitest": "^3.1.3"
|
|
46
53
|
},
|
|
47
54
|
"author": "",
|
|
48
|
-
"license": "
|
|
55
|
+
"license": "Proprietary"
|
|
49
56
|
}
|
package/src/index.ts
CHANGED
|
@@ -45,6 +45,11 @@ const debug = logger.debug.bind(logger);
|
|
|
45
45
|
|
|
46
46
|
const PUBLISH_TIMEOUT = 1000 * 10;
|
|
47
47
|
|
|
48
|
+
// TODO: [QUORUM-PHASE-3] Delete this env var
|
|
49
|
+
const {
|
|
50
|
+
DISABLE_QUORUM_QUEUES,
|
|
51
|
+
} = process.env;
|
|
52
|
+
|
|
48
53
|
export interface IAfRabbitMq {
|
|
49
54
|
ack: any;
|
|
50
55
|
nack: any;
|
|
@@ -149,8 +154,6 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
149
154
|
|
|
150
155
|
blockReconnect: boolean | null | undefined
|
|
151
156
|
|
|
152
|
-
connection: AmqpConnectionManager | null | undefined
|
|
153
|
-
|
|
154
157
|
publishConnection: ConnectionData
|
|
155
158
|
|
|
156
159
|
consumeConnection: ConnectionData
|
|
@@ -213,16 +216,15 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
213
216
|
this.em = new EventEmitter();
|
|
214
217
|
this.publishChannel = null;
|
|
215
218
|
this.publishChannelSetupPromise = null;
|
|
216
|
-
this.connection = null;
|
|
217
219
|
this.publishConnection = {
|
|
218
|
-
|
|
220
|
+
amqpConnection: null,
|
|
219
221
|
creatingConnection: false,
|
|
220
222
|
connectionCreatedEventName: 'publishConnectionCreated',
|
|
221
223
|
connectionFailedEventName: 'publishConnectionFailed',
|
|
222
224
|
blockReconnect: false,
|
|
223
225
|
};
|
|
224
226
|
this.consumeConnection = {
|
|
225
|
-
|
|
227
|
+
amqpConnection: null,
|
|
226
228
|
creatingConnection: false,
|
|
227
229
|
connectionCreatedEventName: 'consumeConnectionCreated',
|
|
228
230
|
connectionFailedEventName: 'consumeConnectionFailed',
|
|
@@ -256,14 +258,14 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
256
258
|
this.oldPublishChannel = null;
|
|
257
259
|
this.oldPublishChannelSetupPromise = null;
|
|
258
260
|
this.oldPublishConnection = {
|
|
259
|
-
|
|
261
|
+
amqpConnection: null,
|
|
260
262
|
creatingConnection: false,
|
|
261
263
|
connectionCreatedEventName: 'oldPublishConnectionCreated',
|
|
262
264
|
connectionFailedEventName: 'oldPublishConnectionFailed',
|
|
263
265
|
blockReconnect: false,
|
|
264
266
|
};
|
|
265
267
|
this.oldConsumeConnection = {
|
|
266
|
-
|
|
268
|
+
amqpConnection: null,
|
|
267
269
|
creatingConnection: false,
|
|
268
270
|
connectionCreatedEventName: 'oldConsumeConnectionCreated',
|
|
269
271
|
connectionFailedEventName: 'oldConsumeConnectionFailed',
|
|
@@ -378,13 +380,13 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
378
380
|
if (
|
|
379
381
|
!skipRetry
|
|
380
382
|
&& (
|
|
381
|
-
!msg.properties.headers[RETRY_HEADER]
|
|
383
|
+
!msg.properties.headers?.[RETRY_HEADER]
|
|
382
384
|
|| parseInt(msg.properties.headers[RETRY_HEADER], 10) < options.retries
|
|
383
385
|
)
|
|
384
386
|
) {
|
|
385
387
|
await this.sendToQueue(queue, RabbitMq.parseMsg(msg).content, options, {
|
|
386
388
|
...msg.properties.headers,
|
|
387
|
-
[RETRY_HEADER]: msg.properties.headers[RETRY_HEADER]
|
|
389
|
+
[RETRY_HEADER]: msg.properties.headers?.[RETRY_HEADER]
|
|
388
390
|
? msg.properties.headers[RETRY_HEADER] + 1
|
|
389
391
|
: 1,
|
|
390
392
|
});
|
|
@@ -392,7 +394,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
392
394
|
const deadQueue = `${queue}-dead`;
|
|
393
395
|
await this.sendToQueue(deadQueue, RabbitMq.parseMsg(msg).content, deadQueueOptions, {
|
|
394
396
|
...msg.properties.headers,
|
|
395
|
-
[RETRY_HEADER]: msg.properties.headers[RETRY_HEADER]
|
|
397
|
+
[RETRY_HEADER]: msg.properties.headers?.[RETRY_HEADER]
|
|
396
398
|
? msg.properties.headers[RETRY_HEADER] + 1
|
|
397
399
|
: 1,
|
|
398
400
|
});
|
|
@@ -409,12 +411,13 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
409
411
|
async getConnection(connection: ConnectionData) {
|
|
410
412
|
return new Promise<AmqpConnectionManager>(async (resolve, reject) => {
|
|
411
413
|
const {
|
|
412
|
-
|
|
414
|
+
amqpConnection: connectionLocal,
|
|
413
415
|
creatingConnection,
|
|
414
416
|
connectionCreatedEventName,
|
|
415
417
|
connectionFailedEventName,
|
|
416
418
|
blockReconnect,
|
|
417
419
|
} = connection;
|
|
420
|
+
|
|
418
421
|
if (blockReconnect) {
|
|
419
422
|
debug('rabbit: block reconnect');
|
|
420
423
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
@@ -456,12 +459,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
456
459
|
findServers,
|
|
457
460
|
});
|
|
458
461
|
|
|
459
|
-
connection.
|
|
460
|
-
if (connection === this.publishConnection) {
|
|
461
|
-
debug('rabbit: publishConnection set');
|
|
462
|
-
} else if (connection === this.consumeConnection) {
|
|
463
|
-
debug('rabbit: consumeConnection set');
|
|
464
|
-
}
|
|
462
|
+
connection.amqpConnection = newConnection;
|
|
465
463
|
newConnection.on('error', (err) => {
|
|
466
464
|
logger.error('rabbit: connection error', { err });
|
|
467
465
|
if (!isResolved) {
|
|
@@ -473,6 +471,9 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
473
471
|
|
|
474
472
|
newConnection.on('connectFailed', (err) => {
|
|
475
473
|
this.consumersTags = [];
|
|
474
|
+
if (typeof err.url === 'string') {
|
|
475
|
+
err.url = this.maskURL(err.url);
|
|
476
|
+
}
|
|
476
477
|
logger.error('rabbit: connection connectFailed', { err, advice: 'Check if the vhost exist', vhost: this.vhost });
|
|
477
478
|
if (!isResolved) {
|
|
478
479
|
isResolved = true;
|
|
@@ -496,7 +497,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
496
497
|
newConnection.once('connect', async () => {
|
|
497
498
|
debug('rabbit: connection established');
|
|
498
499
|
connection.creatingConnection = false;
|
|
499
|
-
this.em.emit(connectionCreatedEventName,
|
|
500
|
+
this.em.emit(connectionCreatedEventName, newConnection);
|
|
500
501
|
isResolved = true;
|
|
501
502
|
resolve(newConnection);
|
|
502
503
|
});
|
|
@@ -576,7 +577,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
576
577
|
if (!channel) {
|
|
577
578
|
throw new RabbitError('channel is not defined');
|
|
578
579
|
}
|
|
579
|
-
debug('rabbit: getting queue length', { queue, connected: this.
|
|
580
|
+
debug('rabbit: getting queue length', { queue, connected: this.oldPublishConnection.amqpConnection?.isConnected() });
|
|
580
581
|
return channel?.checkQueue(queue);
|
|
581
582
|
}
|
|
582
583
|
|
|
@@ -682,7 +683,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
682
683
|
// Used by the microservices to consume messages from the queue
|
|
683
684
|
async consume(queue: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<any> {
|
|
684
685
|
// TODO: [QUORUM-PHASE-3] Use only the implementation of consumeNew and delete consumeNew and consumeOld
|
|
685
|
-
if (options?.isQuorumQueue !== false) {
|
|
686
|
+
if (options?.isQuorumQueue !== false && DISABLE_QUORUM_QUEUES !== 'true') {
|
|
686
687
|
await this.assertVHost();
|
|
687
688
|
await this.consumeNew(queue, callback, options);
|
|
688
689
|
}
|
|
@@ -745,9 +746,9 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
745
746
|
return null;
|
|
746
747
|
}
|
|
747
748
|
|
|
748
|
-
const traceId = msg.properties.headers[TRACING_HEADER];
|
|
749
|
-
const userId = msg.properties.headers[USER_TRACING_HEADER];
|
|
750
|
-
const automationId = msg.properties.headers[AUTOMATION_ID_HEADER];
|
|
749
|
+
const traceId = msg.properties.headers![TRACING_HEADER];
|
|
750
|
+
const userId = msg.properties.headers![USER_TRACING_HEADER];
|
|
751
|
+
const automationId = msg.properties.headers![AUTOMATION_ID_HEADER];
|
|
751
752
|
const parsedMessage = RabbitMq.parseMsg(msg);
|
|
752
753
|
const releaseLock = await this.lockRedisIfNeeded(parsedMessage, optionsWithDefaults);
|
|
753
754
|
const trace = newTrace(traceTypes.RABBIT);
|
|
@@ -831,7 +832,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
831
832
|
RabbitMq.validateName('queue', queue);
|
|
832
833
|
const { limit, deadMessageTtl } = optionsWithDefaults;
|
|
833
834
|
// TODO: [QUORUM-PHASE-3] Delete the if statement after all the queues are created as quorum queues
|
|
834
|
-
if (options?.isQuorumQueue !== false) {
|
|
835
|
+
if (options?.isQuorumQueue !== false && DISABLE_QUORUM_QUEUES !== 'true') {
|
|
835
836
|
await this.assertVHost();
|
|
836
837
|
await this.saveConsumer(queue, callback, options);
|
|
837
838
|
const channel: ChannelWrapper = await this.getNewChannel({
|
|
@@ -853,28 +854,27 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
853
854
|
),
|
|
854
855
|
]);
|
|
855
856
|
});
|
|
856
|
-
} else {
|
|
857
|
-
// TODO: [QUORUM-PHASE-3] Delete the old implementation
|
|
858
|
-
await this.saveConsumerOld(queue, callback, options);
|
|
859
|
-
const channelOld: ChannelWrapper = await this.getNewChannelOld({
|
|
860
|
-
name: `consume-exchange-${exchange}-queue-${queue}-old`,
|
|
861
|
-
connection: this.oldConsumeConnection,
|
|
862
|
-
});
|
|
863
|
-
await channelOld.addSetup(async (c: ConfirmChannel) => {
|
|
864
|
-
const assertExchange = await assertExchangeFanout(c, exchange);
|
|
865
|
-
await c.assertQueue(queue);
|
|
866
|
-
this.oldExchanges[exchange] = assertExchange;
|
|
867
|
-
await c.prefetch(limit, false);
|
|
868
|
-
return Promise.all([
|
|
869
|
-
c.bindQueue(queue, exchange, ''),
|
|
870
|
-
this.consumeOld(
|
|
871
|
-
queue,
|
|
872
|
-
callback,
|
|
873
|
-
options,
|
|
874
|
-
),
|
|
875
|
-
]);
|
|
876
|
-
});
|
|
877
857
|
}
|
|
858
|
+
// TODO: [QUORUM-PHASE-3] Delete the old implementation
|
|
859
|
+
await this.saveConsumerOld(queue, callback, options);
|
|
860
|
+
const channelOld: ChannelWrapper = await this.getNewChannelOld({
|
|
861
|
+
name: `consume-exchange-${exchange}-queue-${queue}-old`,
|
|
862
|
+
connection: this.oldConsumeConnection,
|
|
863
|
+
});
|
|
864
|
+
await channelOld.addSetup(async (c: ConfirmChannel) => {
|
|
865
|
+
const assertExchange = await assertExchangeFanout(c, exchange);
|
|
866
|
+
await c.assertQueue(queue);
|
|
867
|
+
this.oldExchanges[exchange] = assertExchange;
|
|
868
|
+
await c.prefetch(limit, false);
|
|
869
|
+
return Promise.all([
|
|
870
|
+
c.bindQueue(queue, exchange, ''),
|
|
871
|
+
this.consumeOld(
|
|
872
|
+
queue,
|
|
873
|
+
callback,
|
|
874
|
+
options,
|
|
875
|
+
),
|
|
876
|
+
]);
|
|
877
|
+
});
|
|
878
878
|
}
|
|
879
879
|
|
|
880
880
|
// Used by the microservices to publish messages to the exchange
|
|
@@ -920,53 +920,71 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
920
920
|
debug(`rabbit: sending to queue ${queue}`, { res });
|
|
921
921
|
return res;
|
|
922
922
|
} catch (e) {
|
|
923
|
-
const isConnected = await this.
|
|
923
|
+
const isConnected = await this.isConnectedOld();
|
|
924
924
|
logger.error(`rabbit sendToQueue: failed to send to queue ${queue}, isConnected: ${isConnected}`, { e });
|
|
925
925
|
throw e;
|
|
926
926
|
}
|
|
927
927
|
}
|
|
928
928
|
|
|
929
929
|
// TODO: [QUORUM-PHASE-2] After changing the publish from old to new change from the old to the new implementation
|
|
930
|
-
async isConnected()
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
930
|
+
async isConnected(): Promise<boolean> {
|
|
931
|
+
const [connectionNew, connectionOld] = await Promise.all([
|
|
932
|
+
this.isConnectedNew(),
|
|
933
|
+
this.isConnectedOld(),
|
|
934
|
+
]);
|
|
935
|
+
|
|
936
|
+
return connectionNew && connectionOld;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
// TODO: [QUORUM-PHASE-2] After changing the publish from old to new change from the old to the new implementation
|
|
940
|
+
async isConnectedNew(): Promise<boolean> {
|
|
941
|
+
if (DISABLE_QUORUM_QUEUES === 'true') {
|
|
942
|
+
return true;
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
debug('rabbit: start new is connected');
|
|
946
|
+
const consumeConnection = await this.getConnection(this.consumeConnection);
|
|
947
|
+
const publishConnection = await this.getConnection(this.publishConnection);
|
|
948
|
+
const isConnected = consumeConnection.isConnected() && publishConnection.isConnected();
|
|
949
|
+
if (!isConnected) {
|
|
950
|
+
logger.error('rabbit: new isConnected - false');
|
|
937
951
|
return false;
|
|
938
952
|
}
|
|
939
|
-
const
|
|
953
|
+
const channel: any = await this.assertChannel({ connection: this.publishConnection });
|
|
940
954
|
try {
|
|
941
955
|
await Promise.all([
|
|
942
|
-
|
|
943
|
-
...this.
|
|
956
|
+
channel.waitForConnect(),
|
|
957
|
+
...this.consumers.map((c: AfConsumer) => channel.checkQueue(c.queue)),
|
|
944
958
|
]);
|
|
945
959
|
} catch (e) {
|
|
946
|
-
logger.error('rabbit: isConnected - false');
|
|
960
|
+
logger.error('rabbit: new isConnected - false');
|
|
947
961
|
return false;
|
|
948
962
|
}
|
|
949
|
-
logger.debug('rabbit:
|
|
963
|
+
logger.debug('rabbit: new isConnected - true');
|
|
964
|
+
return true;
|
|
965
|
+
}
|
|
950
966
|
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
const
|
|
955
|
-
|
|
956
|
-
|
|
967
|
+
// TODO: [QUORUM-PHASE-2] After changing the publish from old to new change from the old to the new implementation
|
|
968
|
+
async isConnectedOld(): Promise<boolean> {
|
|
969
|
+
debug('rabbit: start old is connected');
|
|
970
|
+
const oldConsumeConnection = await this.getConnectionOld(this.oldConsumeConnection);
|
|
971
|
+
const oldPublishConnection = await this.getConnectionOld(this.oldPublishConnection);
|
|
972
|
+
const oldIsConnected = oldConsumeConnection.isConnected() && oldPublishConnection.isConnected();
|
|
973
|
+
if (!oldIsConnected) {
|
|
974
|
+
logger.error('rabbit: old isConnected - false');
|
|
957
975
|
return false;
|
|
958
976
|
}
|
|
959
|
-
const
|
|
977
|
+
const oldChannel: any = await this.assertChannelOld({ connection: this.oldPublishConnection });
|
|
960
978
|
try {
|
|
961
979
|
await Promise.all([
|
|
962
|
-
|
|
963
|
-
...this.oldConsumers.map((c: AfConsumer) =>
|
|
980
|
+
oldChannel.waitForConnect(),
|
|
981
|
+
...this.oldConsumers.map((c: AfConsumer) => oldChannel.checkQueue(c.queue)),
|
|
964
982
|
]);
|
|
965
983
|
} catch (e) {
|
|
966
|
-
logger.error('rabbit: isConnected - false');
|
|
984
|
+
logger.error('rabbit: old isConnected - false');
|
|
967
985
|
return false;
|
|
968
986
|
}
|
|
969
|
-
logger.debug('rabbit: isConnected - true');
|
|
987
|
+
logger.debug('rabbit: old isConnected - true');
|
|
970
988
|
return true;
|
|
971
989
|
}
|
|
972
990
|
|
|
@@ -990,7 +1008,6 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
990
1008
|
|
|
991
1009
|
private async consumeFromRabbitOld(queue: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<any> {
|
|
992
1010
|
const optionsWithDefaults = { ...DEFAULT_OPTIONS, ...options };
|
|
993
|
-
debug('rabbit: consumeFromRabbitOld', { queue });
|
|
994
1011
|
RabbitMq.validateName('queue', queue);
|
|
995
1012
|
this.saveConsumerOld(queue, callback, options);
|
|
996
1013
|
const uniqueId = randomUUID();
|
|
@@ -1014,9 +1031,9 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
1014
1031
|
return null;
|
|
1015
1032
|
}
|
|
1016
1033
|
|
|
1017
|
-
const traceId = msg.properties.headers[TRACING_HEADER];
|
|
1018
|
-
const userId = msg.properties.headers[USER_TRACING_HEADER];
|
|
1019
|
-
const automationId = msg.properties.headers[AUTOMATION_ID_HEADER];
|
|
1034
|
+
const traceId = msg.properties.headers![TRACING_HEADER];
|
|
1035
|
+
const userId = msg.properties.headers![USER_TRACING_HEADER];
|
|
1036
|
+
const automationId = msg.properties.headers![AUTOMATION_ID_HEADER];
|
|
1020
1037
|
const parsedMessage = RabbitMq.parseMsg(msg);
|
|
1021
1038
|
const releaseLock = await this.lockRedisIfNeeded(parsedMessage, optionsWithDefaults);
|
|
1022
1039
|
const trace = newTrace(traceTypes.RABBIT);
|
|
@@ -1098,11 +1115,6 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
1098
1115
|
name = rand().toString(), onClose = null, options = {}, connection,
|
|
1099
1116
|
}: newChannelOpts) {
|
|
1100
1117
|
let localConnection!: AmqpConnectionManager;
|
|
1101
|
-
if (connection === this.oldPublishConnection) {
|
|
1102
|
-
debug('rabbit: getConnectionOld publish', { connection });
|
|
1103
|
-
} else if (connection === this.oldConsumeConnection) {
|
|
1104
|
-
debug('rabbit: getConnectionOld consume', { connection });
|
|
1105
|
-
}
|
|
1106
1118
|
try {
|
|
1107
1119
|
localConnection = await this.getConnectionOld(connection);
|
|
1108
1120
|
} catch (e) {
|
|
@@ -1114,7 +1126,6 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
1114
1126
|
throw new Error(`rabbit: couldnt get connection for new channel ${name}`);
|
|
1115
1127
|
}
|
|
1116
1128
|
|
|
1117
|
-
debug('rabbit: getNewChannelOld', { localConnection });
|
|
1118
1129
|
const channel = localConnection?.createChannel({ ...options });
|
|
1119
1130
|
once(channel, 'close').then((args) => {
|
|
1120
1131
|
logger.error(`rabbit: channel ${name} closed`);
|
|
@@ -1133,18 +1144,13 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
1133
1144
|
async getConnectionOld(connection: ConnectionData) {
|
|
1134
1145
|
return new Promise<AmqpConnectionManager>(async (resolve, reject) => {
|
|
1135
1146
|
const {
|
|
1136
|
-
|
|
1147
|
+
amqpConnection: connectionLocal,
|
|
1137
1148
|
creatingConnection,
|
|
1138
1149
|
connectionCreatedEventName,
|
|
1139
1150
|
connectionFailedEventName,
|
|
1140
1151
|
blockReconnect,
|
|
1141
1152
|
} = connection;
|
|
1142
1153
|
|
|
1143
|
-
if (connection === this.oldPublishConnection) {
|
|
1144
|
-
debug('rabbit: getConnectionOld publish', { connectionLocal, creatingConnection, blockReconnect });
|
|
1145
|
-
} else if (connection === this.oldConsumeConnection) {
|
|
1146
|
-
debug('rabbit: getConnectionOld consume', { connectionLocal, creatingConnection, blockReconnect });
|
|
1147
|
-
}
|
|
1148
1154
|
if (blockReconnect) {
|
|
1149
1155
|
debug('rabbit: block reconnect');
|
|
1150
1156
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
@@ -1187,12 +1193,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
1187
1193
|
findServers,
|
|
1188
1194
|
});
|
|
1189
1195
|
|
|
1190
|
-
connection.
|
|
1191
|
-
if (connection === this.oldPublishConnection) {
|
|
1192
|
-
debug('rabbit: oldPublishConnection set');
|
|
1193
|
-
} else if (connection === this.oldConsumeConnection) {
|
|
1194
|
-
debug('rabbit: oldConsumeConnection set');
|
|
1195
|
-
}
|
|
1196
|
+
connection.amqpConnection = newConnection;
|
|
1196
1197
|
newConnection.on('error', (err) => {
|
|
1197
1198
|
logger.error('rabbit: connection error', { err });
|
|
1198
1199
|
if (!isResolved) {
|
|
@@ -1204,6 +1205,9 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
1204
1205
|
|
|
1205
1206
|
newConnection.on('connectFailed', (err) => {
|
|
1206
1207
|
this.oldConsumersTags = [];
|
|
1208
|
+
if (typeof err.url === 'string') {
|
|
1209
|
+
err.url = this.maskURL(err.url);
|
|
1210
|
+
}
|
|
1207
1211
|
logger.error('rabbit: connection connectFailed', { err });
|
|
1208
1212
|
if (!isResolved) {
|
|
1209
1213
|
isResolved = true;
|
|
@@ -1226,7 +1230,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
1226
1230
|
newConnection.once('connect', async () => {
|
|
1227
1231
|
debug('rabbit: connection established');
|
|
1228
1232
|
connection.creatingConnection = false;
|
|
1229
|
-
this.oldEm.emit(connectionCreatedEventName,
|
|
1233
|
+
this.oldEm.emit(connectionCreatedEventName, newConnection);
|
|
1230
1234
|
isResolved = true;
|
|
1231
1235
|
resolve(newConnection);
|
|
1232
1236
|
});
|
|
@@ -1300,11 +1304,6 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
1300
1304
|
}
|
|
1301
1305
|
|
|
1302
1306
|
async assertChannelOld({ force = false, connection }: assertChannelOpts): Promise<ChannelWrapper> {
|
|
1303
|
-
if (connection === this.oldPublishConnection) {
|
|
1304
|
-
debug('rabbit: assertChannelOld publish', { force, promiseSetup: this.oldPublishChannelSetupPromise });
|
|
1305
|
-
} else if (connection === this.oldConsumeConnection) {
|
|
1306
|
-
debug('rabbit: assertChannelOld consume', { force, promiseSetup: this.oldPublishChannelSetupPromise });
|
|
1307
|
-
}
|
|
1308
1307
|
if (!this.oldPublishChannelSetupPromise) {
|
|
1309
1308
|
this.oldPublishChannelSetupPromise = new Promise<ChannelWrapper>(async (resolve, reject) => {
|
|
1310
1309
|
if (this.oldPublishChannel && !force) {
|
|
@@ -1313,16 +1312,10 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
1313
1312
|
|
|
1314
1313
|
try {
|
|
1315
1314
|
const channel = await this.getNewChannelOld({ connection });
|
|
1316
|
-
if (connection === this.oldPublishConnection) {
|
|
1317
|
-
debug('rabbit: old new channel got publish', { force, channel });
|
|
1318
|
-
} else if (connection === this.oldConsumeConnection) {
|
|
1319
|
-
debug('rabbit: old new channel got consume', { force, channel });
|
|
1320
|
-
}
|
|
1321
1315
|
channel.on('error', (err) => {
|
|
1322
1316
|
logger.error('rabbit: channel error', { err });
|
|
1323
1317
|
});
|
|
1324
1318
|
if (this.oldPublishConnection === connection) {
|
|
1325
|
-
debug('rabbit: a new channel assigned to the oldPublishChannel', { connection });
|
|
1326
1319
|
this.oldPublishChannel = channel;
|
|
1327
1320
|
}
|
|
1328
1321
|
resolve(channel);
|
|
@@ -1359,6 +1352,17 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
1359
1352
|
this.oldExchanges[exchangeName] = await this.oldAssertExchangePromises[exchangeName];
|
|
1360
1353
|
return this.oldExchanges[exchangeName];
|
|
1361
1354
|
}
|
|
1355
|
+
|
|
1356
|
+
private maskURL = (url: string): string => {
|
|
1357
|
+
try {
|
|
1358
|
+
const urlObj = new URL(url);
|
|
1359
|
+
urlObj.username = '***';
|
|
1360
|
+
urlObj.password = '***';
|
|
1361
|
+
return urlObj.toString();
|
|
1362
|
+
} catch {
|
|
1363
|
+
return url;
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1362
1366
|
}
|
|
1363
1367
|
|
|
1364
1368
|
export default RabbitMq;
|
package/src/lib/types.ts
CHANGED
|
@@ -64,7 +64,7 @@ export const CONSUMER_DEFAULT_OPTIONS: Options.Consume = {
|
|
|
64
64
|
};
|
|
65
65
|
|
|
66
66
|
export type ConnectionData = {
|
|
67
|
-
|
|
67
|
+
amqpConnection: AmqpConnectionManager | null;
|
|
68
68
|
creatingConnection: boolean;
|
|
69
69
|
connectionCreatedEventName: string;
|
|
70
70
|
connectionFailedEventName: string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
// eslint-disable-next-line import/no-
|
|
1
|
+
// eslint-disable-next-line import/no-unresolved
|
|
2
2
|
import 'jest';
|
|
3
|
-
import { IAfRabbitMq } from '
|
|
3
|
+
import type { IAfRabbitMq } from '../index';
|
|
4
4
|
|
|
5
5
|
class RabbitMq implements IAfRabbitMq {
|
|
6
6
|
ack: any = jest.fn();
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { vi } from 'vitest';
|
|
2
|
+
import { IAfRabbitMq } from '../index';
|
|
3
|
+
|
|
4
|
+
class RabbitMq implements IAfRabbitMq {
|
|
5
|
+
ack = vi.fn();
|
|
6
|
+
|
|
7
|
+
nack = vi.fn();
|
|
8
|
+
|
|
9
|
+
assertChannel = vi.fn();
|
|
10
|
+
|
|
11
|
+
assertExchange = vi.fn();
|
|
12
|
+
|
|
13
|
+
assertQueue = vi.fn();
|
|
14
|
+
|
|
15
|
+
consume = vi.fn();
|
|
16
|
+
|
|
17
|
+
consumeFromExchange = vi.fn();
|
|
18
|
+
|
|
19
|
+
publish = vi.fn();
|
|
20
|
+
|
|
21
|
+
sendToQueue = vi.fn();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default RabbitMq;
|
package/tsconfig.json
CHANGED
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
"experimentalDecorators": true,
|
|
10
10
|
"emitDecoratorMetadata": true,
|
|
11
11
|
"skipLibCheck": true,
|
|
12
|
-
"
|
|
12
|
+
"sourceMap": true,
|
|
13
13
|
},
|
|
14
14
|
"exclude": ["node_modules"],
|
|
15
|
-
"include": ["src
|
|
15
|
+
"include": ["src/", "vitest.config.ts"],
|
|
16
16
|
}
|
package/vitest.config.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// eslint-disable-next-line import/no-unresolved
|
|
2
|
+
import { defineConfig } from 'vitest/config';
|
|
3
|
+
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
test: {
|
|
6
|
+
coverage: {
|
|
7
|
+
provider: 'v8',
|
|
8
|
+
include: ['src/**/*.ts'],
|
|
9
|
+
exclude: ['src/example.ts', 'src/mock/*.ts'],
|
|
10
|
+
reporter: 'text',
|
|
11
|
+
thresholds: {
|
|
12
|
+
lines: 74,
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
});
|