diff --git a/docs/api/config-options.md b/docs/api/config-options.md index 4436cbb21..1c9c2538d 100644 --- a/docs/api/config-options.md +++ b/docs/api/config-options.md @@ -269,20 +269,6 @@ Also see [ARCHIVE_NAME](#archive_name). Keep in mind that downloaded binaries will never be automatically deleted. ::: -### EXP_NET0LISTEN - -| Environment Variable | PackageJson | -| :------------------: | :---------: | -| `MONGOMS_EXP_NET0LISTEN` | `expNet0Listen` | - -Option `EXP_NET0LISTEN` is used to use the experimental (non-predictable) port generation of `net.listen`. - -This option will use a random open port, which will lessen the "port is already in use" errors, but will not eliminate them. - -This is a experimental option, it maybe removed, renamed or have changed behavior in the future. - -Default: `false` - ## How to use them in the package.json To use the config options in the `package.json`, they need to be camelCased (and without `_`), and need to be in the property `config.mongodbMemoryServer` diff --git a/docs/guides/migration/migrate10.md b/docs/guides/migration/migrate10.md index 0bd820407..93faf3c13 100644 --- a/docs/guides/migration/migrate10.md +++ b/docs/guides/migration/migrate10.md @@ -35,3 +35,8 @@ It is recommended to run the tests against a tmpfs or equivalent (default `/tmp` The tsconfig `target` option has been updated to `es2021`, which will result in less polyfills. This should be a non-breaking change. + +### Getport now uses `net0listen` by default + +This means a port is now generated by the engine (like nodejs) itself, previously known as `EXP_NET0LISTEN`. +This should reduce amount of `Max port tries exceeded` errors. diff --git a/packages/mongodb-memory-server-core/src/util/getport/__tests__/getport.test.ts b/packages/mongodb-memory-server-core/src/util/getport/__tests__/getport.test.ts index 0e2736033..19d5ed40e 100644 --- a/packages/mongodb-memory-server-core/src/util/getport/__tests__/getport.test.ts +++ b/packages/mongodb-memory-server-core/src/util/getport/__tests__/getport.test.ts @@ -1,9 +1,4 @@ -import resolveConfig, { - ResolveConfigVariables, - defaultValues, - envToBool, - setDefaultValue, -} from '../../resolveConfig'; +import { defaultValues } from '../../resolveConfig'; import * as getPort from '../index'; import * as net from 'node:net'; @@ -71,29 +66,8 @@ describe('getport', () => { await expect(getPort.getFreePort(testPort)).resolves.toStrictEqual(testPort); }); - it('port should be predictable', async () => { - expect(envToBool(resolveConfig(ResolveConfigVariables.EXP_NET0LISTEN))).toStrictEqual(false); - - const testPort = 23232; - await expect(getPort.getFreePort(testPort)).resolves.toStrictEqual(testPort); - - const server = await new Promise((res) => { - const server = net.createServer(); - server.unref(); - server.listen(testPort, () => res(server)); - }); - - const foundPort = await getPort.getFreePort(testPort); - expect(foundPort).toStrictEqual(testPort + 2); // predictable result - - server.close(); - }); - - it('EXP_NET0LISTEN should not be predictable', async () => { - setDefaultValue(ResolveConfigVariables.EXP_NET0LISTEN, 'true'); - expect(envToBool(resolveConfig(ResolveConfigVariables.EXP_NET0LISTEN))).toStrictEqual(true); - - const testPort = 23232; + it('port should not be predictable (net0listen)', async () => { + const testPort = 23233; await expect(getPort.getFreePort(testPort)).resolves.toStrictEqual(testPort); const server = await new Promise((res) => { diff --git a/packages/mongodb-memory-server-core/src/util/getport/index.ts b/packages/mongodb-memory-server-core/src/util/getport/index.ts index 8f6c59583..63f3a5310 100644 --- a/packages/mongodb-memory-server-core/src/util/getport/index.ts +++ b/packages/mongodb-memory-server-core/src/util/getport/index.ts @@ -1,5 +1,3 @@ -import resolveConfig, { ResolveConfigVariables, envToBool } from '../resolveConfig'; -import * as crypto from 'node:crypto'; import * as net from 'node:net'; import debug from 'debug'; @@ -16,8 +14,6 @@ interface IPortsCache { timeSet: undefined | number; /** The ports that were tried */ ports: Set; - /** Store last used number, reduces amount of tries needed */ - lastNumber: number; } /** @@ -32,15 +28,14 @@ const PORTS_CACHE_CLEAN_TIME = 1000 * 10; const PORTS_CACHE: IPortsCache = { timeSet: undefined, ports: new Set(), - lastNumber: MIN_PORT, }; /** Max default tries before giving up */ const MAX_DEFAULT_TRIES = 10; /** - * Try to get a free port - * @param firstPort The first port to try or empty for semi-random port + * Try to get a free port. + * @param firstPort The first port to try or empty for a random port * @param max_tries maximum amount of tries to get a port, default to {@link MAX_DEFAULT_TRIES} * @returns A valid free port * @throws if "max_tries" is exceeded @@ -49,8 +44,8 @@ export async function getFreePort( firstPort?: number, max_tries: number = MAX_DEFAULT_TRIES ): Promise { - // 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)); + // use "0" as a fallback to use net0listen, which generates a random free port + firstPort = firstPort || 0; // clear ports cache after some time, but not on an interval if (PORTS_CACHE.timeSet && Date.now() - PORTS_CACHE.timeSet > PORTS_CACHE_CLEAN_TIME) { @@ -60,22 +55,12 @@ export async function getFreePort( PORTS_CACHE.timeSet = Date.now(); } - const exp_net0listen = envToBool(resolveConfig(ResolveConfigVariables.EXP_NET0LISTEN)); - log('EXP_NET0LISTEN', exp_net0listen); - let tries = 0; while (tries <= max_tries) { tries += 1; - let nextPort: number; - - if (exp_net0listen) { - // "0" means to use ".listen" random port - nextPort = tries === 1 ? firstPort : 0; - } else { - // use "startPort" at first try, otherwise increase from last number - nextPort = tries === 1 ? firstPort : validPort(PORTS_CACHE.lastNumber + tries); - } + // "0" means to use have ".listen" use a random port + const nextPort = tries === 1 ? firstPort : 0; // try next port, because it is already in the cache // unless port is "0" which will use "net.listen(0)" @@ -84,15 +69,15 @@ export async function getFreePort( } PORTS_CACHE.ports.add(nextPort); - // only set "lastNumber" if the "nextPort" was not in the cache - PORTS_CACHE.lastNumber = nextPort; const triedPort = await tryPort(nextPort); - // returned port can be different than the "nextPort" (if EXP_NET0LISTEN) - PORTS_CACHE.ports.add(nextPort); - if (triedPort > 0) { + log('getFreePort: found free port', triedPort); + + // returned port can be different than the "nextPort" (if net0listen) + PORTS_CACHE.ports.add(nextPort); + return triedPort; } } @@ -103,8 +88,8 @@ export async function getFreePort( export default getFreePort; /** - * Check that input number is within range of {@link MIN_PORT} and {@link MAX_PORT} - * If more than {@link MAX_PORT}, wrap around, if less than {@link MIN_PORT} use {@link MIN_PORT} + * Ensure that input number is within range of {@link MIN_PORT} and {@link MAX_PORT}. + * If more than {@link MAX_PORT}, wrap around, if less than {@link MIN_PORT} use {@link MIN_PORT}. * @param port The Number to check * @returns A Valid number in port range */ @@ -115,9 +100,9 @@ export function validPort(port: number): number { } /** - * Try a given port + * Try a given port. * @param port The port to try - * @returns "true" if the port is not in use, "false" if in use + * @returns the port if successful, "-1" in case of `EADDRINUSE`, all other errors reject * @throws The error given if the code is not "EADDRINUSE" */ export function tryPort(port: number): Promise { @@ -147,12 +132,11 @@ export function tryPort(port: number): Promise { } /** - * Reset the {@link PORTS_CACHE} to its initial state + * Reset the {@link PORTS_CACHE} to its initial state. * - * This function is meant for debugging and testing purposes only + * This function is meant for debugging and testing purposes only. */ export function resetPortsCache() { - PORTS_CACHE.lastNumber = MIN_PORT; PORTS_CACHE.timeSet = undefined; PORTS_CACHE.ports.clear(); } diff --git a/packages/mongodb-memory-server-core/src/util/resolveConfig.ts b/packages/mongodb-memory-server-core/src/util/resolveConfig.ts index 49b309fa3..5d98b56d1 100644 --- a/packages/mongodb-memory-server-core/src/util/resolveConfig.ts +++ b/packages/mongodb-memory-server-core/src/util/resolveConfig.ts @@ -34,7 +34,6 @@ export enum ResolveConfigVariables { USE_ARCHIVE_NAME_FOR_BINARY_NAME = 'USE_ARCHIVE_NAME_FOR_BINARY_NAME', MAX_REDIRECTS = 'MAX_REDIRECTS', DISTRO = 'DISTRO', - EXP_NET0LISTEN = 'EXP_NET0LISTEN', } /** The Prefix for Environmental values */