@autofleet/rabbit 1.6.0 → 1.6.2

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 CHANGED
@@ -11,10 +11,6 @@ export interface AfRabbitOptions {
11
11
  declare class RabbitMq {
12
12
  static parseMsg(msg: any): any;
13
13
  static validateName(type: string, name: string): void;
14
- static consumeOptions(options?: any): {
15
- limit: number;
16
- deadMessageTtl: number;
17
- };
18
14
  PUBLISH_TIMEOUT: number;
19
15
  PUBLISH_ERROR_MSG: string;
20
16
  DISCONNECT_MSG: string;
@@ -27,7 +23,7 @@ declare class RabbitMq {
27
23
  options: AfRabbitOptions | undefined;
28
24
  constructor(options?: AfRabbitOptions);
29
25
  ack: (msg: any) => Promise<void>;
30
- nack: (queue: string, deadQueueOptions?: Options.AssertQueue | undefined) => (msg: any, retries: number) => Promise<void>;
26
+ nack: (queue: string, options: any, deadQueueOptions: Options.AssertQueue) => (msg: any, { skipRetry, }?: any) => Promise<void>;
31
27
  getConnection(): Promise<AmqpConnectionManager>;
32
28
  assertChannel(): Promise<ChannelWrapper>;
33
29
  assertExchange(exchangeName: string, options?: any): Promise<any>;
package/dist/index.js CHANGED
@@ -38,6 +38,12 @@ const amqp_connection_manager_1 = require("amqp-connection-manager");
38
38
  const events_1 = require("events");
39
39
  const outbreak_1 = require("@autofleet/outbreak");
40
40
  const rabbitError_1 = __importDefault(require("./rabbitError"));
41
+ const DEFAULT_DEAD_TTL_TWO_DAYS = 60000 * 60 * 48;
42
+ const defaultOptions = {
43
+ limit: 1,
44
+ retries: 1,
45
+ deadMessageTtl: DEFAULT_DEAD_TTL_TWO_DAYS,
46
+ };
41
47
  const assertExchangeFanout = (c, exchangeName) => c.assertExchange(exchangeName, 'fanout');
42
48
  const connectionCreatedConst = 'connectionCreated';
43
49
  class RabbitMq {
@@ -51,9 +57,11 @@ class RabbitMq {
51
57
  yield this.channel.ack(msg);
52
58
  }
53
59
  });
54
- this.nack = (queue, deadQueueOptions) => (msg, retries) => __awaiter(this, void 0, void 0, function* () {
60
+ this.nack = (queue, options, deadQueueOptions) => (msg, { skipRetry = false, } = {}) => __awaiter(this, void 0, void 0, function* () {
55
61
  if (this.channel) {
56
- if (!msg.content['x-retry-count'] || msg.content['x-retry-count'] <= retries) {
62
+ if (!skipRetry
63
+ && (!msg.content['x-retry-count']
64
+ || msg.content['x-retry-count'] < options.retries)) {
57
65
  msg.content['x-retry-count'] = msg.content['x-retry-count'] ? msg.content['x-retry-count'] + 1 : 1;
58
66
  yield this.sendToQueue(queue, msg.content);
59
67
  }
@@ -86,9 +94,6 @@ class RabbitMq {
86
94
  throw new rabbitError_1.default(`error while using ${type} with no name`);
87
95
  }
88
96
  }
89
- static consumeOptions(options) {
90
- return Object.assign({ limit: 1, deadMessageTtl: null }, options);
91
- }
92
97
  getConnection() {
93
98
  return __awaiter(this, void 0, void 0, function* () {
94
99
  return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
@@ -175,18 +180,17 @@ class RabbitMq {
175
180
  }
176
181
  consume(queue, callback, options) {
177
182
  return __awaiter(this, void 0, void 0, function* () {
183
+ const optionsWithDefaults = Object.assign(Object.assign({}, defaultOptions), options);
178
184
  RabbitMq.validateName('queue', queue);
179
- const { limit, deadMessageTtl } = RabbitMq.consumeOptions(options);
185
+ const { limit, deadMessageTtl } = optionsWithDefaults;
180
186
  const channel = yield this.assertChannel();
181
187
  return channel.addSetup((c) => __awaiter(this, void 0, void 0, function* () {
182
188
  yield c.assertQueue(queue);
183
189
  yield c.prefetch(limit, true);
184
190
  return Promise.all([
185
191
  c.consume(queue, (msg) => {
186
- setImmediate(() => {
187
- outbreak_1.newTrace(outbreak_1.traceTypes.RABBIT);
188
- callback(RabbitMq.parseMsg(msg), this.ack, this.nack(queue, { messageTtl: deadMessageTtl }));
189
- });
192
+ outbreak_1.newTrace(outbreak_1.traceTypes.RABBIT);
193
+ callback(RabbitMq.parseMsg(msg), this.ack, this.nack(queue, optionsWithDefaults, { messageTtl: deadMessageTtl }));
190
194
  }),
191
195
  ]);
192
196
  }));
@@ -194,9 +198,10 @@ class RabbitMq {
194
198
  }
195
199
  consumeFromExchange(queue, exchange, callback, options) {
196
200
  return __awaiter(this, void 0, void 0, function* () {
197
- RabbitMq.validateName('queue', queue);
201
+ const optionsWithDefaults = Object.assign(Object.assign({}, defaultOptions), options);
198
202
  RabbitMq.validateName('exchange', exchange);
199
- const { limit, deadMessageTtl } = RabbitMq.consumeOptions(options);
203
+ RabbitMq.validateName('queue', queue);
204
+ const { limit, deadMessageTtl } = optionsWithDefaults;
200
205
  const channel = yield this.assertChannel();
201
206
  return channel.addSetup((c) => __awaiter(this, void 0, void 0, function* () {
202
207
  const assertExchange = yield assertExchangeFanout(c, exchange);
@@ -206,10 +211,8 @@ class RabbitMq {
206
211
  return Promise.all([
207
212
  c.bindQueue(queue, exchange, ''),
208
213
  c.consume(queue, (msg) => {
209
- setImmediate(() => {
210
- outbreak_1.newTrace(outbreak_1.traceTypes.RABBIT);
211
- callback(RabbitMq.parseMsg(msg), this.ack, this.nack(queue, { messageTtl: deadMessageTtl }));
212
- });
214
+ outbreak_1.newTrace(outbreak_1.traceTypes.RABBIT);
215
+ callback(RabbitMq.parseMsg(msg), this.ack, this.nack(queue, optionsWithDefaults, { messageTtl: deadMessageTtl }));
213
216
  }),
214
217
  ]);
215
218
  }));
@@ -16,30 +16,60 @@ Object.defineProperty(exports, "__esModule", { value: true });
16
16
  const index_1 = __importDefault(require("./index"));
17
17
  jest.setTimeout(120000);
18
18
  const rabbit = new index_1.default();
19
- const delay = () => new Promise((resolve) => setTimeout(() => resolve(), 500));
19
+ const delay = (ms = 500) => new Promise((resolve) => setTimeout(() => resolve(), ms));
20
+ const callback = (eq = 'hey') => (msg, ack) => {
21
+ expect(msg.content).toEqual(eq);
22
+ ack(msg);
23
+ };
24
+ const nackcallback = ({ skipRetry = false } = {}) => (msg, ack, nack) => {
25
+ console.log('msg', msg.content);
26
+ expect(msg.content.ttt).toEqual('hey-q');
27
+ if (skipRetry) {
28
+ nack(msg, { skipRetry });
29
+ }
30
+ else {
31
+ nack(msg);
32
+ }
33
+ };
20
34
  describe('RabbitMQ', () => {
21
35
  it('check exchange', () => __awaiter(void 0, void 0, void 0, function* () {
22
- const callback = (msg, ack) => {
23
- expect(msg.content).toEqual('hey');
24
- ack(msg);
25
- };
26
- const mockFn = jest.fn(callback);
36
+ const mockFn = jest.fn(callback());
27
37
  yield rabbit.consumeFromExchange('test-q2', 'test-e', mockFn);
28
38
  yield rabbit.publish('test-e', 'hey');
29
39
  yield delay();
30
40
  expect(mockFn).toBeCalled();
31
41
  }));
32
42
  it('check queue', () => __awaiter(void 0, void 0, void 0, function* () {
33
- const callback = (msg, ack) => {
34
- expect(msg.content).toEqual('hey-q');
35
- ack(msg);
36
- };
37
- const mockFn = jest.fn(callback);
43
+ const mockFn = jest.fn(callback('hey-q'));
38
44
  yield rabbit.consume('test-q-2', mockFn);
39
45
  yield rabbit.sendToQueue('test-q-2', 'hey-q');
40
46
  yield delay();
41
47
  expect(mockFn).toBeCalled();
42
48
  }));
49
+ it('check retry', () => __awaiter(void 0, void 0, void 0, function* () {
50
+ const mockFn = jest.fn(nackcallback());
51
+ yield rabbit.consume('test-q-retry', mockFn, { retries: 3 });
52
+ yield rabbit.sendToQueue('test-q-retry', { ttt: 'hey-q' });
53
+ yield delay(1500);
54
+ expect(mockFn).toHaveBeenCalledTimes(4); // one run then 3 times retry
55
+ }));
56
+ it('check skip retry', () => __awaiter(void 0, void 0, void 0, function* () {
57
+ const mockFn = jest.fn(nackcallback({ skipRetry: true }));
58
+ yield rabbit.consume('test-q-skip-retry', mockFn, { retries: 3 });
59
+ yield rabbit.sendToQueue('test-q-skip-retry', { ttt: 'hey-q' });
60
+ yield delay(1500);
61
+ expect(mockFn).toHaveBeenCalledTimes(1);
62
+ }));
63
+ it('check nack and dead queue', () => __awaiter(void 0, void 0, void 0, function* () {
64
+ const mockFn = jest.fn(nackcallback());
65
+ yield rabbit.consume('test-q-nack', mockFn);
66
+ yield rabbit.sendToQueue('test-q-nack', { ttt: 'hey-q' });
67
+ yield delay(1000);
68
+ expect(mockFn).toHaveBeenCalledTimes(2); // one run then 1 time retry
69
+ yield delay();
70
+ const length = yield rabbit.getQueueLength('test-q-nack-dead');
71
+ expect(length.messageCount).toEqual(1);
72
+ }));
43
73
  it('cant publish to unknown exchange', () => __awaiter(void 0, void 0, void 0, function* () {
44
74
  let err;
45
75
  try {
@@ -76,10 +106,7 @@ describe('RabbitMQ', () => {
76
106
  yield rabbit.publish(exchangeName, 'hey');
77
107
  ({ messageCount } = yield rabbit.getQueueLength(queueName));
78
108
  expect(messageCount).toEqual(2);
79
- yield rabbit.consumeFromExchange(queueName, exchangeName, (msg, ack) => __awaiter(void 0, void 0, void 0, function* () {
80
- expect(msg.content).toEqual('hey');
81
- ack(msg);
82
- }));
109
+ yield rabbit.consumeFromExchange(queueName, exchangeName, callback());
83
110
  yield delay();
84
111
  ({ messageCount } = yield rabbit.getQueueLength(queueName));
85
112
  expect(messageCount).toEqual(0);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autofleet/rabbit",
3
- "version": "1.6.0",
3
+ "version": "1.6.2",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
package/src/index.test.ts CHANGED
@@ -5,15 +5,26 @@ jest.setTimeout(120000);
5
5
 
6
6
  const rabbit = new RabbitMq();
7
7
 
8
- const delay = () => new Promise((resolve) => setTimeout(() => resolve(), 500));
8
+ const delay = (ms = 500) => new Promise((resolve) => setTimeout(() => resolve(), ms));
9
+
10
+ const callback = (eq = 'hey') => (msg: any, ack: any) => {
11
+ expect(msg.content).toEqual(eq);
12
+ ack(msg);
13
+ };
14
+
15
+ const nackcallback = ({ skipRetry = false } = { }) => (msg: any, ack: any, nack: any) => {
16
+ console.log('msg', msg.content);
17
+ expect(msg.content.ttt).toEqual('hey-q');
18
+ if (skipRetry) {
19
+ nack(msg, { skipRetry });
20
+ } else {
21
+ nack(msg);
22
+ }
23
+ };
9
24
 
10
25
  describe('RabbitMQ', () => {
11
26
  it('check exchange', async () => {
12
- const callback = (msg: any, ack: any) => {
13
- expect(msg.content).toEqual('hey');
14
- ack(msg);
15
- };
16
- const mockFn = jest.fn(callback);
27
+ const mockFn = jest.fn(callback());
17
28
  await rabbit.consumeFromExchange('test-q2', 'test-e', mockFn);
18
29
  await rabbit.publish('test-e', 'hey');
19
30
  await delay();
@@ -21,17 +32,40 @@ describe('RabbitMQ', () => {
21
32
  });
22
33
 
23
34
  it('check queue', async () => {
24
- const callback = (msg: any, ack: any) => {
25
- expect(msg.content).toEqual('hey-q');
26
- ack(msg);
27
- };
28
- const mockFn = jest.fn(callback);
35
+ const mockFn = jest.fn(callback('hey-q'));
29
36
  await rabbit.consume('test-q-2', mockFn);
30
37
  await rabbit.sendToQueue('test-q-2', 'hey-q');
31
38
  await delay();
32
39
  expect(mockFn).toBeCalled();
33
40
  });
34
41
 
42
+ it('check retry', async () => {
43
+ const mockFn = jest.fn(nackcallback());
44
+ await rabbit.consume('test-q-retry', mockFn, { retries: 3 });
45
+ await rabbit.sendToQueue('test-q-retry', { ttt: 'hey-q' });
46
+ await delay(1500);
47
+ expect(mockFn).toHaveBeenCalledTimes(4); // one run then 3 times retry
48
+ });
49
+
50
+ it('check skip retry', async () => {
51
+ const mockFn = jest.fn(nackcallback({ skipRetry: true }));
52
+ await rabbit.consume('test-q-skip-retry', mockFn, { retries: 3 });
53
+ await rabbit.sendToQueue('test-q-skip-retry', { ttt: 'hey-q' });
54
+ await delay(1500);
55
+ expect(mockFn).toHaveBeenCalledTimes(1);
56
+ });
57
+
58
+ it('check nack and dead queue', async () => {
59
+ const mockFn = jest.fn(nackcallback());
60
+ await rabbit.consume('test-q-nack', mockFn);
61
+ await rabbit.sendToQueue('test-q-nack', { ttt: 'hey-q' });
62
+ await delay(1000);
63
+ expect(mockFn).toHaveBeenCalledTimes(2); // one run then 1 time retry
64
+ await delay();
65
+ const length = await rabbit.getQueueLength('test-q-nack-dead');
66
+ expect(length.messageCount).toEqual(1);
67
+ });
68
+
35
69
  it('cant publish to unknown exchange', async () => {
36
70
  let err;
37
71
  try {
@@ -71,10 +105,7 @@ describe('RabbitMQ', () => {
71
105
  await rabbit.publish(exchangeName, 'hey');
72
106
  ({ messageCount } = await rabbit.getQueueLength(queueName));
73
107
  expect(messageCount).toEqual(2);
74
- await rabbit.consumeFromExchange(queueName, exchangeName, async (msg: any, ack: any) => {
75
- expect(msg.content).toEqual('hey');
76
- ack(msg);
77
- });
108
+ await rabbit.consumeFromExchange(queueName, exchangeName, callback());
78
109
  await delay();
79
110
  ({ messageCount } = await rabbit.getQueueLength(queueName));
80
111
  expect(messageCount).toEqual(0);
package/src/index.ts CHANGED
@@ -15,6 +15,14 @@ export interface AfRabbitOptions {
15
15
  reconnect: boolean
16
16
  }
17
17
 
18
+ const DEFAULT_DEAD_TTL_TWO_DAYS = 60000 * 60 * 48;
19
+
20
+ const defaultOptions = {
21
+ limit: 1,
22
+ retries: 1,
23
+ deadMessageTtl: DEFAULT_DEAD_TTL_TWO_DAYS,
24
+ };
25
+
18
26
  const assertExchangeFanout = (c: any, exchangeName: string) => c.assertExchange(exchangeName, 'fanout');
19
27
 
20
28
  const connectionCreatedConst = 'connectionCreated';
@@ -39,14 +47,6 @@ class RabbitMq {
39
47
  }
40
48
  }
41
49
 
42
- static consumeOptions(options?: any): {limit: number, deadMessageTtl: number} {
43
- return {
44
- limit: 1,
45
- deadMessageTtl: null,
46
- ...options,
47
- };
48
- }
49
-
50
50
  PUBLISH_TIMEOUT = Number(process.env.RABBITMQ_PUBLISH_TIMEOUT) || 60000;
51
51
 
52
52
  PUBLISH_ERROR_MSG = `rabbit: publish timeout(${this.PUBLISH_TIMEOUT}ms) has pass, exchange: `;
@@ -82,9 +82,22 @@ class RabbitMq {
82
82
  }
83
83
  }
84
84
 
85
- public nack = (queue: string, deadQueueOptions?: Options.AssertQueue) => async (msg: any, retries: number) => {
85
+ public nack = (
86
+ queue: string,
87
+ options: any,
88
+ deadQueueOptions: Options.AssertQueue,
89
+ ) => async (
90
+ msg: any,
91
+ {
92
+ skipRetry = false,
93
+ }: any = { },
94
+ ) => {
86
95
  if (this.channel) {
87
- if (!msg.content['x-retry-count'] || msg.content['x-retry-count'] <= retries) {
96
+ if (
97
+ !skipRetry
98
+ && (!msg.content['x-retry-count']
99
+ || msg.content['x-retry-count'] < options.retries)
100
+ ) {
88
101
  msg.content['x-retry-count'] = msg.content['x-retry-count'] ? msg.content['x-retry-count'] + 1 : 1;
89
102
  await this.sendToQueue(queue, msg.content);
90
103
  } else {
@@ -175,8 +188,9 @@ class RabbitMq {
175
188
  }
176
189
 
177
190
  async consume(queue: string, callback: (msg: any, ack: Function, nack: Function) => any, options?: any) {
191
+ const optionsWithDefaults = { ...defaultOptions, ...options };
178
192
  RabbitMq.validateName('queue', queue);
179
- const { limit, deadMessageTtl } = RabbitMq.consumeOptions(options);
193
+ const { limit, deadMessageTtl } = optionsWithDefaults;
180
194
  const channel: ChannelWrapper = await this.assertChannel();
181
195
  return channel.addSetup(async (c: ConfirmChannel) => {
182
196
  await c.assertQueue(queue);
@@ -185,10 +199,8 @@ class RabbitMq {
185
199
  c.consume(
186
200
  queue,
187
201
  (msg: any) => {
188
- setImmediate(() => {
189
- newTrace(traceTypes.RABBIT);
190
- callback(RabbitMq.parseMsg(msg), this.ack, this.nack(queue, { messageTtl: deadMessageTtl }));
191
- })
202
+ newTrace(traceTypes.RABBIT);
203
+ callback(RabbitMq.parseMsg(msg), this.ack, this.nack(queue, optionsWithDefaults, { messageTtl: deadMessageTtl }));
192
204
  },
193
205
  ),
194
206
  ]);
@@ -196,9 +208,10 @@ class RabbitMq {
196
208
  }
197
209
 
198
210
  async consumeFromExchange(queue: string, exchange: string, callback: (msg: any, ack: Function, nack: Function) => any, options?: any) {
199
- RabbitMq.validateName('queue', queue);
211
+ const optionsWithDefaults = { ...defaultOptions, ...options };
200
212
  RabbitMq.validateName('exchange', exchange);
201
- const { limit, deadMessageTtl } = RabbitMq.consumeOptions(options);
213
+ RabbitMq.validateName('queue', queue);
214
+ const { limit, deadMessageTtl } = optionsWithDefaults;
202
215
  const channel: ChannelWrapper = await this.assertChannel();
203
216
 
204
217
  return channel.addSetup(async (c: ConfirmChannel) => {
@@ -211,10 +224,8 @@ class RabbitMq {
211
224
  c.consume(
212
225
  queue,
213
226
  (msg: any) => {
214
- setImmediate(() => {
215
- newTrace(traceTypes.RABBIT);
216
- callback(RabbitMq.parseMsg(msg), this.ack, this.nack(queue, { messageTtl: deadMessageTtl }));
217
- })
227
+ newTrace(traceTypes.RABBIT);
228
+ callback(RabbitMq.parseMsg(msg), this.ack, this.nack(queue, optionsWithDefaults, { messageTtl: deadMessageTtl }));
218
229
  },
219
230
  ),
220
231
  ]);