diff --git a/.changeset/rotten-carrots-cheer.md b/.changeset/rotten-carrots-cheer.md new file mode 100644 index 0000000000..58da6d2a21 --- /dev/null +++ b/.changeset/rotten-carrots-cheer.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-app-api': patch +--- + +Register unhandled rejection and uncaught exception handlers to avoid backend crashes. diff --git a/packages/backend-app-api/src/wiring/BackendInitializer.ts b/packages/backend-app-api/src/wiring/BackendInitializer.ts index 2a8fa1e720..b2c62c2122 100644 --- a/packages/backend-app-api/src/wiring/BackendInitializer.ts +++ b/packages/backend-app-api/src/wiring/BackendInitializer.ts @@ -165,6 +165,25 @@ export class BackendInitializer { ); await registerInit.init.func(deps); } + + // Once the backend is started, any uncaught errors or unhandled rejections are caught + // and logged, in order to avoid crashing the entire backend on local failures. + if (process.env.NODE_ENV !== 'test') { + const rootLogger = await this.#serviceHolder.get( + coreServices.rootLogger, + 'root', + ); + process.on('unhandledRejection', (reason: Error) => { + rootLogger + ?.child({ type: 'unhandledRejection' }) + ?.error('Unhandled rejection', reason); + }); + process.on('uncaughtException', error => { + rootLogger + ?.child({ type: 'uncaughtException' }) + ?.error('Uncaught exception', error); + }); + } } #resolveInitOrder(registerInits: Array) {