nest icon indicating copy to clipboard operation
nest copied to clipboard

feat(core): free port listening

Open DES-Destry opened this issue 2 years ago • 5 comments

PR Checklist

Please check if your PR fulfills the following requirements:

  • [ ] The commit message follows our guidelines: https://github.com/nestjs/nest/blob/master/CONTRIBUTING.md
  • [x] Tests for the changes have been added (for bug fixes / features)
  • [x] Docs have been added / updated (for bug fixes / features)

PR Type

What kind of change does this PR introduce?

  • [ ] Bugfix
  • [x] Feature
  • [ ] Code style update (formatting, local variables)
  • [ ] Refactoring (no functional changes, no api changes)
  • [ ] Build related changes
  • [ ] CI related changes
  • [ ] Other... Please describe:

What is the current behavior?

Default Nest.js application startup.

  const app = await NestFactory.create(AppModule);
  await app.listen(3000);

It will potentially throw EADDRINUSE error (if you launching different servers at the same time with same ports).

What is the new behavior?

We can run application anyway, even port is busy. Nest.js application will automatically find free port.

  const app = await NestFactory.create<INestFreePortListener>(AppModule);
  await app.listenFreePort({
    port: 3000,
  });

It can be helpful in debugging, when we want just to start a server.

  const app = await NestFactory.create<INestFreePortListener>(AppModule);
  if (process.env.NODE_ENV === 'development') {
    await app.listenFreePort({
      port: 3000,
    });
  } else {
    await app.listen(3000);
  }

All parameters of .listenFreePort(options). All parameters are nullable. Default port is 3000.

  const app = await NestFactory.create<INestFreePortListener>(AppModule);
  await app.listenFreePort({
    port: 3000,
    hostname: '0.0.0.0',
    onSkip: (port) => {
      console.log(`Port ${port} is busy. Try another one...`);
      return port < 4000; // Set some restriction for port. Return true if we want to continue port skipping.
    },
    onStart: (port) => console.log(`Server listening at http://localhost:${port}`),
  });

Does this PR introduce a breaking change?

  • [ ] Yes
  • [x] No

Other information

Fastify support not available yet :(

DES-Destry avatar Oct 14 '22 04:10 DES-Destry

Pull Request Test Coverage Report for Build bdc9e6c6-dd01-4424-9c19-d7be885abfb5

  • 2 of 2 (100.0%) changed or added relevant lines in 1 file are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage increased (+0.002%) to 93.788%

Totals Coverage Status
Change from base Build 6b637f64-9c7a-4d7b-8537-b6a8d098f58e: 0.002%
Covered Lines: 6115
Relevant Lines: 6520

💛 - Coveralls

coveralls avatar Oct 14 '22 04:10 coveralls

actually, we can't say that "the default is 3000". That's just the value we got when generating the app with the CLI.

What we could do instead is making that port parameter optional. When not supplied, a random available port will be taken, like they do in Express already.

We would have to do a minimal change on FastifyAdapter#listen. And just a type def changing on ExpressAdapter#listen. What do you think?

const app = await NestFactory.create(AppModule);
await app.listen();
console.log( await app.getUrl() ) // to see the port

I just tested the above with both HTTP adapters without making any change on their source code and it works

micalevisk avatar Oct 15 '22 20:10 micalevisk

By the way, using 0 as the port means that the OS will find a free port for you. I do this in just about every e2e test that I write now so I don't worry about port collision. You could do the same thing here and use the getUrl() like @micalevisk suggested

jmcdo29 avatar Oct 15 '22 20:10 jmcdo29

So we could use 0 as the default value for port.

Or just document that you could use 0 if you want to pick a random port in our docs site.

micalevisk avatar Oct 15 '22 20:10 micalevisk

Also, what would be the reason for keeping a port within a certain range, like under 4000? So long as it's above port 1023 is should generally be okay as you don't need super user permissions to run, and the OS will find one that's open anyways. Do some tools/utilities have issues with 5 digit ports, or ports over a certain value?

jmcdo29 avatar Oct 15 '22 20:10 jmcdo29

This is redundant changes as I understand it. PR should be closed?

DES-Destry avatar Oct 17 '22 03:10 DES-Destry

yep

It would be better to write another one if you want to make the port parameter optional

micalevisk avatar Oct 17 '22 03:10 micalevisk