diff --git a/.changeset/bright-clubs-throw.md b/.changeset/bright-clubs-throw.md new file mode 100644 index 0000000000..00a6dd3381 --- /dev/null +++ b/.changeset/bright-clubs-throw.md @@ -0,0 +1,6 @@ +--- +"@pnpm/plugin-commands-server": patch +"@pnpm/server": patch +--- + +Wait for server to listen [#9620](https://github.com/pnpm/pnpm/pull/9620). diff --git a/store/plugin-commands-server/src/start.ts b/store/plugin-commands-server/src/start.ts index 63723d6bc6..4239452afa 100644 --- a/store/plugin-commands-server/src/start.ts +++ b/store/plugin-commands-server/src/start.ts @@ -102,6 +102,7 @@ export async function start ( ignoreStopRequests: opts.ignoreStopRequests, ignoreUploadRequests: opts.ignoreUploadRequests, }) + await server.waitForListen // Make sure to populate server.json after the server has started, so clients know that the server is // listening if a server.json with valid JSON content exists. const serverJson = { diff --git a/store/server/example/server.js b/store/server/example/server.js index e042268038..015c5337e8 100644 --- a/store/server/example/server.js +++ b/store/server/example/server.js @@ -32,6 +32,7 @@ async function main() { port, hostname, }) + await server.waitForListen process.on('exit', () => server.close()) } diff --git a/store/server/src/createServer.ts b/store/server/src/createServer.ts index 58472467b6..6c61ed7f05 100644 --- a/store/server/src/createServer.ts +++ b/store/server/src/createServer.ts @@ -28,6 +28,7 @@ interface RequestBody { export interface StoreServerHandle { close: () => Promise + waitForListen: Promise waitForClose: Promise } @@ -169,17 +170,24 @@ export function createServer ( }) let listener: Server - if (opts.path) { - listener = server.listen(opts.path) - } else { - listener = server.listen(opts.port, opts.hostname) - } + + const waitForListen = new Promise((resolve) => { + if (opts.path) { + listener = server.listen(opts.path, () => { + resolve() + }) + } else { + listener = server.listen(opts.port, opts.hostname, () => { + resolve() + }) + } + }) const waitForClose = new Promise((resolve) => listener.once('close', () => { resolve() })) - return { close, waitForClose } + return { close, waitForListen, waitForClose } async function close (): Promise { listener.close() diff --git a/store/server/test/index.ts b/store/server/test/index.ts index 914ca61098..ff5cd18898 100644 --- a/store/server/test/index.ts +++ b/store/server/test/index.ts @@ -48,6 +48,7 @@ test('server', async () => { hostname, port, }) + await server.waitForListen const storeCtrl = await connectStoreController({ remotePrefix, concurrency: 100 }) const projectDir = process.cwd() const response = await storeCtrl.requestPackage( @@ -85,6 +86,7 @@ test('fetchPackage', async () => { hostname, port, }) + await server.waitForListen const storeCtrl = await connectStoreController({ remotePrefix, concurrency: 100 }) const pkgId = 'registry.npmjs.org/is-positive/1.0.0' // This should be fixed @@ -123,6 +125,7 @@ test('server errors should arrive to the client', async () => { hostname, port, }) + await server.waitForListen const storeCtrl = await connectStoreController({ remotePrefix, concurrency: 100 }) let caught = false try { @@ -163,6 +166,7 @@ test('server upload', async () => { hostname, port, }) + await server.waitForListen const storeCtrl = await connectStoreController({ remotePrefix, concurrency: 100 }) const fakeEngine = 'client-engine' @@ -198,6 +202,7 @@ test('disable server upload', async () => { ignoreUploadRequests: true, port, }) + await server.waitForListen const storeCtrl = await connectStoreController({ remotePrefix, concurrency: 100 }) const fakeEngine = 'client-engine' @@ -226,11 +231,12 @@ test('stop server with remote call', async () => { const hostname = 'localhost' const remotePrefix = `http://${hostname}:${port}` const storeCtrlForServer = await createStoreController() - createServer(storeCtrlForServer, { + const server = createServer(storeCtrlForServer, { hostname, ignoreStopRequests: false, port, }) + await server.waitForListen expect(await isPortReachable(port)).toBeTruthy() @@ -251,6 +257,7 @@ test('disallow stop server with remote call', async () => { ignoreStopRequests: true, port, }) + await server.waitForListen expect(await isPortReachable(port)).toBeTruthy() @@ -271,6 +278,7 @@ test('disallow store prune', async () => { hostname, port, }) + await server.waitForListen expect(await isPortReachable(port)).toBeTruthy() @@ -290,6 +298,7 @@ test('server should only allow POST', async () => { hostname, port, }) + await server.waitForListen expect(await isPortReachable(port)).toBeTruthy() @@ -318,6 +327,7 @@ test('server route not found', async () => { hostname, port, }) + await server.waitForListen expect(await isPortReachable(port)).toBeTruthy()