golevelup / nestjs

A collection of badass modules and utilities to help you level up your NestJS applications 🚀

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Re-queue with with x-delay

aviNrich opened this issue · comments

Hi,
I have a logic inside my handler, that if it doesn't meet a certain criteria I want to re-queue with delay.
and give up after 3 tries.

  @RabbitRPC({
    exchange: 'exchange1',
    routingKey: 'rpc-route',
    queue: 'rpc-queue',
  })
  public async rpcHandler(msg: {}) {
       if( this.canWeGoOn() ){
            //do something 
            return;
       }
       message.setHader('x-delay',1000);
       return new Nack(true);
  }

I also want to set some other header header and get it in runtime.
How is that possible, how can I Re-queue with set/get headers?

Thanks

aviNrich I apply it this way.

I created a decorator named Requeueable:

export function Requeueable(maxRetries = 3, delayInMillis = 5000) {
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        const originalMethod = descriptor.value;

        descriptor.value = async function (...args: any[]) {
            try {
                await originalMethod.apply(this, args);
            } catch (error) {
                const message = args[1]; // The message is the second argument to the method
                const retryCount = message.properties.headers?.retryCount || 0;

                await sleep(delayInMillis * retryCount);

                if (retryCount < maxRetries) {
                    console.error(`Error: ${error.message}, requeueing message. Retry Count: ${retryCount + 1}`);

                    const amqpConnection: AmqpConnection = this.amqpConnection; // Ensure AmqpConnection is injected into your service
                    await amqpConnection.publish(
                        message.fields.exchange,
                        message.fields.routingKey,
                        args[0],
                        {
                            headers: {
                                ...message.properties.headers,
                                retryCount: retryCount + 1,
                                'x-delay': delayInMillis * retryCount,
                            }
                        }
                    );

                    return new Nack();
                } else {
                    console.error(`Maximum retry count reached. Message will be discarded.`);
                    return new Nack();
                }
            }
        };

        return descriptor;
    };
}

And in my service, I use it like this:

const MAX_RETRIES = 50;
const RETRY_DELAY = 2000;

@Injectable()
export class RabbitmqHandler {
  constructor(
    private readonly amqpConnection: AmqpConnection,
  ) {}

  @RabbitSubscribe({
    exchange: 'initiation_exchange',
    routingKey: 'ScanReportCreatedEvent',
    queue: 'product-creation-queue',
    queueOptions: {
      durable: true,
      channel: 'product-creation-channel',
    },
    allowNonJsonMessages: true,
    createQueueIfNotExists: true,
  })
  @Requeueable(MAX_RETRIES, RETRY_DELAY)
  public async pubSubHandler(msg: {}, amqpMsg: ConsumeMessage) {
    throw new Error('test');
    }

@brknesn Thank you for providing your Requeueable decorator