backend-app-api: improved error messaging when service factories throw errors
Co-authored-by: Fredrik Adelöw <freben@gmail.com> Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
@@ -36,6 +36,7 @@
|
||||
"@backstage/backend-common": "^0.15.1-next.1",
|
||||
"@backstage/backend-plugin-api": "^0.1.2-next.0",
|
||||
"@backstage/backend-tasks": "^0.3.5-next.0",
|
||||
"@backstage/errors": "^1.1.0",
|
||||
"@backstage/plugin-permission-node": "^0.6.5-next.1",
|
||||
"express": "^4.17.1",
|
||||
"express-promise-router": "^4.1.0",
|
||||
|
||||
@@ -237,7 +237,43 @@ describe('ServiceRegistry', () => {
|
||||
const factory = registry.get(ref1)!;
|
||||
|
||||
await expect(factory('catalog')).rejects.toThrow(
|
||||
"Failed to instantiate service '1' for 'catalog'. The following dependent services are missing: '2'",
|
||||
"Failed to instantiate service '1' for 'catalog' because the following dependent services are missing: '2'",
|
||||
);
|
||||
});
|
||||
|
||||
it('should decorate error messages thrown by the top-level factory function', async () => {
|
||||
const myFactory = createServiceFactory({
|
||||
service: ref1,
|
||||
deps: {},
|
||||
factory() {
|
||||
throw new Error('top-level error');
|
||||
},
|
||||
});
|
||||
|
||||
const registry = new ServiceRegistry([myFactory]);
|
||||
const factory = registry.get(ref1)!;
|
||||
|
||||
await expect(factory('catalog')).rejects.toThrow(
|
||||
"Failed to instantiate service '1' because the top-level factory function threw an error, Error: top-level error",
|
||||
);
|
||||
});
|
||||
|
||||
it('should decorate error messages thrown by the plugin-level factory function', async () => {
|
||||
const myFactory = createServiceFactory({
|
||||
service: ref1,
|
||||
deps: {},
|
||||
async factory() {
|
||||
return pluginId => {
|
||||
throw new Error(`error in plugin ${pluginId}`);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
const registry = new ServiceRegistry([myFactory]);
|
||||
const factory = registry.get(ref1)!;
|
||||
|
||||
await expect(factory('catalog')).rejects.toThrow(
|
||||
"Failed to instantiate service '1' for 'catalog' because the factory function threw an error, Error: error in plugin catalog",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
FactoryFunc,
|
||||
ServiceRef,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { stringifyError } from '@backstage/errors';
|
||||
|
||||
export class ServiceRegistry {
|
||||
readonly #providedFactories: Map<string, ServiceFactory>;
|
||||
@@ -71,12 +72,22 @@ export class ServiceRegistry {
|
||||
if (missingRefs.length) {
|
||||
const missing = missingRefs.map(r => `'${r.id}'`).join(', ');
|
||||
throw new Error(
|
||||
`Failed to instantiate service '${ref.id}' for '${pluginId}'. The following dependent services are missing: ${missing}`,
|
||||
`Failed to instantiate service '${ref.id}' for '${pluginId}' because the following dependent services are missing: ${missing}`,
|
||||
);
|
||||
}
|
||||
|
||||
implementation = {
|
||||
factoryFunc: factory.factory(factoryDeps),
|
||||
factoryFunc: Promise.resolve()
|
||||
.then(() => factory!.factory(factoryDeps))
|
||||
.catch(error => {
|
||||
throw new Error(
|
||||
`Failed to instantiate service '${
|
||||
ref.id
|
||||
}' because the top-level factory function threw an error, ${stringifyError(
|
||||
error,
|
||||
)}`,
|
||||
);
|
||||
}),
|
||||
byPlugin: new Map(),
|
||||
};
|
||||
|
||||
@@ -85,7 +96,19 @@ export class ServiceRegistry {
|
||||
|
||||
let result = implementation.byPlugin.get(pluginId) as Promise<any>;
|
||||
if (!result) {
|
||||
result = implementation.factoryFunc.then(func => func(pluginId));
|
||||
result = implementation.factoryFunc.then(func =>
|
||||
Promise.resolve()
|
||||
.then(() => func(pluginId))
|
||||
.catch(error => {
|
||||
throw new Error(
|
||||
`Failed to instantiate service '${
|
||||
ref.id
|
||||
}' for '${pluginId}' because the factory function threw an error, ${stringifyError(
|
||||
error,
|
||||
)}`,
|
||||
);
|
||||
}),
|
||||
);
|
||||
|
||||
implementation.byPlugin.set(pluginId, result);
|
||||
}
|
||||
|
||||
@@ -2846,6 +2846,7 @@ __metadata:
|
||||
"@backstage/backend-plugin-api": ^0.1.2-next.0
|
||||
"@backstage/backend-tasks": ^0.3.5-next.0
|
||||
"@backstage/cli": ^0.19.0-next.1
|
||||
"@backstage/errors": ^1.1.0
|
||||
"@backstage/plugin-permission-node": ^0.6.5-next.1
|
||||
express: ^4.17.1
|
||||
express-promise-router: ^4.1.0
|
||||
|
||||
Reference in New Issue
Block a user