@goparrot/pubsub-event-bus
Version:
NestJS EventBus extension for RabbitMQ PubSub
82 lines • 4.45 kB
JavaScript
import { __decorate, __metadata, __param } from "tslib";
import { Inject, Injectable } from '@nestjs/common';
import { chain, times } from 'lodash';
import { RetryStrategyEnum } from '../../interface';
import { LoggerProvider } from '../../provider';
import { CQRS_BINDING_QUEUE_CONFIG, CQRS_EXCHANGE_CONFIG, CQRS_RETRY_OPTIONS } from '../../utils/configuration';
import { DEFAULT_DELAY_QUEUE_NAME_PREFIX, DEFAULT_RETRY_DELAY_EXCHANGE_NAME, DEFAULT_RETRY_REQUEUE_EXCHANGE_NAME, ORIGIN_EXCHANGE_HEADER, RETRY_COUNT_HEADER, } from '../../utils/retry-constants';
import { calculateDelay, getMessageExchange } from '../../utils';
let DeadLetterTtlRetryStrategy = class DeadLetterTtlRetryStrategy {
constructor(rootRetryOptions, assertExchangeOptions, bindingQueueOptions) {
this.rootRetryOptions = rootRetryOptions;
this.assertExchangeOptions = assertExchangeOptions;
this.bindingQueueOptions = bindingQueueOptions;
this.strategy = RetryStrategyEnum.DEAD_LETTER_TTL;
}
get logger() {
return LoggerProvider.logger;
}
async setupInfrastructure(channelWrapper, wrappersWithRetryStrategy) {
const delays = chain(wrappersWithRetryStrategy)
.flatMap((wrapper) => {
const { delay = this.rootRetryOptions.delay, maxRetryAttempts = this.rootRetryOptions.maxRetryAttempts } = wrapper.options.retryOptions ?? {};
return times(maxRetryAttempts, (retryCount) => calculateDelay(delay, retryCount + 1));
})
.uniq()
.value();
await channelWrapper.addSetup(async (channel) => {
await Promise.all([
channel
.assertExchange(DEFAULT_RETRY_DELAY_EXCHANGE_NAME, 'topic', this.assertExchangeOptions)
.then(() => this.logger.log(`Delay auto retry exchange "${DEFAULT_RETRY_DELAY_EXCHANGE_NAME}" asserted`)),
channel
.assertExchange(DEFAULT_RETRY_REQUEUE_EXCHANGE_NAME, 'topic', this.assertExchangeOptions)
.then(() => this.logger.log(`Requeue auto retry exchange "${DEFAULT_RETRY_REQUEUE_EXCHANGE_NAME}" asserted`)),
...delays.map(async (delay) => {
const queue = `${DEFAULT_DELAY_QUEUE_NAME_PREFIX}.${delay}`;
await channel.assertQueue(queue, {
...this.bindingQueueOptions,
messageTtl: delay,
deadLetterExchange: DEFAULT_RETRY_REQUEUE_EXCHANGE_NAME,
});
await channel.bindQueue(queue, DEFAULT_RETRY_DELAY_EXCHANGE_NAME, `#.retry.${delay}`);
this.logger.log(`Delay queue asserted "${queue}" asserted`);
}),
...wrappersWithRetryStrategy.map(async (handlerWrapper) => {
const { queue } = handlerWrapper;
await channel.bindQueue(queue, DEFAULT_RETRY_REQUEUE_EXCHANGE_NAME, `${queue}.#`);
}),
]);
});
}
async requeue(channelWrapper, handlerWrapper, event) {
const { queue, handler, options: { retryOptions }, } = handlerWrapper;
const message = event.message();
if (!message) {
return;
}
const { delay = this.rootRetryOptions.delay } = retryOptions ?? {};
const retryCount = event.retryCount + 1;
const delayValue = calculateDelay(delay, retryCount);
const routingKey = `${queue}.retry.${delayValue}`;
await channelWrapper.publish(DEFAULT_RETRY_DELAY_EXCHANGE_NAME, routingKey, event.payload, {
...message.properties,
type: message.properties.type,
headers: {
...message.properties.headers,
[RETRY_COUNT_HEADER]: retryCount,
[ORIGIN_EXCHANGE_HEADER]: getMessageExchange(message),
},
});
this.logger.log(`Event ${event.constructor.name} was republished to "${queue}" queue with ${delayValue} ms delay`, handler.name);
}
};
DeadLetterTtlRetryStrategy = __decorate([
Injectable(),
__param(0, Inject(CQRS_RETRY_OPTIONS)),
__param(1, Inject(CQRS_EXCHANGE_CONFIG)),
__param(2, Inject(CQRS_BINDING_QUEUE_CONFIG)),
__metadata("design:paramtypes", [Object, Object, Object])
], DeadLetterTtlRetryStrategy);
export { DeadLetterTtlRetryStrategy };
//# sourceMappingURL=DeadLetterTtlRetryStrategy.js.map