@autofleet/rabbit 2.3.2 → 2.3.5

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
@@ -62,8 +62,8 @@ declare class RabbitMq implements IAfRabbitMq {
62
62
  redisLock?: RedisLockType;
63
63
  constructor(options?: AfRabbitOptions, redisConfig?: RedisConfig);
64
64
  private shouldConsumeMessageByTimestamp;
65
- ack: (channel: ChannelWrapper, msg: ConsumeMessageOrNull, shouldUpdateRedisTimestamp?: boolean) => (userMsg: ConsumeMessage) => Promise<any>;
66
- nack: (channel: ChannelWrapper, queue: string, options: any, deadQueueOptions: Options.AssertQueue, msg: ConsumeMessageOrNull) => (userMsg: ConsumeMessageOrNull, { skipRetry, }?: any) => Promise<any>;
65
+ ack: (channel: ChannelWrapper, msg: ConsumeMessageOrNull, shouldUpdateRedisTimestamp?: boolean, releaseLock?: null) => (userMsg: ConsumeMessage) => Promise<any>;
66
+ nack: (channel: ChannelWrapper, queue: string, options: any, deadQueueOptions: Options.AssertQueue, msg: ConsumeMessageOrNull, releaseLock: any) => (userMsg: ConsumeMessageOrNull, { skipRetry, }?: any) => Promise<any>;
67
67
  getConnection(): Promise<AmqpConnectionManager>;
68
68
  getNewChannel(): Promise<ChannelWrapper>;
69
69
  assertChannel(): Promise<ChannelWrapper>;
@@ -72,7 +72,8 @@ declare class RabbitMq implements IAfRabbitMq {
72
72
  bindQueue(queue: string, exchange: string): Promise<void>;
73
73
  assertQueue(queueName: string, options?: Options.AssertQueue): Promise<any>;
74
74
  consume(queue: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<any>;
75
- private consumeWithLock;
75
+ private lockRedisIfNeeded;
76
+ private unlockRedisIfNeeded;
76
77
  private consumeFromRabbit;
77
78
  consumeFromExchange(queue: string, exchange: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<any>;
78
79
  publish(exchange: string, content: any, customHeaders?: any): Promise<boolean>;
package/dist/index.js CHANGED
@@ -26,12 +26,15 @@ const redis_1 = __importDefault(require("./redis"));
26
26
  const DEFAULT_DEAD_TTL_TWO_DAYS = 60000 * 60 * 48;
27
27
  const DEFAULT_LOCK_TIMEOUT = 1000 * 5;
28
28
  const RETRY_HEADER = 'x-retry-count';
29
+ const DEFAULT_USE_CONSUME_WITH_LOCK = false;
29
30
  const defaultOptions = {
30
31
  limit: 1,
31
32
  retries: 1,
32
33
  deadMessageTtl: DEFAULT_DEAD_TTL_TWO_DAYS,
34
+ lockTimeout: DEFAULT_LOCK_TIMEOUT,
35
+ useConsumeWithLock: DEFAULT_USE_CONSUME_WITH_LOCK,
33
36
  };
34
- const assertExchangeFanout = (c, exchangeName) => c.assertExchange(exchangeName, 'fanout');
37
+ const assertExchangeFanout = (c, exchangeName) => __awaiter(void 0, void 0, void 0, function* () { return c.assertExchange(exchangeName, 'fanout'); });
35
38
  const connectionCreatedConst = 'connectionCreated';
36
39
  const wrapSetImmediate = (callback) => new Promise((resolve, reject) => __awaiter(void 0, void 0, void 0, function* () {
37
40
  setImmediate(() => __awaiter(void 0, void 0, void 0, function* () {
@@ -62,7 +65,7 @@ class RabbitMq {
62
65
  }
63
66
  return false;
64
67
  });
65
- this.ack = (channel, msg, shouldUpdateRedisTimestamp = false) => (userMsg) => __awaiter(this, void 0, void 0, function* () {
68
+ this.ack = (channel, msg, shouldUpdateRedisTimestamp = false, releaseLock = null) => (userMsg) => __awaiter(this, void 0, void 0, function* () {
66
69
  if (msg) {
67
70
  yield channel.ack(msg);
68
71
  const { properties: { headers } } = msg;
@@ -70,10 +73,12 @@ class RabbitMq {
70
73
  if (shouldUpdateRedisTimestamp && timestamp && (headers === null || headers === void 0 ? void 0 : headers.redisTimestampValidationKey) && this.redisClient) {
71
74
  const parsedTimestamp = parseInt(timestamp, 10);
72
75
  yield this.redisClient.setAsync(headers.redisTimestampValidationKey, parsedTimestamp, 'EX', 3600);
76
+ yield this.unlockRedisIfNeeded(releaseLock);
73
77
  }
74
78
  }
75
79
  });
76
- this.nack = (channel, queue, options, deadQueueOptions, msg) => (userMsg, { skipRetry = false, } = {}) => __awaiter(this, void 0, void 0, function* () {
80
+ this.nack = (channel, queue, options, deadQueueOptions, msg, releaseLock) => (userMsg, { skipRetry = false, } = {}) => __awaiter(this, void 0, void 0, function* () {
81
+ yield this.unlockRedisIfNeeded(releaseLock);
77
82
  if (channel && msg) {
78
83
  if (!skipRetry
79
84
  && (!msg.properties.headers[RETRY_HEADER]
@@ -173,7 +178,7 @@ class RabbitMq {
173
178
  try {
174
179
  const connection = yield this.getConnection();
175
180
  if (this.channel === null) {
176
- this.channel = connection.createChannel({});
181
+ this.channel = yield connection.createChannel({});
177
182
  }
178
183
  resolve(this.channel);
179
184
  }
@@ -205,6 +210,7 @@ class RabbitMq {
205
210
  bindQueue(queue, exchange) {
206
211
  return __awaiter(this, void 0, void 0, function* () {
207
212
  const channel = yield this.assertChannel();
213
+ yield channel.addSetup((setupChannel) => setupChannel.bindQueue(queue, exchange, ''));
208
214
  // @ts-ignore
209
215
  return channel.bindQueue(queue, exchange, '');
210
216
  });
@@ -216,6 +222,7 @@ class RabbitMq {
216
222
  if (this.queues[queueName]) {
217
223
  return this.queues[queueName];
218
224
  }
225
+ yield channel.addSetup((setupChannel) => setupChannel.assertQueue(queueName, options));
219
226
  const queue = yield channel.assertQueue(queueName, options);
220
227
  this.queues[queueName] = queueName;
221
228
  return queue;
@@ -223,52 +230,38 @@ class RabbitMq {
223
230
  }
224
231
  consume(queue, callback, options) {
225
232
  return __awaiter(this, void 0, void 0, function* () {
226
- if (options && options.useConsumeWithLock) {
227
- return this.consumeWithLock(queue, callback, options);
228
- }
229
233
  return this.consumeFromRabbit(queue, callback, options);
230
234
  });
231
235
  }
232
- consumeWithLock(queue, callback, options) {
236
+ lockRedisIfNeeded(msg, options) {
233
237
  return __awaiter(this, void 0, void 0, function* () {
234
- if (!this.redisLock) {
235
- throw new Error('Usage of consumeWithLock requires RedisInstance');
238
+ const { properties: { headers } } = msg;
239
+ const timestamp = headers === null || headers === void 0 ? void 0 : headers.creationTimestamp;
240
+ let releaseLock = null;
241
+ if (options.useConsumeWithLock && timestamp && (headers === null || headers === void 0 ? void 0 : headers.redisTimestampValidationKey) && this.redisLock) {
242
+ releaseLock = yield this.redisLock(headers.redisTimestampValidationKey, (options === null || options === void 0 ? void 0 : options.lockTimeout) || DEFAULT_LOCK_TIMEOUT);
243
+ }
244
+ return releaseLock;
245
+ });
246
+ }
247
+ unlockRedisIfNeeded(releaseLock) {
248
+ return __awaiter(this, void 0, void 0, function* () {
249
+ if (this.redisLock && releaseLock) {
250
+ yield releaseLock();
236
251
  }
237
- const lockTimeout = (options === null || options === void 0 ? void 0 : options.lockTimeout) || DEFAULT_LOCK_TIMEOUT;
238
- logger_1.default.info(`Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
239
- return this.consumeFromRabbit(queue, (msg, ack, nack) => __awaiter(this, void 0, void 0, function* () {
240
- logger_1.default.info('Logs ');
241
- if (!msg) {
242
- return null;
243
- }
244
- const { properties: { headers } } = msg;
245
- const timestamp = headers === null || headers === void 0 ? void 0 : headers.creationTimestamp;
246
- let releaseLock = null;
247
- try {
248
- if (timestamp && (headers === null || headers === void 0 ? void 0 : headers.redisTimestampValidationKey)) {
249
- if (this.redisLock) {
250
- releaseLock = yield this.redisLock(headers.redisTimestampValidationKey, lockTimeout);
251
- yield callback(msg, ack, nack);
252
- yield releaseLock();
253
- return;
254
- }
255
- }
256
- yield callback(msg, ack, nack);
257
- }
258
- catch (err) {
259
- if (releaseLock) {
260
- yield releaseLock();
261
- }
262
- throw err;
263
- }
264
- }), options);
265
252
  });
266
253
  }
267
254
  consumeFromRabbit(queue, callback, options) {
268
255
  return __awaiter(this, void 0, void 0, function* () {
269
256
  const optionsWithDefaults = Object.assign(Object.assign({}, defaultOptions), options);
270
257
  RabbitMq.validateName('queue', queue);
271
- const { limit, deadMessageTtl } = optionsWithDefaults;
258
+ const { limit, deadMessageTtl, useConsumeWithLock, lockTimeout, } = optionsWithDefaults;
259
+ if (useConsumeWithLock) {
260
+ if (!this.redisLock) {
261
+ throw new Error('Usage of consumeWithLock requires RedisInstance');
262
+ }
263
+ logger_1.default.info(`Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
264
+ }
272
265
  const channel = yield this.getNewChannel();
273
266
  return channel.addSetup((c) => __awaiter(this, void 0, void 0, function* () {
274
267
  yield c.assertQueue(queue);
@@ -279,15 +272,17 @@ class RabbitMq {
279
272
  return null;
280
273
  }
281
274
  const parsedMessage = RabbitMq.parseMsg(msg);
275
+ const releaseLock = yield this.lockRedisIfNeeded(parsedMessage, optionsWithDefaults);
282
276
  const shouldConsume = yield this.shouldConsumeMessageByTimestamp(parsedMessage);
283
277
  if (!shouldConsume) {
278
+ yield this.unlockRedisIfNeeded(releaseLock);
284
279
  return this.ack(channel, msg)(msg);
285
280
  }
286
281
  try {
287
- yield callback(parsedMessage, this.ack(channel, msg, true), this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg));
282
+ yield callback(parsedMessage, this.ack(channel, msg, true, releaseLock), this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock));
288
283
  }
289
284
  catch (e) {
290
- yield this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg)(msg);
285
+ yield this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg);
291
286
  }
292
287
  })),
293
288
  ]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autofleet/rabbit",
3
- "version": "2.3.2",
3
+ "version": "2.3.5",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
package/src/index.ts CHANGED
@@ -55,14 +55,17 @@ export interface AfRabbitOptions {
55
55
  const DEFAULT_DEAD_TTL_TWO_DAYS = 60000 * 60 * 48;
56
56
  const DEFAULT_LOCK_TIMEOUT = 1000 * 5;
57
57
  const RETRY_HEADER = 'x-retry-count';
58
+ const DEFAULT_USE_CONSUME_WITH_LOCK = false;
58
59
 
59
60
  const defaultOptions = {
60
61
  limit: 1,
61
62
  retries: 1,
62
63
  deadMessageTtl: DEFAULT_DEAD_TTL_TWO_DAYS,
64
+ lockTimeout: DEFAULT_LOCK_TIMEOUT,
65
+ useConsumeWithLock: DEFAULT_USE_CONSUME_WITH_LOCK,
63
66
  };
64
67
 
65
- const assertExchangeFanout = (c: any, exchangeName: string) => c.assertExchange(exchangeName, 'fanout');
68
+ const assertExchangeFanout = async (c: any, exchangeName: string) => c.assertExchange(exchangeName, 'fanout');
66
69
 
67
70
  const connectionCreatedConst = 'connectionCreated';
68
71
 
@@ -162,7 +165,7 @@ class RabbitMq implements IAfRabbitMq {
162
165
  return false;
163
166
  }
164
167
 
165
- public ack = (channel: ChannelWrapper, msg: ConsumeMessageOrNull, shouldUpdateRedisTimestamp = false) => async (userMsg: ConsumeMessage) : Promise<any> => {
168
+ public ack = (channel: ChannelWrapper, msg: ConsumeMessageOrNull, shouldUpdateRedisTimestamp = false, releaseLock = null) => async (userMsg: ConsumeMessage) : Promise<any> => {
166
169
  if (msg) {
167
170
  await channel.ack(msg);
168
171
  const { properties: { headers } } = msg;
@@ -171,6 +174,7 @@ class RabbitMq implements IAfRabbitMq {
171
174
  if (shouldUpdateRedisTimestamp && timestamp && headers?.redisTimestampValidationKey && this.redisClient) {
172
175
  const parsedTimestamp = parseInt(timestamp, 10);
173
176
  await this.redisClient.setAsync(headers.redisTimestampValidationKey, parsedTimestamp, 'EX', 3600);
177
+ await this.unlockRedisIfNeeded(releaseLock);
174
178
  }
175
179
  }
176
180
  }
@@ -181,12 +185,14 @@ class RabbitMq implements IAfRabbitMq {
181
185
  options: any,
182
186
  deadQueueOptions: Options.AssertQueue,
183
187
  msg: ConsumeMessageOrNull,
188
+ releaseLock: any,
184
189
  ) => async (
185
190
  userMsg: ConsumeMessageOrNull,
186
191
  {
187
192
  skipRetry = false,
188
193
  }: any = { },
189
194
  ) : Promise<any> => {
195
+ await this.unlockRedisIfNeeded(releaseLock);
190
196
  if (channel && msg) {
191
197
  if (
192
198
  !skipRetry
@@ -261,7 +267,7 @@ class RabbitMq implements IAfRabbitMq {
261
267
  try {
262
268
  const connection: AmqpConnectionManager = await this.getConnection();
263
269
  if (this.channel === null) {
264
- this.channel = connection.createChannel({});
270
+ this.channel = await connection.createChannel({});
265
271
  }
266
272
  resolve(this.channel);
267
273
  } catch (e) {
@@ -289,6 +295,7 @@ class RabbitMq implements IAfRabbitMq {
289
295
 
290
296
  async bindQueue(queue: string, exchange: string) {
291
297
  const channel: ChannelWrapper = await this.assertChannel();
298
+ await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.bindQueue(queue, exchange, ''));
292
299
  // @ts-ignore
293
300
  return channel.bindQueue(queue, exchange, '');
294
301
  }
@@ -299,59 +306,48 @@ class RabbitMq implements IAfRabbitMq {
299
306
  if (this.queues[queueName]) {
300
307
  return this.queues[queueName];
301
308
  }
309
+ await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.assertQueue(queueName, options));
302
310
  const queue = await channel.assertQueue(queueName, options);
303
311
  this.queues[queueName] = queueName;
304
312
  return queue;
305
313
  }
306
314
 
307
315
  async consume(queue: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<any> {
308
- if (options && options.useConsumeWithLock) {
309
- return this.consumeWithLock(queue, callback, options);
310
- }
311
316
  return this.consumeFromRabbit(queue, callback, options);
312
317
  }
313
318
 
314
- private async consumeWithLock(queue: string, callback: CallbackFunction, options?: ConsumeOptions) : Promise<any> {
315
- if (!this.redisLock) {
316
- throw new Error('Usage of consumeWithLock requires RedisInstance');
319
+ private async lockRedisIfNeeded(msg: any, options: any) {
320
+ const { properties: { headers } } = msg;
321
+ const timestamp = headers?.creationTimestamp;
322
+ let releaseLock = null;
323
+
324
+ if (options.useConsumeWithLock && timestamp && headers?.redisTimestampValidationKey && this.redisLock) {
325
+ releaseLock = await this.redisLock(
326
+ headers.redisTimestampValidationKey,
327
+ options?.lockTimeout || DEFAULT_LOCK_TIMEOUT,
328
+ );
317
329
  }
318
- const lockTimeout = options?.lockTimeout || DEFAULT_LOCK_TIMEOUT;
319
- logger.info(`Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
320
- return this.consumeFromRabbit(queue, async (msg, ack, nack) => {
321
- logger.info('Logs ');
322
- if (!msg) {
323
- return null;
324
- }
325
- const { properties: { headers } } = msg;
326
- const timestamp = headers?.creationTimestamp;
327
- let releaseLock = null;
330
+ return releaseLock;
331
+ }
328
332
 
329
- try {
330
- if (timestamp && headers?.redisTimestampValidationKey) {
331
- if (this.redisLock) {
332
- releaseLock = await this.redisLock(
333
- headers.redisTimestampValidationKey,
334
- lockTimeout,
335
- );
336
- await callback(msg, ack, nack);
337
- await releaseLock();
338
- return;
339
- }
340
- }
341
- await callback(msg, ack, nack);
342
- } catch (err) {
343
- if (releaseLock) {
344
- await releaseLock();
345
- }
346
- throw err;
347
- }
348
- }, options);
333
+ private async unlockRedisIfNeeded(releaseLock: any) {
334
+ if (this.redisLock && releaseLock) {
335
+ await releaseLock();
336
+ }
349
337
  }
350
338
 
351
339
  private async consumeFromRabbit(queue: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<any> {
352
340
  const optionsWithDefaults = { ...defaultOptions, ...options };
353
341
  RabbitMq.validateName('queue', queue);
354
- const { limit, deadMessageTtl } = optionsWithDefaults;
342
+ const {
343
+ limit, deadMessageTtl, useConsumeWithLock, lockTimeout,
344
+ } = optionsWithDefaults;
345
+ if (useConsumeWithLock) {
346
+ if (!this.redisLock) {
347
+ throw new Error('Usage of consumeWithLock requires RedisInstance');
348
+ }
349
+ logger.info(`Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
350
+ }
355
351
  const channel: ChannelWrapper = await this.getNewChannel();
356
352
  return channel.addSetup(async (c: ConfirmChannel) => {
357
353
  await c.assertQueue(queue);
@@ -364,18 +360,20 @@ class RabbitMq implements IAfRabbitMq {
364
360
  return null;
365
361
  }
366
362
  const parsedMessage = RabbitMq.parseMsg(msg);
363
+ const releaseLock = await this.lockRedisIfNeeded(parsedMessage, optionsWithDefaults);
367
364
  const shouldConsume = await this.shouldConsumeMessageByTimestamp(parsedMessage);
368
365
  if (!shouldConsume) {
366
+ await this.unlockRedisIfNeeded(releaseLock);
369
367
  return this.ack(channel, msg)(msg);
370
368
  }
371
369
  try {
372
370
  await callback(
373
371
  parsedMessage,
374
- this.ack(channel, msg, true),
375
- this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg),
372
+ this.ack(channel, msg, true, releaseLock),
373
+ this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock),
376
374
  );
377
375
  } catch (e) {
378
- await this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg)(msg);
376
+ await this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg);
379
377
  }
380
378
  },
381
379
  ),