1
votes

I'm trying to understand how Nest microservices work.

Let's start with this example from the docs (https://docs.nestjs.com/faq/hybrid-application)

const app = await NestFactory.create(AppModule);
// microservice #1
const microserviceTcp = app.connectMicroservice<MicroserviceOptions>({
  transport: Transport.TCP,
  options: {
    port: 3001,
  },
});
// microservice #2
const microserviceRedis = app.connectMicroservice<MicroserviceOptions>({
  transport: Transport.REDIS,
  options: {
    url: 'redis://localhost:6379',
  },
});

await app.startAllMicroservicesAsync();
await app.listen(3001);

After going through the source (https://github.com/nestjs/nest) , I understand connectMicroservice creates a net.Server when using TCP and the server starts listening when startAllMicroservicesAsync is called. But then app.listen should initialize the listening of the base Nest webserver.

Why doesn't that cause an error?

I checked what happens if I have two microservices connected on the port. It sure does throw an error. What am I missing here?

// CODE CAUSES ERROR AS EXPECTED

const app = await NestFactory.create(AppModule);
// microservice #1
const microserviceTcp = app.connectMicroservice<MicroserviceOptions>({
  transport: Transport.TCP,
  options: {
    port: 3001,
  },
});

// microservice #2  <--- THIS WILL CAUSE AN ERROR AS EXPECTED
const microserviceTcp = app.connectMicroservice<MicroserviceOptions>({
  transport: Transport.TCP,
  options: {
    port: 3001,
  },
});

await app.startAllMicroservicesAsync();
await app.listen(3001);
1

1 Answers

4
votes

In case anyone is interested: it is because microservices and "classic" Nest apps register ports with different defaults. Using lsof to check the open TCP sockets it is immediately clear.

localhost:3000 (LISTEN). // microservice
*:3000 (LISTEN)          // http app

If I explicitly provide a hostname as localhost for app.listen in main.ts, HTTP app fails to start, as expected.