backend-app-api: settle all inits before exiting on error

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2024-09-19 12:03:45 +02:00
parent 332d4cb836
commit 04af116eea
3 changed files with 61 additions and 1 deletions
@@ -418,6 +418,49 @@ describe('BackendInitializer', () => {
);
});
it('should forward errors when multiple plugins fail to start', async () => {
const init = new BackendInitializer([]);
init.add(
createBackendPlugin({
pluginId: 'test-1',
register(reg) {
reg.registerInit({
deps: {},
async init() {
throw new Error('NOPE A');
},
});
},
}),
);
init.add(
createBackendPlugin({
pluginId: 'test-2',
register(reg) {
reg.registerInit({
deps: {},
async init() {
throw new Error('NOPE B');
},
});
},
}),
);
const result = init.start();
await expect(result).rejects.toThrow('Backend startup failed');
await expect(result).rejects.toMatchObject({
errors: [
expect.objectContaining({
message: "Plugin 'test-1' startup failed; caused by Error: NOPE A",
}),
expect.objectContaining({
message: "Plugin 'test-2' startup failed; caused by Error: NOPE B",
}),
],
});
});
it('should forward errors when modules fail to start', async () => {
const init = new BackendInitializer([]);
init.add(testPlugin);
@@ -275,7 +275,7 @@ export class BackendInitializer {
);
// All plugins are initialized in parallel
await Promise.all(
const results = await Promise.allSettled(
allPluginIds.map(async pluginId => {
// Initialize all eager services
await this.#serviceRegistry.initializeEagerServicesWithScope(
@@ -345,6 +345,16 @@ export class BackendInitializer {
}),
);
const initErrors = results.flatMap(r =>
r.status === 'rejected' ? [r.reason] : [],
);
if (initErrors.length === 1) {
throw initErrors[0];
} else if (initErrors.length > 1) {
// TODO(Rugvip): Seems like there aren't proper types for AggregateError yet
throw new (AggregateError as any)(initErrors, 'Backend startup failed');
}
// Once all plugins and modules have been initialized, we can signal that the backend has started up successfully
const lifecycleService = await this.#getRootLifecycleImpl();
await lifecycleService.startup();