backend-app-api: more informative error messages for plugin and module startup failures
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
@@ -18,6 +18,8 @@ import {
|
||||
createServiceRef,
|
||||
createServiceFactory,
|
||||
coreServices,
|
||||
createBackendPlugin,
|
||||
createBackendModule,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { BackendInitializer } from './BackendInitializer';
|
||||
import { ServiceRegistry } from './ServiceRegistry';
|
||||
@@ -72,4 +74,45 @@ describe('BackendInitializer', () => {
|
||||
expect(rootFactory).toHaveBeenCalled();
|
||||
expect(pluginFactory).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should forward errors when plugins fail to start', async () => {
|
||||
const init = new BackendInitializer(new ServiceRegistry([]));
|
||||
init.add(
|
||||
createBackendPlugin({
|
||||
pluginId: 'test',
|
||||
register(reg) {
|
||||
reg.registerInit({
|
||||
deps: {},
|
||||
async init() {
|
||||
throw new Error('NOPE');
|
||||
},
|
||||
});
|
||||
},
|
||||
})(),
|
||||
);
|
||||
await expect(init.start()).rejects.toThrow(
|
||||
"Plugin 'test' startup failed; caused by Error: NOPE",
|
||||
);
|
||||
});
|
||||
|
||||
it('should forward errors when modules fail to start', async () => {
|
||||
const init = new BackendInitializer(new ServiceRegistry([]));
|
||||
init.add(
|
||||
createBackendModule({
|
||||
pluginId: 'test',
|
||||
moduleId: 'mod',
|
||||
register(reg) {
|
||||
reg.registerInit({
|
||||
deps: {},
|
||||
async init() {
|
||||
throw new Error('NOPE');
|
||||
},
|
||||
});
|
||||
},
|
||||
})(),
|
||||
);
|
||||
await expect(init.start()).rejects.toThrow(
|
||||
"Module 'mod' for plugin 'test' startup failed; caused by Error: NOPE",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -26,6 +26,7 @@ import { EnumerableServiceHolder, ServiceOrExtensionPoint } from './types';
|
||||
// Direct internal import to avoid duplication
|
||||
// eslint-disable-next-line @backstage/no-forbidden-package-imports
|
||||
import { InternalBackendFeature } from '@backstage/backend-plugin-api/src/wiring/types';
|
||||
import { ForwardedError } from '@backstage/errors';
|
||||
|
||||
export interface BackendRegisterInit {
|
||||
consumes: Set<ServiceOrExtensionPoint>;
|
||||
@@ -194,12 +195,17 @@ export class BackendInitializer {
|
||||
// Modules are initialized before plugins, so that they can provide extension to the plugin
|
||||
const modules = moduleInits.get(pluginId) ?? [];
|
||||
await Promise.all(
|
||||
Array.from(modules.values()).map(async moduleInit => {
|
||||
Array.from(modules).map(async ([moduleId, moduleInit]) => {
|
||||
const moduleDeps = await this.#getInitDeps(
|
||||
moduleInit.init.deps,
|
||||
pluginId,
|
||||
);
|
||||
await moduleInit.init.func(moduleDeps);
|
||||
await moduleInit.init.func(moduleDeps).catch(error => {
|
||||
throw new ForwardedError(
|
||||
`Module '${moduleId}' for plugin '${pluginId}' startup failed`,
|
||||
error,
|
||||
);
|
||||
});
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -211,7 +217,12 @@ export class BackendInitializer {
|
||||
pluginInit.init.deps,
|
||||
pluginId,
|
||||
);
|
||||
await pluginInit.init.func(pluginDeps);
|
||||
await pluginInit.init.func(pluginDeps).catch(error => {
|
||||
throw new ForwardedError(
|
||||
`Plugin '${pluginId}' startup failed`,
|
||||
error,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// Once the plugin and all modules have been initialized, we can signal that the plugin has stared up successfully
|
||||
|
||||
Reference in New Issue
Block a user