From a8732a1200bc4dfa90de84841f98e7a0d057fd2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Thu, 11 Nov 2021 11:58:33 +0100 Subject: [PATCH 1/2] Make sure that the server builder propagates init errors properly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .changeset/rich-pillows-cough.md | 12 +++++++ .../src/service/lib/ServiceBuilderImpl.ts | 34 +++++++++++-------- packages/backend/src/index.ts | 2 +- 3 files changed, 32 insertions(+), 16 deletions(-) create mode 100644 .changeset/rich-pillows-cough.md diff --git a/.changeset/rich-pillows-cough.md b/.changeset/rich-pillows-cough.md new file mode 100644 index 0000000000000..959eb692141ed --- /dev/null +++ b/.changeset/rich-pillows-cough.md @@ -0,0 +1,12 @@ +--- +'@backstage/backend-common': patch +--- + +Make sure that server builder `start()` propagates errors (such as failing to bind to the required port) properly and doesn't resolve the promise prematurely. + +After this change, the backend logger will be able to actually capture the error as it happens: + +``` +2021-11-11T10:54:21.334Z backstage info Initializing http server +2021-11-11T10:54:21.335Z backstage error listen EADDRINUSE: address already in use :::7000 code=EADDRINUSE errno=-48 syscall=listen address=:: port=7000 +``` diff --git a/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts b/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts index ed16c9c9a7aa5..a50fed9e93be6 100644 --- a/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts +++ b/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts @@ -176,25 +176,29 @@ export class ServiceBuilderImpl implements ServiceBuilder { : createHttpServer(app, logger); return new Promise((resolve, reject) => { - app.on('error', e => { - logger.error(`Failed to start up on port ${port}, ${e}`); + function handleStartupError(e: unknown) { + server.close(); reject(e); - }); + } + + app.on('error', handleStartupError); + server.on('error', handleStartupError); - const stoppableServer = stoppable( - server.listen(port, host, () => { - logger.info(`Listening on ${host}:${port}`); - }), - 0, - ); + server.listen(port, host, () => { + app.off('error', handleStartupError); + server.off('error', handleStartupError); - useHotCleanup(this.module, () => - stoppableServer.stop((e: any) => { - if (e) console.error(e); - }), - ); + const stoppableServer = stoppable(server, 0); - resolve(stoppableServer); + useHotCleanup(this.module, () => + stoppableServer.stop((e: any) => { + if (e) console.error(e); + }), + ); + + logger.info(`Listening on ${host}:${port}`); + resolve(stoppableServer); + }); }); } diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index ffdce949b727c..f3e4547e16ef4 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -140,7 +140,7 @@ async function main() { await service.start().catch(err => { logger.error(err); - process.exit(1); + throw err; }); } From 6f276707e37187a45a875709f349369e3ce7aa16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Thu, 11 Nov 2021 20:06:45 +0100 Subject: [PATCH 2/2] review comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .../src/service/lib/ServiceBuilderImpl.ts | 18 +++++++----------- packages/backend/src/index.ts | 2 +- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts b/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts index a50fed9e93be6..885baba54bbbf 100644 --- a/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts +++ b/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts @@ -174,6 +174,13 @@ export class ServiceBuilderImpl implements ServiceBuilder { const server: http.Server = httpsSettings ? await createHttpsServer(app, httpsSettings, logger) : createHttpServer(app, logger); + const stoppableServer = stoppable(server, 0); + + useHotCleanup(this.module, () => + stoppableServer.stop((e: any) => { + if (e) console.error(e); + }), + ); return new Promise((resolve, reject) => { function handleStartupError(e: unknown) { @@ -181,21 +188,10 @@ export class ServiceBuilderImpl implements ServiceBuilder { reject(e); } - app.on('error', handleStartupError); server.on('error', handleStartupError); server.listen(port, host, () => { - app.off('error', handleStartupError); server.off('error', handleStartupError); - - const stoppableServer = stoppable(server, 0); - - useHotCleanup(this.module, () => - stoppableServer.stop((e: any) => { - if (e) console.error(e); - }), - ); - logger.info(`Listening on ${host}:${port}`); resolve(stoppableServer); }); diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index f3e4547e16ef4..ffdce949b727c 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -140,7 +140,7 @@ async function main() { await service.start().catch(err => { logger.error(err); - throw err; + process.exit(1); }); }