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
67.78k stars 7.64k forks source link

Connect Microservice not working with amqps #9054

Closed ProductOfAmerica closed 2 years ago

ProductOfAmerica commented 2 years ago

Is there an existing issue for this?

Current behavior

Right now, if I try to connect to amqp://localhost:5672 everything works fine. However, if I change my URL to a managed/hosted URL (for example amqps://username:password@hawk.rmq.cloudamqp.com/username) I get a connection refuse error. I'm positive my username/password are correct.

import { NestFactory } from '@nestjs/core';
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
import { PaymentsModule } from './payments.module';
import { INestApplication, Logger, ValidationPipe } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';

async function bootstrap() {
  const app = await NestFactory.create<INestApplication>(PaymentsModule, {
    logger: new Logger()
  });
  app.setGlobalPrefix('api');
  app.useGlobalPipes(
    new ValidationPipe({
      transform: true
    })
  );

  const configService = app.get<ConfigService>(ConfigService);
  app.connectMicroservice<MicroserviceOptions>({
    transport: Transport.RMQ,
    options: {
      urls: ['amqps://username:password@hawk.rmq.cloudamqp.com/username'],
      queue: 'payments_queue',
      queueOptions: {
        durable: true
      },
      persistent: true
    }
  });

  await app.startAllMicroservices();
  await app.init();
  console.debug('Payments Microservices are listening...');
  await app.listen(3000);
  console.debug(`Payments HTTP Services are listening on 3000...`);
}

bootstrap();

If I try using the module this.client.connect() method:

export class PaymentsModule {
  @Client({ transport: Transport.RMQ })
  client: ClientProxy;

  async onApplicationBootstrap() {
    await this.client.connect();
  }
}

I get this error: UnhandledPromiseRejection: This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "#<Object>".

If I try it without, I get this error:

{
  err: OperationalError: connect ECONNREFUSED 127.0.0.1:5672
      at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1161:16) {
    cause: Error: connect ECONNREFUSED 127.0.0.1:5672
        at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1161:16) {
      errno: -4078,
      code: 'ECONNREFUSED',
      syscall: 'connect',
      address: '127.0.0.1',
      port: 5672
    },
    isOperational: true,
    errno: -4078,
    code: 'ECONNREFUSED',
    syscall: 'connect',
    address: '127.0.0.1',
    port: 5672
  },
  url: 'amqp://localhost'
}

I don't understand why this: url: 'amqp://localhost' is in the error, when I specifically specify the correct managed URL.

Minimum reproduction code

None, see above code

Steps to reproduce

None, see above code

Expected behavior

The service should be able to connect to a managed server.

Package

Other package

No response

NestJS version

No response

Packages versions

  "dependencies": {
    "@coreui/coreui-pro": "^4.1.0",
    "@coreui/icons": "^2.1.0",
    "@coreui/icons-react": "^2.0.1",
    "@coreui/react-pro": "^4.1.3",
    "@nestjs/axios": "^0.0.5",
    "@nestjs/common": "^8.0.0",
    "@nestjs/config": "^1.1.6",
    "@nestjs/core": "^8.0.0",
    "@nestjs/jwt": "^8.0.0",
    "@nestjs/mapped-types": "^1.0.1",
    "@nestjs/microservices": "^8.2.5",
    "@nestjs/mongoose": "^9.0.2",
    "@nestjs/passport": "^8.1.0",
    "@nestjs/platform-express": "^8.2.5",
    "@reduxjs/toolkit": "^1.7.1",
    "amqp-connection-manager": "^4.0.1",
    "amqplib": "^0.8.0",
    "class-transformer": "^0.5.1",
    "class-validator": "^0.13.2",
    "cookie-session": "^2.0.0",
    "core-js": "^3.6.5",
    "express": "^4.17.2",
    "mongoose": "^6.1.7",
    "nestjs-cookie-session": "^2.0.1",
    "nestjs-stripe": "^1.0.0",
    "passport": "^0.5.2",
    "passport-google-oauth20": "^2.0.0",
    "passport-jwt": "^4.0.0",
    "passport-oauth2": "^1.6.1",
    "react": "17.0.2",
    "react-dom": "17.0.2",
    "react-redux": "^7.2.6",
    "react-router-dom": "6.2.1",
    "redux": "^4.1.2",
    "redux-persist": "^6.0.0",
    "reflect-metadata": "^0.1.13",
    "regenerator-runtime": "0.13.9",
    "rxjs": "^7.0.0",
    "simplebar-react": "^2.3.6",
    "stripe": "^8.200.0",
    "tslib": "^2.0.0",
    "web-vitals": "^2.1.4"
  },

Node.js version

No response

In which operating systems have you tested?

Other

No response

jmcdo29 commented 2 years ago

Please provide a minimum reproduction repository.

ProductOfAmerica commented 2 years ago

@jmcdo29 Sorry about that. Ended up figuring it out... for some reason you need to add a query param of 'hearbeat' to the URL string. So turning my URL from this: amqps://username:password@hawk.rmq.cloudamqp.com/username to this: amqps://username:password@hawk.rmq.cloudamqp.com/username?heartbeat=30 fixed the issue. I have no idea why this is a requirement, and it's completely undocumented.