Skip to content

Commit

Permalink
fix(getport): randomize first port using crypto.randomInt (#844)
Browse files Browse the repository at this point in the history
* fix(getport): Randomize first port using crypto

The current implementation of `getPort()` relies on using `Date.now()`
to get the first port to try to launch mongo on, even when the
`EXP_NET0LISTEN` flag is set. This causes a couple issues:
- If the `Date` module is mocked, it can result in `getFreePort()`
  returning the same first port every time.
- If multiple mongos are being started at once in parallel, it's
  possible for the same first port to be picked leading to port
  conflicts
In order to better randomize the initial port selection so that port
conflicts can be avoided, instead of using `Date.now()` for an initial
seed, use `crypto.randomInt()` which should provide more randomness and
hopefully avoid some of these race conditions.

re #827

* fix(getport): change crypto.randomInt "max" to be inclusive

---------

Co-authored-by: hasezoey <hasezoey@gmail.com>
  • Loading branch information
noseworthy and hasezoey authored Jan 13, 2024
1 parent 702df8f commit 4132dbf
Showing 1 changed file with 4 additions and 3 deletions.
7 changes: 4 additions & 3 deletions packages/mongodb-memory-server-core/src/util/getport/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import resolveConfig, { ResolveConfigVariables, envToBool } from '../resolveConfig';
import * as crypto from 'node:crypto';
import * as net from 'node:net';
import debug from 'debug';

Expand Down Expand Up @@ -48,10 +49,10 @@ export async function getFreePort(
firstPort?: number,
max_tries: number = MAX_DEFAULT_TRIES
): Promise<number> {
// use "Date" as a semi-random value to lessen conflicts between simultaneous tests
firstPort = firstPort || validPort(Date.now());
// Get a random value from crypto to use as first port if none is given
firstPort = firstPort || validPort(crypto.randomInt(MIN_PORT, MAX_PORT + 1));

// clear ports cache after some time, but not on a interval
// clear ports cache after some time, but not on an interval
if (PORTS_CACHE.timeSet && Date.now() - PORTS_CACHE.timeSet > PORTS_CACHE_CLEAN_TIME) {
PORTS_CACHE.ports.clear();
PORTS_CACHE.timeSet = Date.now();
Expand Down

0 comments on commit 4132dbf

Please sign in to comment.