nestjs / nest

A progressive Node.js framework for building efficient, scalable, and enterprise-grade server-side applications with TypeScript/JavaScript 🚀
https://nestjs.com
MIT License
66.89k stars 7.56k forks source link

Alternating success/error with RabbitMQ: There is no equivalent message pattern defined in the remote service. #1245

Closed patricknazar closed 5 years ago

patricknazar commented 5 years ago

I'm submitting a...


[ ] Regression 
[x] Bug report
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.

Current behavior

When I used RabbitMQ with microservices, I get an alternating response/error "There is no equivalent message pattern defined in the remote service.". One message will work, the next will not, and repeat. It always alternates, it is not randomly failing, it reliably fails and works, fails and works.

This does not happen with the other transports I've tried, NATS/REDIS

Expected behavior

This doesn't happen.

Minimal reproduction of the problem with instructions

One nest app is a graphql server, followed by other nest apps all connected via microservices messaging with basic rabbitmq:3 docker container. In graphql gateway I am using ClientProxyFactory to create a client with RMQ transport, to connect to the other services in the resolvers. Normally works but wanted to try RabbitMQ. Repo that doesn't reproduce (sadly) patricknazar/nestjs-rabbitmq-problem

What is the motivation / use case for changing the behavior?

It should work

Environment


Nest version: 5.4.0


For Tooling issues:
- Node version: 8
- Platform:  Linux

Others:

Yarn
kamilmysliwiec commented 5 years ago

We need a way to somehow reproduce your issue. Could you share a minimal reproduction repository?

patricknazar commented 5 years ago

Sure i'll get onto that

patricknazar commented 5 years ago

Sadly my reproduction repo didn't have the problem... sigh. I can't even begin to figure out why this is happening.

andreastoermer commented 5 years ago

Can you maybe post the reproduction here, I've got the same problem at the moment

patricknazar commented 5 years ago

Sure patricknazar/nestjs-rabbitmq-problem

andreastoermer commented 5 years ago

This is extremely strange. I tried now my controller call with your codebase, and it works too. I also add a custom queue.

patricknazar commented 5 years ago

Yeah, I also tried with custom queue on both my other repo and this one, made no difference :/

andreastoermer commented 5 years ago

Ok I found a difference.

When I create a sub module and add the microservice controller to the submodule, I get the error " There is no equivalent message pattern defined in the remote service.". When I add the microservice controller directly to the application definition, it works.

Adding Microservice Controller to submodule, does this need a prefix for a cmd pattern?

Sorry this is the first i'm working with the microservice functionality, so maybe i missed something in the tutorial

andreastoermer commented 5 years ago

Ok I found a difference.

When I create a sub module and add the microservice controller to the submodule, I get the error " There is no equivalent message pattern defined in the remote service.". When I add the microservice controller directly to the application definition, it works.

Adding Microservice Controller to submodule, does this need a prefix for a cmd pattern?

Sorry this is the first i'm working with the microservice functionality, so maybe i missed something in the tutorial

@kamilmysliwiec do you have a solution for this problem, or is this a bug?

Add a microservice controller directly to the definition.ts and use the cmd patter => it works

Create a sub module, add this sub module to the definition.ts and add the microservice controller to the sub module => it don't work

patricknazar commented 5 years ago

I can't actually reproduce that, I've moved it to a submodule and it still works :/

patricknazar commented 5 years ago

@kamilmysliwiec @andreastoermer Ok I've been able to reproduce the bug. It happens where there is more than one microservice. I've added another one "microservice2" and changed the message handler slightly. The issue now happens. Repo updated patricknazar/nestjs-rabbitmq-problem

andreastoermer commented 5 years ago

have you tried to add a custom queue for each microservice?

andreastoermer commented 5 years ago

@kamilmysliwiec @andreastoermer Ok I've been able to reproduce the bug. It happens where there is more than one microservice. I've added another one "microservice2" and changed the message handler slightly. The issue now happens. Repo updated patricknazar/nestjs-rabbitmq-problem

I've got the same problem with two connected microservices (and different queues)

Even if i disable the "old" microservice and only create a call with a different cmd to the new, i get the error message, very strange ...

andreastoermer commented 5 years ago

I found the problem in my code (the pattern object in my second call was wrong), and now everything works

kamilmysliwiec commented 5 years ago

Just to recap, this repo reproduces the issue, am I right? https://github.com/patricknazar/nestjs-rabbitmq-problem

patricknazar commented 5 years ago

@kamilmysliwiec That's correct

TVGSOFT commented 5 years ago

Hi @patricknazar From my investigation, RabbitMQ queue is routing by round-robin algorithm. @nestjs/microservice routed the message pattern until it reached to the service. Message Pattern didn't route by RabbitMQ. If your microservice is listening to the same queue and didn't implement MessagePattern for all service, then you will get that issue. So my suggestion, you can group MessagePattern for each queue and listen to services used that queue. For example:

BTW, Current @nestjs/miscroservice supports listen with multiple queues (will be multiple connection).

Hi @kamilmysliwiec , Can @nestjs/miscroservice support multiple queue for same connection. For example: app.connectMicroservice({ transport: Transport.RMQ, options: { urls: [amqp://rabbitmq:5672], queues: [ 'queue_1', 'queue_2' ], queueOptions: { durable: false, }, }, });

patricknazar commented 5 years ago

Thanks for your response. I'll close for now. I'd be grateful for any more comments on the matter.

KhaustovN1ck commented 5 years ago

Hi, this problem happens to me too. I have 2 microservices, first one is configured like this

// main.ts
 app.connectMicroservice({
        transport: Transport.RMQ,
        options: {
            urls: [`amqp://localhost:5672`],
            queue: 'manager_service_queue',
            queueOptions: {
                durable: false,
           }
      }
});

and has controller like this:

@Controller()
export class MyController {

    constructor(
        private ordersService: OrdersService,
        private logger: AppLoggerService){}

    @MessagePattern({cmd: RmqPatterns.ORDER_PAYMENT_REJECTED})
    async orderRejected(paymentStatusDto: PaymentStatusDto) {
        this.ordersService.changeOrderStatus(
            paymentStatusDto.status,
            paymentStatusDto.userId,
            paymentStatusDto.orderId,
            paymentStatusDto.reason,
        );
    }

    @MessagePattern({cmd: RmqPatterns.ORDER_CREATED})
    async orderCreated(newOrder: Order) {
        this.ordersService.notifyNewOrder(newOrder);
    }

    @MessagePattern({cmd: RmqPatterns.ORDER_PAYMENT_APPROVED})
    async orderApproved(paymentStatusDto: PaymentStatusDto) {
        this.ordersService.changeOrderStatus(
            paymentStatusDto.status,
            paymentStatusDto.userId,
            paymentStatusDto.orderId,
            paymentStatusDto.reason,
        );
    }
}

second one has this logic:

// my-service.service.ts
// ...
 @Client({
    transport: Transport.RMQ,
    options: {
      urls: [`amqp://localhost:5672`],
      queue: 'manager_service_queue',
      queueOptions: {durable: false},
    },
  })
  managerQueue: ClientProxy;

  callAnotherService(){
     return this.managerQueue.send({cmd: RmqPatterns.ORDER_CREATED}, order);
  }
// ....

When callAnotherService method is called first time I receive this error: There is no equivalent message pattern defined in the remote service Second call seems to be OK, third fails again, fourth work, etc. 😄 In other words even calls work and odd calls fail. Does anyone know why it happens? And perhaps more important thing is what to do with that 🤔 Will appreciate any help 🙏

lock[bot] commented 4 years ago

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.