backend-app-api: log at the point of plugin startup failure
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
@@ -277,71 +277,76 @@ export class BackendInitializer {
|
||||
// All plugins are initialized in parallel
|
||||
const results = await Promise.allSettled(
|
||||
allPluginIds.map(async pluginId => {
|
||||
// Initialize all eager services
|
||||
await this.#serviceRegistry.initializeEagerServicesWithScope(
|
||||
'plugin',
|
||||
pluginId,
|
||||
);
|
||||
|
||||
// Modules are initialized before plugins, so that they can provide extension to the plugin
|
||||
const modules = moduleInits.get(pluginId);
|
||||
if (modules) {
|
||||
const tree = DependencyGraph.fromIterable(
|
||||
Array.from(modules).map(([moduleId, moduleInit]) => ({
|
||||
value: { moduleId, moduleInit },
|
||||
// Relationships are reversed at this point since we're only interested in the extension points.
|
||||
// If a modules provides extension point A we want it to be initialized AFTER all modules
|
||||
// that depend on extension point A, so that they can provide their extensions.
|
||||
consumes: Array.from(moduleInit.provides).map(p => p.id),
|
||||
provides: Array.from(moduleInit.consumes).map(c => c.id),
|
||||
})),
|
||||
);
|
||||
const circular = tree.detectCircularDependency();
|
||||
if (circular) {
|
||||
throw new ConflictError(
|
||||
`Circular dependency detected for modules of plugin '${pluginId}', ${circular
|
||||
.map(({ moduleId }) => `'${moduleId}'`)
|
||||
.join(' -> ')}`,
|
||||
);
|
||||
}
|
||||
await tree.parallelTopologicalTraversal(
|
||||
async ({ moduleId, moduleInit }) => {
|
||||
const moduleDeps = await this.#getInitDeps(
|
||||
moduleInit.init.deps,
|
||||
pluginId,
|
||||
moduleId,
|
||||
);
|
||||
await moduleInit.init.func(moduleDeps).catch(error => {
|
||||
throw new ForwardedError(
|
||||
`Module '${moduleId}' for plugin '${pluginId}' startup failed`,
|
||||
error,
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// Once all modules have been initialized, we can initialize the plugin itself
|
||||
const pluginInit = pluginInits.get(pluginId);
|
||||
// We allow modules to be installed without the accompanying plugin, so the plugin may not exist
|
||||
if (pluginInit) {
|
||||
const pluginDeps = await this.#getInitDeps(
|
||||
pluginInit.init.deps,
|
||||
try {
|
||||
// Initialize all eager services
|
||||
await this.#serviceRegistry.initializeEagerServicesWithScope(
|
||||
'plugin',
|
||||
pluginId,
|
||||
);
|
||||
await pluginInit.init.func(pluginDeps).catch(error => {
|
||||
throw new ForwardedError(
|
||||
`Plugin '${pluginId}' startup failed`,
|
||||
error,
|
||||
|
||||
// Modules are initialized before plugins, so that they can provide extension to the plugin
|
||||
const modules = moduleInits.get(pluginId);
|
||||
if (modules) {
|
||||
const tree = DependencyGraph.fromIterable(
|
||||
Array.from(modules).map(([moduleId, moduleInit]) => ({
|
||||
value: { moduleId, moduleInit },
|
||||
// Relationships are reversed at this point since we're only interested in the extension points.
|
||||
// If a modules provides extension point A we want it to be initialized AFTER all modules
|
||||
// that depend on extension point A, so that they can provide their extensions.
|
||||
consumes: Array.from(moduleInit.provides).map(p => p.id),
|
||||
provides: Array.from(moduleInit.consumes).map(c => c.id),
|
||||
})),
|
||||
);
|
||||
});
|
||||
const circular = tree.detectCircularDependency();
|
||||
if (circular) {
|
||||
throw new ConflictError(
|
||||
`Circular dependency detected for modules of plugin '${pluginId}', ${circular
|
||||
.map(({ moduleId }) => `'${moduleId}'`)
|
||||
.join(' -> ')}`,
|
||||
);
|
||||
}
|
||||
await tree.parallelTopologicalTraversal(
|
||||
async ({ moduleId, moduleInit }) => {
|
||||
const moduleDeps = await this.#getInitDeps(
|
||||
moduleInit.init.deps,
|
||||
pluginId,
|
||||
moduleId,
|
||||
);
|
||||
await moduleInit.init.func(moduleDeps).catch(error => {
|
||||
throw new ForwardedError(
|
||||
`Module '${moduleId}' for plugin '${pluginId}' startup failed`,
|
||||
error,
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// Once all modules have been initialized, we can initialize the plugin itself
|
||||
const pluginInit = pluginInits.get(pluginId);
|
||||
// We allow modules to be installed without the accompanying plugin, so the plugin may not exist
|
||||
if (pluginInit) {
|
||||
const pluginDeps = await this.#getInitDeps(
|
||||
pluginInit.init.deps,
|
||||
pluginId,
|
||||
);
|
||||
await pluginInit.init.func(pluginDeps).catch(error => {
|
||||
throw new ForwardedError(
|
||||
`Plugin '${pluginId}' startup failed`,
|
||||
error,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
initLogger.onPluginStarted(pluginId);
|
||||
|
||||
// Once the plugin and all modules have been initialized, we can signal that the plugin has stared up successfully
|
||||
const lifecycleService = await this.#getPluginLifecycleImpl(pluginId);
|
||||
await lifecycleService.startup();
|
||||
} catch (error) {
|
||||
initLogger.onPluginFailed(pluginId);
|
||||
throw error;
|
||||
}
|
||||
|
||||
initLogger.onPluginStarted(pluginId);
|
||||
|
||||
// Once the plugin and all modules have been initialized, we can signal that the plugin has stared up successfully
|
||||
const lifecycleService = await this.#getPluginLifecycleImpl(pluginId);
|
||||
await lifecycleService.startup();
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ export function createInitializationLogger(
|
||||
rootLogger?: RootLoggerService,
|
||||
): {
|
||||
onPluginStarted(pluginId: string): void;
|
||||
onPluginFailed(pluginId: string): void;
|
||||
onAllStarted(): void;
|
||||
} {
|
||||
const logger = rootLogger?.child({ type: 'initialization' });
|
||||
@@ -67,6 +68,16 @@ export function createInitializationLogger(
|
||||
starting.delete(pluginId);
|
||||
started.add(pluginId);
|
||||
},
|
||||
onPluginFailed(pluginId: string) {
|
||||
starting.delete(pluginId);
|
||||
const status =
|
||||
starting.size > 0
|
||||
? `, waiting for ${starting.size} other plugins to finish before shutting down the process`
|
||||
: '';
|
||||
logger?.error(
|
||||
`Plugin '${pluginId}' thew an error during startup${status}`,
|
||||
);
|
||||
},
|
||||
onAllStarted() {
|
||||
logger?.info(`Plugin initialization complete${getInitStatus()}`);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user