@autofleet/rabbit 2.3.1 → 2.3.4
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 +4 -3
- package/dist/index.js +32 -40
- package/package.json +1 -1
- package/src/index.ts +37 -42
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
|
|
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,10 +26,13 @@ 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
37
|
const assertExchangeFanout = (c, exchangeName) => c.assertExchange(exchangeName, 'fanout');
|
|
35
38
|
const connectionCreatedConst = 'connectionCreated';
|
|
@@ -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]
|
|
@@ -223,52 +228,38 @@ class RabbitMq {
|
|
|
223
228
|
}
|
|
224
229
|
consume(queue, callback, options) {
|
|
225
230
|
return __awaiter(this, void 0, void 0, function* () {
|
|
226
|
-
if (options && options.useConsumeWithLock) {
|
|
227
|
-
return this.consumeWithLock(queue, callback, options);
|
|
228
|
-
}
|
|
229
231
|
return this.consumeFromRabbit(queue, callback, options);
|
|
230
232
|
});
|
|
231
233
|
}
|
|
232
|
-
|
|
234
|
+
lockRedisIfNeeded(msg, options) {
|
|
233
235
|
return __awaiter(this, void 0, void 0, function* () {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
+
const { properties: { headers } } = msg;
|
|
237
|
+
const timestamp = headers === null || headers === void 0 ? void 0 : headers.creationTimestamp;
|
|
238
|
+
let releaseLock = null;
|
|
239
|
+
if (options.useConsumeWithLock && timestamp && (headers === null || headers === void 0 ? void 0 : headers.redisTimestampValidationKey) && this.redisLock) {
|
|
240
|
+
releaseLock = yield this.redisLock(headers.redisTimestampValidationKey, (options === null || options === void 0 ? void 0 : options.lockTimeout) || DEFAULT_LOCK_TIMEOUT);
|
|
241
|
+
}
|
|
242
|
+
return releaseLock;
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
unlockRedisIfNeeded(releaseLock) {
|
|
246
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
247
|
+
if (this.redisLock && releaseLock) {
|
|
248
|
+
yield releaseLock();
|
|
236
249
|
}
|
|
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
250
|
});
|
|
266
251
|
}
|
|
267
252
|
consumeFromRabbit(queue, callback, options) {
|
|
268
253
|
return __awaiter(this, void 0, void 0, function* () {
|
|
269
254
|
const optionsWithDefaults = Object.assign(Object.assign({}, defaultOptions), options);
|
|
270
255
|
RabbitMq.validateName('queue', queue);
|
|
271
|
-
const { limit, deadMessageTtl } = optionsWithDefaults;
|
|
256
|
+
const { limit, deadMessageTtl, useConsumeWithLock, lockTimeout, } = optionsWithDefaults;
|
|
257
|
+
if (useConsumeWithLock) {
|
|
258
|
+
if (!this.redisLock) {
|
|
259
|
+
throw new Error('Usage of consumeWithLock requires RedisInstance');
|
|
260
|
+
}
|
|
261
|
+
logger_1.default.info(`Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
|
|
262
|
+
}
|
|
272
263
|
const channel = yield this.getNewChannel();
|
|
273
264
|
return channel.addSetup((c) => __awaiter(this, void 0, void 0, function* () {
|
|
274
265
|
yield c.assertQueue(queue);
|
|
@@ -279,15 +270,17 @@ class RabbitMq {
|
|
|
279
270
|
return null;
|
|
280
271
|
}
|
|
281
272
|
const parsedMessage = RabbitMq.parseMsg(msg);
|
|
273
|
+
const releaseLock = yield this.lockRedisIfNeeded(parsedMessage, optionsWithDefaults);
|
|
282
274
|
const shouldConsume = yield this.shouldConsumeMessageByTimestamp(parsedMessage);
|
|
283
275
|
if (!shouldConsume) {
|
|
276
|
+
yield this.unlockRedisIfNeeded(releaseLock);
|
|
284
277
|
return this.ack(channel, msg)(msg);
|
|
285
278
|
}
|
|
286
279
|
try {
|
|
287
|
-
yield callback(parsedMessage, this.ack(channel, msg, true), this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg));
|
|
280
|
+
yield callback(parsedMessage, this.ack(channel, msg, true, releaseLock), this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock));
|
|
288
281
|
}
|
|
289
282
|
catch (e) {
|
|
290
|
-
yield this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg)(msg);
|
|
283
|
+
yield this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg);
|
|
291
284
|
}
|
|
292
285
|
})),
|
|
293
286
|
]);
|
|
@@ -325,7 +318,6 @@ class RabbitMq {
|
|
|
325
318
|
}
|
|
326
319
|
sendToQueue(queue, content, options, customHeaders) {
|
|
327
320
|
return __awaiter(this, void 0, void 0, function* () {
|
|
328
|
-
logger_1.default.info('ss', RabbitMq.getPublishOptions(customHeaders));
|
|
329
321
|
return wrapSetImmediate(() => __awaiter(this, void 0, void 0, function* () {
|
|
330
322
|
RabbitMq.validateName('queue', queue);
|
|
331
323
|
const channel = yield this.assertChannel();
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -55,11 +55,14 @@ 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
68
|
const assertExchangeFanout = (c: any, exchangeName: string) => c.assertExchange(exchangeName, 'fanout');
|
|
@@ -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
|
|
@@ -305,53 +311,41 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
305
311
|
}
|
|
306
312
|
|
|
307
313
|
async consume(queue: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<any> {
|
|
308
|
-
if (options && options.useConsumeWithLock) {
|
|
309
|
-
return this.consumeWithLock(queue, callback, options);
|
|
310
|
-
}
|
|
311
314
|
return this.consumeFromRabbit(queue, callback, options);
|
|
312
315
|
}
|
|
313
316
|
|
|
314
|
-
private async
|
|
315
|
-
|
|
316
|
-
|
|
317
|
+
private async lockRedisIfNeeded(msg: any, options: any) {
|
|
318
|
+
const { properties: { headers } } = msg;
|
|
319
|
+
const timestamp = headers?.creationTimestamp;
|
|
320
|
+
let releaseLock = null;
|
|
321
|
+
|
|
322
|
+
if (options.useConsumeWithLock && timestamp && headers?.redisTimestampValidationKey && this.redisLock) {
|
|
323
|
+
releaseLock = await this.redisLock(
|
|
324
|
+
headers.redisTimestampValidationKey,
|
|
325
|
+
options?.lockTimeout || DEFAULT_LOCK_TIMEOUT,
|
|
326
|
+
);
|
|
317
327
|
}
|
|
318
|
-
|
|
319
|
-
|
|
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;
|
|
328
|
+
return releaseLock;
|
|
329
|
+
}
|
|
328
330
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
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);
|
|
331
|
+
private async unlockRedisIfNeeded(releaseLock: any) {
|
|
332
|
+
if (this.redisLock && releaseLock) {
|
|
333
|
+
await releaseLock();
|
|
334
|
+
}
|
|
349
335
|
}
|
|
350
336
|
|
|
351
337
|
private async consumeFromRabbit(queue: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<any> {
|
|
352
338
|
const optionsWithDefaults = { ...defaultOptions, ...options };
|
|
353
339
|
RabbitMq.validateName('queue', queue);
|
|
354
|
-
const {
|
|
340
|
+
const {
|
|
341
|
+
limit, deadMessageTtl, useConsumeWithLock, lockTimeout,
|
|
342
|
+
} = optionsWithDefaults;
|
|
343
|
+
if (useConsumeWithLock) {
|
|
344
|
+
if (!this.redisLock) {
|
|
345
|
+
throw new Error('Usage of consumeWithLock requires RedisInstance');
|
|
346
|
+
}
|
|
347
|
+
logger.info(`Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
|
|
348
|
+
}
|
|
355
349
|
const channel: ChannelWrapper = await this.getNewChannel();
|
|
356
350
|
return channel.addSetup(async (c: ConfirmChannel) => {
|
|
357
351
|
await c.assertQueue(queue);
|
|
@@ -364,18 +358,20 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
364
358
|
return null;
|
|
365
359
|
}
|
|
366
360
|
const parsedMessage = RabbitMq.parseMsg(msg);
|
|
361
|
+
const releaseLock = await this.lockRedisIfNeeded(parsedMessage, optionsWithDefaults);
|
|
367
362
|
const shouldConsume = await this.shouldConsumeMessageByTimestamp(parsedMessage);
|
|
368
363
|
if (!shouldConsume) {
|
|
364
|
+
await this.unlockRedisIfNeeded(releaseLock);
|
|
369
365
|
return this.ack(channel, msg)(msg);
|
|
370
366
|
}
|
|
371
367
|
try {
|
|
372
368
|
await callback(
|
|
373
369
|
parsedMessage,
|
|
374
|
-
this.ack(channel, msg, true),
|
|
375
|
-
this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg),
|
|
370
|
+
this.ack(channel, msg, true, releaseLock),
|
|
371
|
+
this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock),
|
|
376
372
|
);
|
|
377
373
|
} catch (e) {
|
|
378
|
-
await this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg)(msg);
|
|
374
|
+
await this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg);
|
|
379
375
|
}
|
|
380
376
|
},
|
|
381
377
|
),
|
|
@@ -418,7 +414,6 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
418
414
|
}
|
|
419
415
|
|
|
420
416
|
async sendToQueue(queue: string, content: any, options?: any, customHeaders?: any) : Promise<boolean> {
|
|
421
|
-
logger.info('ss', RabbitMq.getPublishOptions(customHeaders));
|
|
422
417
|
return wrapSetImmediate(async () => {
|
|
423
418
|
RabbitMq.validateName('queue', queue);
|
|
424
419
|
const channel: ChannelWrapper = await this.assertChannel();
|