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

Connect to multiple RabbitMQ instances

jenshorch opened this issue · comments

Is there a way to register RabbitMQModule twice for communication with two different vhosts at the same time?
I tried to register twice with different names and uris but it seems this does not work.

imports: [
    RabbitMQModule.forRoot(RabbitMQModule, {
      exchanges: [
        {
          type: 'topic',
          name: 'exchange1',
        },
      ],
      uri: 'amqps://rabbit:5672/instanceA',
      name: 'InstanceA',
    }),
    RabbitMQModule.forRoot(RabbitMQModule, {
      exchanges: [
        {
          type: 'topic',
          name: 'exchange2',
        },
      ],
      uri: 'amqps://rabbit:5672/instanceB',
      name: 'InstanceB',
    }),
  ]

When running the application it looks as the event handler gets registered in both modules which will fail as exchange1 does not exist on instanceB.

LOG [NestFactory] Starting Nest application...
LOG [AmqpConnection] Trying to connect to RabbitMQ broker (InstanceA)
LOG [AmqpConnection] Trying to connect to RabbitMQ broker (InstanceB)
LOG [InstanceLoader] AppModule dependencies initialized +29ms
LOG [InstanceLoader] DiscoveryModule dependencies initialized +0ms
LOG [AmqpConnection] Successfully connected to RabbitMQ broker (InstanceA)
LOG [AmqpConnection] Successfully connected to RabbitMQ broker (InstanceB)
LOG [RabbitMQModule] Successfully connected to RabbitMQ
LOG [AmqpConnection] Successfully connected a RabbitMQ channel "AmqpConnection"
LOG [InstanceLoader] RabbitMQModule dependencies initialized +1ms
LOG [RabbitMQModule] Successfully connected to RabbitMQ
LOG [AmqpConnection] Successfully connected a RabbitMQ channel "AmqpConnection"
LOG [InstanceLoader] RabbitMQModule dependencies initialized +0ms
LOG [RabbitMQModule] Initializing RabbitMQ Handlers
LOG [RabbitMQModule] Registering rabbitmq handlers from AppService
LOG [RabbitMQModule] AppService.getEvent {subscribe} -> exchange1::*::event-collector
LOG [RabbitMQModule] Initializing RabbitMQ Handlers
LOG [RabbitMQModule] Registering rabbitmq handlers from AppService
LOG [RabbitMQModule] AppService.getEvent {subscribe} -> exchange1::*::event-collector
ERROR [AmqpConnection] Disconnected from RabbitMQ broker (InstanceB)
Error: Channel closed by server: 404 (NOT-FOUND) with message "NOT_FOUND - no exchange 'exchange1' in vhost 'instanceB'"

Is there a way to specify in handler registration which instance should be used?

The use case is to read events from instanceA and forward them to instanceB. So my handler should only listen to events on instanceA. InstanceB should be injected in the class containing the handler and when received a new message it should be sent to instanceB via the injected instance.

Something like this:

@Injectable()
export class AppService {
  // how to specify the correct connection here?
  constructor(private readonly amqpConnection: AmqpConnection) {}

  @RabbitSubscribe({
    name: 'InstanceA',
    exchange: 'exchange1',
    routingKey: '*',
    queue: 'event-collector',
    queueOptions: {
      durable: true,
      autoDelete: false,
    },
  })
  getEvent(msg: any) {
    this.amqpConnection.publish('exchange2', null, msg);
  }
}

Any ideas how to solve this?

Check this PR: #411 but as far as I looked into it, the modules have to be separate for both connections.

@salmansaif-gt Thanks for your reply. But what do you mean with "the modules have to be separate for both connections"?

I think it's because that when it trys to register rabbitmq from @RabbitSubscribe, it merges the config from modlue and the config inside rabbitSubscrible, so you have exchange1 inside @RabbitSubscribel which override the config in module. Remove exchange1 inside rabbitsubscirble might help you.