@backstage/backend-app-api 1.3.0-next.1 → 1.4.0-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # @backstage/backend-app-api
2
2
 
3
+ ## 1.4.0-next.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 5a2d538: Introduced backend startup result tracking and error handling. The `Backend.start()` method now returns a `BackendStartupResult` with detailed success/failure status and timing information for all plugins and modules. When startup fails, a `BackendStartupError` is thrown that includes the complete startup results, making it easier to diagnose which plugins or modules failed.
8
+
9
+ This also improves the default error message when backend startup fails, and of course makes it possible to craft your own custom error reporting based on the startup results.
10
+
11
+ ### Patch Changes
12
+
13
+ - Updated dependencies
14
+ - @backstage/backend-plugin-api@1.5.1-next.0
15
+ - @backstage/config@1.3.6
16
+ - @backstage/errors@1.2.7
17
+
18
+ ## 1.3.0
19
+
20
+ ### Minor Changes
21
+
22
+ - a17d9df: Updates API for `instanceMetadata` service to return a list of plugins not features.
23
+
24
+ ### Patch Changes
25
+
26
+ - 05f60e1: Refactored constructor parameter properties to explicit property declarations for compatibility with TypeScript's `erasableSyntaxOnly` setting. This internal refactoring maintains all existing functionality while ensuring TypeScript compilation compatibility.
27
+ - Updated dependencies
28
+ - @backstage/backend-plugin-api@1.5.0
29
+ - @backstage/config@1.3.6
30
+
3
31
  ## 1.3.0-next.1
4
32
 
5
33
  ### Minor Changes
package/dist/index.cjs.js CHANGED
@@ -1,8 +1,10 @@
1
1
  'use strict';
2
2
 
3
3
  var createSpecializedBackend = require('./wiring/createSpecializedBackend.cjs.js');
4
+ var BackendStartupError = require('./wiring/BackendStartupError.cjs.js');
4
5
 
5
6
 
6
7
 
7
8
  exports.createSpecializedBackend = createSpecializedBackend.createSpecializedBackend;
9
+ exports.BackendStartupError = BackendStartupError.BackendStartupError;
8
10
  //# sourceMappingURL=index.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;"}
1
+ {"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { BackendFeature, ServiceFactory } from '@backstage/backend-plugin-api';
2
+ import { CustomErrorBase } from '@backstage/errors';
2
3
 
3
4
  /**
4
5
  * @public
@@ -7,7 +8,9 @@ interface Backend {
7
8
  add(feature: BackendFeature | Promise<{
8
9
  default: BackendFeature;
9
10
  }>): void;
10
- start(): Promise<void>;
11
+ start(): Promise<{
12
+ result: BackendStartupResult;
13
+ }>;
11
14
  stop(): Promise<void>;
12
15
  }
13
16
  /**
@@ -16,10 +19,103 @@ interface Backend {
16
19
  interface CreateSpecializedBackendOptions {
17
20
  defaultServiceFactories: ServiceFactory[];
18
21
  }
22
+ /**
23
+ * Result of a module startup attempt.
24
+ * @public
25
+ */
26
+ interface ModuleStartupResult {
27
+ /**
28
+ * The time the module startup was completed.
29
+ */
30
+ resultAt: Date;
31
+ /**
32
+ * The ID of the module.
33
+ */
34
+ moduleId: string;
35
+ /**
36
+ * If the startup failed, this contains information about the failure.
37
+ */
38
+ failure?: {
39
+ /**
40
+ * The error that occurred during startup, if any.
41
+ */
42
+ error: Error;
43
+ /**
44
+ * Whether the failure was allowed.
45
+ */
46
+ allowed: boolean;
47
+ };
48
+ }
49
+ /**
50
+ * Result of a plugin startup attempt.
51
+ * @public
52
+ */
53
+ interface PluginStartupResult {
54
+ /**
55
+ * The time the plugin startup was completed.
56
+ */
57
+ resultAt: Date;
58
+ /**
59
+ * If the startup failed, this contains information about the failure.
60
+ */
61
+ failure?: {
62
+ /**
63
+ * The error that occurred during startup, if any.
64
+ */
65
+ error: Error;
66
+ /**
67
+ * Whether the failure was allowed.
68
+ */
69
+ allowed: boolean;
70
+ };
71
+ /**
72
+ * The ID of the plugin.
73
+ */
74
+ pluginId: string;
75
+ /**
76
+ * Results for all modules belonging to this plugin.
77
+ */
78
+ modules: ModuleStartupResult[];
79
+ }
80
+ /**
81
+ * Result of a backend startup attempt.
82
+ * @public
83
+ */
84
+ interface BackendStartupResult {
85
+ /**
86
+ * The time the backend startup started.
87
+ */
88
+ beginAt: Date;
89
+ /**
90
+ * The time the backend startup was completed.
91
+ */
92
+ resultAt: Date;
93
+ /**
94
+ * Results for all plugins that were attempted to start.
95
+ */
96
+ plugins: PluginStartupResult[];
97
+ /**
98
+ * The outcome of the backend startup.
99
+ */
100
+ outcome: 'success' | 'failure';
101
+ }
19
102
 
20
103
  /**
21
104
  * @public
22
105
  */
23
106
  declare function createSpecializedBackend(options: CreateSpecializedBackendOptions): Backend;
24
107
 
25
- export { type Backend, type CreateSpecializedBackendOptions, createSpecializedBackend };
108
+ /**
109
+ * Error thrown when backend startup fails.
110
+ * Includes detailed startup results for all plugins and modules.
111
+ *
112
+ * @public
113
+ */
114
+ declare class BackendStartupError extends CustomErrorBase {
115
+ #private;
116
+ name: "BackendStartupError";
117
+ constructor(startupResult: BackendStartupResult);
118
+ get result(): BackendStartupResult;
119
+ }
120
+
121
+ export { type Backend, BackendStartupError, type BackendStartupResult, type CreateSpecializedBackendOptions, type ModuleStartupResult, type PluginStartupResult, createSpecializedBackend };
@@ -4,8 +4,10 @@ var backendPluginApi = require('@backstage/backend-plugin-api');
4
4
  var errors = require('@backstage/errors');
5
5
  var DependencyGraph = require('../lib/DependencyGraph.cjs.js');
6
6
  var ServiceRegistry = require('./ServiceRegistry.cjs.js');
7
- var createInitializationLogger = require('./createInitializationLogger.cjs.js');
7
+ var createInitializationResultCollector = require('./createInitializationResultCollector.cjs.js');
8
8
  var helpers = require('./helpers.cjs.js');
9
+ var BackendStartupError = require('./BackendStartupError.cjs.js');
10
+ var createAllowBootFailurePredicate = require('./createAllowBootFailurePredicate.cjs.js');
9
11
 
10
12
  const instanceRegistry = new class InstanceRegistry {
11
13
  #registered = false;
@@ -75,11 +77,9 @@ function createRootInstanceMetadataServiceFactory(rawRegistrations) {
75
77
  service: backendPluginApi.coreServices.rootInstanceMetadata,
76
78
  deps: {},
77
79
  factory: async () => {
78
- console.log(installedPlugins);
79
80
  const readonlyInstalledPlugins = helpers.deepFreeze([
80
81
  ...installedPlugins.values()
81
82
  ]);
82
- console.log(readonlyInstalledPlugins, Object.values(installedPlugins));
83
83
  const instanceMetadata = {
84
84
  getInstalledPlugins: () => Promise.resolve(readonlyInstalledPlugins)
85
85
  };
@@ -159,7 +159,7 @@ class BackendInitializer {
159
159
  }
160
160
  instanceRegistry.register(this);
161
161
  this.#startPromise = this.#doStart();
162
- await this.#startPromise;
162
+ return await this.#startPromise;
163
163
  }
164
164
  async #doStart() {
165
165
  this.#serviceRegistry.checkForCircularDeps();
@@ -171,15 +171,15 @@ class BackendInitializer {
171
171
  createRootInstanceMetadataServiceFactory(this.#registrations)
172
172
  );
173
173
  if (process.env.NODE_ENV !== "test") {
174
- const rootLogger = await this.#serviceRegistry.get(
174
+ const rootLogger2 = await this.#serviceRegistry.get(
175
175
  backendPluginApi.coreServices.rootLogger,
176
176
  "root"
177
177
  );
178
178
  process.on("unhandledRejection", (reason) => {
179
- rootLogger?.child({ type: "unhandledRejection" })?.error("Unhandled rejection", reason);
179
+ rootLogger2?.child({ type: "unhandledRejection" })?.error("Unhandled rejection", reason);
180
180
  });
181
181
  process.on("uncaughtException", (error) => {
182
- rootLogger?.child({ type: "uncaughtException" })?.error("Uncaught exception", error);
182
+ rootLogger2?.child({ type: "uncaughtException" })?.error("Uncaught exception", error);
183
183
  });
184
184
  }
185
185
  await this.#serviceRegistry.initializeEagerServicesWithScope("root");
@@ -232,21 +232,22 @@ class BackendInitializer {
232
232
  }
233
233
  }
234
234
  }
235
- const allPluginIds = [...pluginInits.keys()];
236
- const initLogger = createInitializationLogger.createInitializationLogger(
237
- allPluginIds,
238
- await this.#serviceRegistry.get(backendPluginApi.coreServices.rootLogger, "root")
239
- );
235
+ const pluginIds = [...pluginInits.keys()];
240
236
  const rootConfig = await this.#serviceRegistry.get(
241
237
  backendPluginApi.coreServices.rootConfig,
242
238
  "root"
243
239
  );
244
- const results = await Promise.allSettled(
245
- allPluginIds.map(async (pluginId) => {
246
- const isBootFailurePermitted = this.#getPluginBootFailurePredicate(
247
- pluginId,
248
- rootConfig
249
- );
240
+ const rootLogger = await this.#serviceRegistry.get(
241
+ backendPluginApi.coreServices.rootLogger,
242
+ "root"
243
+ );
244
+ const resultCollector = createInitializationResultCollector.createInitializationResultCollector({
245
+ pluginIds,
246
+ logger: rootLogger,
247
+ allowBootFailurePredicate: createAllowBootFailurePredicate.createAllowBootFailurePredicate(rootConfig)
248
+ });
249
+ await Promise.all(
250
+ pluginIds.map(async (pluginId) => {
250
251
  try {
251
252
  await this.#serviceRegistry.initializeEagerServicesWithScope(
252
253
  "plugin",
@@ -272,35 +273,21 @@ class BackendInitializer {
272
273
  }
273
274
  await tree.parallelTopologicalTraversal(
274
275
  async ({ moduleId, moduleInit }) => {
275
- const isModuleBootFailurePermitted = this.#getPluginModuleBootFailurePredicate(
276
- pluginId,
277
- moduleId,
278
- rootConfig
279
- );
280
276
  try {
281
277
  const moduleDeps = await this.#getInitDeps(
282
278
  moduleInit.init.deps,
283
279
  pluginId,
284
280
  moduleId
285
281
  );
286
- await moduleInit.init.func(moduleDeps).catch((error) => {
287
- throw new errors.ForwardedError(
288
- `Module '${moduleId}' for plugin '${pluginId}' startup failed`,
289
- error
290
- );
291
- });
282
+ await moduleInit.init.func(moduleDeps);
283
+ resultCollector.onPluginModuleResult(pluginId, moduleId);
292
284
  } catch (error) {
293
285
  errors.assertError(error);
294
- if (isModuleBootFailurePermitted) {
295
- initLogger.onPermittedPluginModuleFailure(
296
- pluginId,
297
- moduleId,
298
- error
299
- );
300
- } else {
301
- initLogger.onPluginModuleFailed(pluginId, moduleId, error);
302
- throw error;
303
- }
286
+ resultCollector.onPluginModuleResult(
287
+ pluginId,
288
+ moduleId,
289
+ error
290
+ );
304
291
  }
305
292
  }
306
293
  );
@@ -311,38 +298,29 @@ class BackendInitializer {
311
298
  pluginInit.init.deps,
312
299
  pluginId
313
300
  );
314
- await pluginInit.init.func(pluginDeps).catch((error) => {
315
- throw new errors.ForwardedError(
316
- `Plugin '${pluginId}' startup failed`,
317
- error
318
- );
319
- });
301
+ await pluginInit.init.func(pluginDeps);
320
302
  }
321
- initLogger.onPluginStarted(pluginId);
303
+ resultCollector.onPluginResult(pluginId);
322
304
  const lifecycleService2 = await this.#getPluginLifecycleImpl(pluginId);
323
305
  await lifecycleService2.startup();
324
306
  } catch (error) {
325
307
  errors.assertError(error);
326
- if (isBootFailurePermitted) {
327
- initLogger.onPermittedPluginFailure(pluginId, error);
328
- } else {
329
- initLogger.onPluginFailed(pluginId, error);
330
- throw error;
331
- }
308
+ resultCollector.onPluginResult(pluginId, error);
332
309
  }
333
310
  })
334
- );
335
- const initErrors = results.flatMap(
336
- (r) => r.status === "rejected" ? [r.reason] : []
337
- );
338
- if (initErrors.length === 1) {
339
- throw initErrors[0];
340
- } else if (initErrors.length > 1) {
341
- throw new AggregateError(initErrors, "Backend startup failed");
311
+ ).catch((error) => {
312
+ throw new errors.ForwardedError(
313
+ "Unexpected uncaught backend startup error",
314
+ error
315
+ );
316
+ });
317
+ const result = resultCollector.finalize();
318
+ if (result.outcome === "failure") {
319
+ throw new BackendStartupError.BackendStartupError(result);
342
320
  }
343
321
  const lifecycleService = await this.#getRootLifecycleImpl();
344
322
  await lifecycleService.startup();
345
- initLogger.onAllStarted();
323
+ return { result };
346
324
  }
347
325
  // It's fine to call .stop() multiple times, which for example can happen with manual stop + process exit
348
326
  async stop() {
@@ -467,24 +445,6 @@ class BackendInitializer {
467
445
  }
468
446
  }
469
447
  }
470
- #getPluginBootFailurePredicate(pluginId, config) {
471
- const defaultStartupBootFailureValue = config?.getOptionalString(
472
- "backend.startup.default.onPluginBootFailure"
473
- ) ?? "abort";
474
- const pluginStartupBootFailureValue = config?.getOptionalString(
475
- `backend.startup.plugins.${pluginId}.onPluginBootFailure`
476
- ) ?? defaultStartupBootFailureValue;
477
- return pluginStartupBootFailureValue === "continue";
478
- }
479
- #getPluginModuleBootFailurePredicate(pluginId, moduleId, config) {
480
- const defaultStartupBootFailureValue = config?.getOptionalString(
481
- "backend.startup.default.onPluginModuleBootFailure"
482
- ) ?? "abort";
483
- const pluginModuleStartupBootFailureValue = config?.getOptionalString(
484
- `backend.startup.plugins.${pluginId}.modules.${moduleId}.onPluginModuleBootFailure`
485
- ) ?? defaultStartupBootFailureValue;
486
- return pluginModuleStartupBootFailureValue === "continue";
487
- }
488
448
  }
489
449
  function toInternalBackendFeature(feature) {
490
450
  if (feature.$$type !== "@backstage/BackendFeature") {
@@ -1 +1 @@
1
- {"version":3,"file":"BackendInitializer.cjs.js","sources":["../../src/wiring/BackendInitializer.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n BackendFeature,\n ExtensionPoint,\n coreServices,\n ServiceRef,\n ServiceFactory,\n LifecycleService,\n RootLifecycleService,\n createServiceFactory,\n} from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\nimport { ServiceOrExtensionPoint } from './types';\n// Direct internal import to avoid duplication\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport type {\n InternalBackendFeature,\n InternalBackendFeatureLoader,\n InternalBackendRegistrations,\n} from '../../../backend-plugin-api/src/wiring/types';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport type { InternalServiceFactory } from '../../../backend-plugin-api/src/services/system/types';\nimport { ForwardedError, ConflictError, assertError } from '@backstage/errors';\nimport { DependencyGraph } from '../lib/DependencyGraph';\nimport { ServiceRegistry } from './ServiceRegistry';\nimport { createInitializationLogger } from './createInitializationLogger';\nimport { deepFreeze, unwrapFeature } from './helpers';\nimport type { RootInstanceMetadataServicePluginInfo } from '@backstage/backend-plugin-api';\n\nexport interface BackendRegisterInit {\n consumes: Set<ServiceOrExtensionPoint>;\n provides: Set<ServiceOrExtensionPoint>;\n init: {\n deps: { [name: string]: ServiceOrExtensionPoint };\n func: (deps: { [name: string]: unknown }) => Promise<void>;\n };\n}\n\n/**\n * A registry of backend instances, used to manage process shutdown hooks across all instances.\n */\nconst instanceRegistry = new (class InstanceRegistry {\n #registered = false;\n #instances = new Set<BackendInitializer>();\n\n register(instance: BackendInitializer) {\n if (!this.#registered) {\n this.#registered = true;\n\n process.addListener('SIGTERM', this.#exitHandler);\n process.addListener('SIGINT', this.#exitHandler);\n process.addListener('beforeExit', this.#exitHandler);\n }\n\n this.#instances.add(instance);\n }\n\n unregister(instance: BackendInitializer) {\n this.#instances.delete(instance);\n }\n\n #exitHandler = async () => {\n try {\n const results = await Promise.allSettled(\n Array.from(this.#instances).map(b => b.stop()),\n );\n const errors = results.flatMap(r =>\n r.status === 'rejected' ? [r.reason] : [],\n );\n\n if (errors.length > 0) {\n for (const error of errors) {\n console.error(error);\n }\n process.exit(1);\n } else {\n process.exit(0);\n }\n } catch (error) {\n console.error(error);\n process.exit(1);\n }\n };\n})();\n\nfunction createRootInstanceMetadataServiceFactory(\n rawRegistrations: InternalBackendRegistrations[],\n) {\n const installedPlugins: Map<string, RootInstanceMetadataServicePluginInfo> =\n new Map();\n const registrations = rawRegistrations\n .filter(registration => registration.featureType === 'registrations')\n .flatMap(registration => registration.getRegistrations());\n const plugins = registrations.filter(\n registration => registration.type === 'plugin',\n );\n const modules = registrations.filter(\n registration => registration.type === 'module',\n );\n for (const plugin of plugins) {\n const { pluginId } = plugin;\n if (!installedPlugins.get(pluginId)) {\n installedPlugins.set(pluginId, {\n pluginId,\n modules: [],\n });\n }\n }\n for (const module of modules) {\n const { pluginId, moduleId } = module;\n const installedPlugin = installedPlugins.get(pluginId);\n if (installedPlugin) {\n (installedPlugin.modules as Array<{ moduleId: string }>).push({\n moduleId,\n });\n }\n }\n\n return createServiceFactory({\n service: coreServices.rootInstanceMetadata,\n deps: {},\n factory: async () => {\n console.log(installedPlugins);\n const readonlyInstalledPlugins = deepFreeze([\n ...installedPlugins.values(),\n ]);\n console.log(readonlyInstalledPlugins, Object.values(installedPlugins));\n const instanceMetadata = {\n getInstalledPlugins: () => Promise.resolve(readonlyInstalledPlugins),\n };\n\n return instanceMetadata;\n },\n });\n}\n\nexport class BackendInitializer {\n #startPromise?: Promise<void>;\n #stopPromise?: Promise<void>;\n #registrations = new Array<InternalBackendRegistrations>();\n #extensionPoints = new Map<string, { impl: unknown; pluginId: string }>();\n #serviceRegistry: ServiceRegistry;\n #registeredFeatures = new Array<Promise<BackendFeature>>();\n #registeredFeatureLoaders = new Array<InternalBackendFeatureLoader>();\n\n constructor(defaultApiFactories: ServiceFactory[]) {\n this.#serviceRegistry = ServiceRegistry.create([...defaultApiFactories]);\n }\n\n async #getInitDeps(\n deps: { [name: string]: ServiceOrExtensionPoint },\n pluginId: string,\n moduleId?: string,\n ) {\n const result = new Map<string, unknown>();\n const missingRefs = new Set<ServiceOrExtensionPoint>();\n\n for (const [name, ref] of Object.entries(deps)) {\n const ep = this.#extensionPoints.get(ref.id);\n if (ep) {\n if (ep.pluginId !== pluginId) {\n throw new Error(\n `Illegal dependency: Module '${moduleId}' for plugin '${pluginId}' attempted to depend on extension point '${ref.id}' for plugin '${ep.pluginId}'. Extension points can only be used within their plugin's scope.`,\n );\n }\n result.set(name, ep.impl);\n } else {\n const impl = await this.#serviceRegistry.get(\n ref as ServiceRef<unknown>,\n pluginId,\n );\n if (impl) {\n result.set(name, impl);\n } else {\n missingRefs.add(ref);\n }\n }\n }\n\n if (missingRefs.size > 0) {\n const missing = Array.from(missingRefs).join(', ');\n const target = moduleId\n ? `module '${moduleId}' for plugin '${pluginId}'`\n : `plugin '${pluginId}'`;\n throw new Error(\n `Service or extension point dependencies of ${target} are missing for the following ref(s): ${missing}`,\n );\n }\n\n return Object.fromEntries(result);\n }\n\n add(feature: BackendFeature | Promise<BackendFeature>) {\n if (this.#startPromise) {\n throw new Error('feature can not be added after the backend has started');\n }\n this.#registeredFeatures.push(Promise.resolve(feature));\n }\n\n #addFeature(feature: BackendFeature) {\n if (isServiceFactory(feature)) {\n this.#serviceRegistry.add(feature);\n } else if (isBackendFeatureLoader(feature)) {\n this.#registeredFeatureLoaders.push(feature);\n } else if (isBackendRegistrations(feature)) {\n this.#registrations.push(feature);\n } else {\n throw new Error(\n `Failed to add feature, invalid feature ${JSON.stringify(feature)}`,\n );\n }\n }\n\n async start(): Promise<void> {\n if (this.#startPromise) {\n throw new Error('Backend has already started');\n }\n if (this.#stopPromise) {\n throw new Error('Backend has already stopped');\n }\n\n instanceRegistry.register(this);\n\n this.#startPromise = this.#doStart();\n await this.#startPromise;\n }\n\n async #doStart(): Promise<void> {\n this.#serviceRegistry.checkForCircularDeps();\n\n for (const feature of this.#registeredFeatures) {\n this.#addFeature(await feature);\n }\n\n await this.#applyBackendFeatureLoaders(this.#registeredFeatureLoaders);\n\n this.#serviceRegistry.add(\n createRootInstanceMetadataServiceFactory(this.#registrations),\n );\n\n // This makes sure that any uncaught errors or unhandled rejections are\n // caught and logged, rather than terminating the process. We register these\n // as early as possible while still using the root logger service, the\n // tradeoff that if there are any unhandled errors as part of the that\n // instationation, it will cause the process to crash. If there are multiple\n // backend instances, each instance will log the error, because we can't\n // determine which instance the error came from.\n if (process.env.NODE_ENV !== 'test') {\n const rootLogger = await this.#serviceRegistry.get(\n coreServices.rootLogger,\n 'root',\n );\n process.on('unhandledRejection', (reason: Error) => {\n rootLogger\n ?.child({ type: 'unhandledRejection' })\n ?.error('Unhandled rejection', reason);\n });\n process.on('uncaughtException', error => {\n rootLogger\n ?.child({ type: 'uncaughtException' })\n ?.error('Uncaught exception', error);\n });\n }\n\n // Initialize all root scoped services\n await this.#serviceRegistry.initializeEagerServicesWithScope('root');\n\n const pluginInits = new Map<string, BackendRegisterInit>();\n const moduleInits = new Map<string, Map<string, BackendRegisterInit>>();\n\n // Enumerate all registrations\n for (const feature of this.#registrations) {\n for (const r of feature.getRegistrations()) {\n const provides = new Set<ExtensionPoint<unknown>>();\n\n if (r.type === 'plugin' || r.type === 'module') {\n for (const [extRef, extImpl] of r.extensionPoints) {\n if (this.#extensionPoints.has(extRef.id)) {\n throw new Error(\n `ExtensionPoint with ID '${extRef.id}' is already registered`,\n );\n }\n this.#extensionPoints.set(extRef.id, {\n impl: extImpl,\n pluginId: r.pluginId,\n });\n provides.add(extRef);\n }\n }\n\n if (r.type === 'plugin') {\n if (pluginInits.has(r.pluginId)) {\n throw new Error(`Plugin '${r.pluginId}' is already registered`);\n }\n pluginInits.set(r.pluginId, {\n provides,\n consumes: new Set(Object.values(r.init.deps)),\n init: r.init,\n });\n } else if (r.type === 'module') {\n let modules = moduleInits.get(r.pluginId);\n if (!modules) {\n modules = new Map();\n moduleInits.set(r.pluginId, modules);\n }\n if (modules.has(r.moduleId)) {\n throw new Error(\n `Module '${r.moduleId}' for plugin '${r.pluginId}' is already registered`,\n );\n }\n modules.set(r.moduleId, {\n provides,\n consumes: new Set(Object.values(r.init.deps)),\n init: r.init,\n });\n } else {\n throw new Error(`Invalid registration type '${(r as any).type}'`);\n }\n }\n }\n\n const allPluginIds = [...pluginInits.keys()];\n\n const initLogger = createInitializationLogger(\n allPluginIds,\n await this.#serviceRegistry.get(coreServices.rootLogger, 'root'),\n );\n\n const rootConfig = await this.#serviceRegistry.get(\n coreServices.rootConfig,\n 'root',\n );\n\n // All plugins are initialized in parallel\n const results = await Promise.allSettled(\n allPluginIds.map(async pluginId => {\n const isBootFailurePermitted = this.#getPluginBootFailurePredicate(\n pluginId,\n rootConfig,\n );\n\n try {\n // Initialize all eager services\n await this.#serviceRegistry.initializeEagerServicesWithScope(\n 'plugin',\n pluginId,\n );\n\n // Modules are initialized before plugins, so that they can provide extension to the plugin\n const modules = moduleInits.get(pluginId);\n if (modules) {\n const tree = DependencyGraph.fromIterable(\n Array.from(modules).map(([moduleId, moduleInit]) => ({\n value: { moduleId, moduleInit },\n // Relationships are reversed at this point since we're only interested in the extension points.\n // If a modules provides extension point A we want it to be initialized AFTER all modules\n // that depend on extension point A, so that they can provide their extensions.\n consumes: Array.from(moduleInit.provides).map(p => p.id),\n provides: Array.from(moduleInit.consumes).map(c => c.id),\n })),\n );\n const circular = tree.detectCircularDependency();\n if (circular) {\n throw new ConflictError(\n `Circular dependency detected for modules of plugin '${pluginId}', ${circular\n .map(({ moduleId }) => `'${moduleId}'`)\n .join(' -> ')}`,\n );\n }\n await tree.parallelTopologicalTraversal(\n async ({ moduleId, moduleInit }) => {\n const isModuleBootFailurePermitted =\n this.#getPluginModuleBootFailurePredicate(\n pluginId,\n moduleId,\n rootConfig,\n );\n\n try {\n const moduleDeps = await this.#getInitDeps(\n moduleInit.init.deps,\n pluginId,\n moduleId,\n );\n await moduleInit.init.func(moduleDeps).catch(error => {\n throw new ForwardedError(\n `Module '${moduleId}' for plugin '${pluginId}' startup failed`,\n error,\n );\n });\n } catch (error: unknown) {\n assertError(error);\n if (isModuleBootFailurePermitted) {\n initLogger.onPermittedPluginModuleFailure(\n pluginId,\n moduleId,\n error,\n );\n } else {\n initLogger.onPluginModuleFailed(pluginId, moduleId, error);\n throw error;\n }\n }\n },\n );\n }\n\n // Once all modules have been initialized, we can initialize the plugin itself\n const pluginInit = pluginInits.get(pluginId);\n // We allow modules to be installed without the accompanying plugin, so the plugin may not exist\n if (pluginInit) {\n const pluginDeps = await this.#getInitDeps(\n pluginInit.init.deps,\n pluginId,\n );\n await pluginInit.init.func(pluginDeps).catch(error => {\n throw new ForwardedError(\n `Plugin '${pluginId}' startup failed`,\n error,\n );\n });\n }\n\n initLogger.onPluginStarted(pluginId);\n\n // Once the plugin and all modules have been initialized, we can signal that the plugin has stared up successfully\n const lifecycleService = await this.#getPluginLifecycleImpl(pluginId);\n await lifecycleService.startup();\n } catch (error: unknown) {\n assertError(error);\n if (isBootFailurePermitted) {\n initLogger.onPermittedPluginFailure(pluginId, error);\n } else {\n initLogger.onPluginFailed(pluginId, error);\n throw error;\n }\n }\n }),\n );\n\n const initErrors = results.flatMap(r =>\n r.status === 'rejected' ? [r.reason] : [],\n );\n if (initErrors.length === 1) {\n throw initErrors[0];\n } else if (initErrors.length > 1) {\n // TODO(Rugvip): Seems like there aren't proper types for AggregateError yet\n throw new (AggregateError as any)(initErrors, 'Backend startup failed');\n }\n\n // Once all plugins and modules have been initialized, we can signal that the backend has started up successfully\n const lifecycleService = await this.#getRootLifecycleImpl();\n await lifecycleService.startup();\n\n initLogger.onAllStarted();\n }\n\n // It's fine to call .stop() multiple times, which for example can happen with manual stop + process exit\n async stop(): Promise<void> {\n instanceRegistry.unregister(this);\n\n if (!this.#stopPromise) {\n this.#stopPromise = this.#doStop();\n }\n await this.#stopPromise;\n }\n\n async #doStop(): Promise<void> {\n if (!this.#startPromise) {\n return;\n }\n\n try {\n await this.#startPromise;\n } catch (error) {\n // The startup failed, but we may still want to do cleanup so we continue silently\n }\n\n const rootLifecycleService = await this.#getRootLifecycleImpl();\n\n // Root services like the health one need to immediately be notified of the shutdown\n await rootLifecycleService.beforeShutdown();\n\n // Get all plugins.\n const allPlugins = new Set<string>();\n for (const feature of this.#registrations) {\n for (const r of feature.getRegistrations()) {\n if (r.type === 'plugin') {\n allPlugins.add(r.pluginId);\n }\n }\n }\n\n // Iterate through all plugins and run their shutdown hooks.\n await Promise.allSettled(\n [...allPlugins].map(async pluginId => {\n const lifecycleService = await this.#getPluginLifecycleImpl(pluginId);\n await lifecycleService.shutdown();\n }),\n );\n\n // Once all plugin shutdown hooks are done, run root shutdown hooks.\n await rootLifecycleService.shutdown();\n }\n\n // Bit of a hacky way to grab the lifecycle services, potentially find a nicer way to do this\n async #getRootLifecycleImpl(): Promise<\n RootLifecycleService & {\n startup(): Promise<void>;\n beforeShutdown(): Promise<void>;\n shutdown(): Promise<void>;\n }\n > {\n const lifecycleService = await this.#serviceRegistry.get(\n coreServices.rootLifecycle,\n 'root',\n );\n\n const service = lifecycleService as any;\n if (\n service &&\n typeof service.startup === 'function' &&\n typeof service.shutdown === 'function'\n ) {\n return service;\n }\n\n throw new Error('Unexpected root lifecycle service implementation');\n }\n\n async #getPluginLifecycleImpl(\n pluginId: string,\n ): Promise<\n LifecycleService & { startup(): Promise<void>; shutdown(): Promise<void> }\n > {\n const lifecycleService = await this.#serviceRegistry.get(\n coreServices.lifecycle,\n pluginId,\n );\n\n const service = lifecycleService as any;\n if (\n service &&\n typeof service.startup === 'function' &&\n typeof service.shutdown === 'function'\n ) {\n return service;\n }\n\n throw new Error('Unexpected plugin lifecycle service implementation');\n }\n\n async #applyBackendFeatureLoaders(loaders: InternalBackendFeatureLoader[]) {\n const servicesAddedByLoaders = new Map<\n string,\n InternalBackendFeatureLoader\n >();\n\n for (const loader of loaders) {\n const deps = new Map<string, unknown>();\n const missingRefs = new Set<ServiceOrExtensionPoint>();\n\n for (const [name, ref] of Object.entries(loader.deps ?? {})) {\n if (ref.scope !== 'root') {\n throw new Error(\n `Feature loaders can only depend on root scoped services, but '${name}' is scoped to '${ref.scope}'. Offending loader is ${loader.description}`,\n );\n }\n const impl = await this.#serviceRegistry.get(\n ref as ServiceRef<unknown>,\n 'root',\n );\n if (impl) {\n deps.set(name, impl);\n } else {\n missingRefs.add(ref);\n }\n }\n\n if (missingRefs.size > 0) {\n const missing = Array.from(missingRefs).join(', ');\n throw new Error(\n `No service available for the following ref(s): ${missing}, depended on by feature loader ${loader.description}`,\n );\n }\n\n const result = await loader\n .loader(Object.fromEntries(deps))\n .then(features => features.map(unwrapFeature))\n .catch(error => {\n throw new ForwardedError(\n `Feature loader ${loader.description} failed`,\n error,\n );\n });\n\n let didAddServiceFactory = false;\n const newLoaders = new Array<InternalBackendFeatureLoader>();\n\n for await (const feature of result) {\n if (isBackendFeatureLoader(feature)) {\n newLoaders.push(feature);\n } else {\n // This block makes sure that feature loaders do not provide duplicate\n // implementations for the same service, but at the same time allows\n // service factories provided by feature loaders to be overridden by\n // ones that are explicitly installed with backend.add(serviceFactory).\n //\n // If a factory has already been explicitly installed, the service\n // factory provided by the loader will simply be ignored.\n if (isServiceFactory(feature) && !feature.service.multiton) {\n const conflictingLoader = servicesAddedByLoaders.get(\n feature.service.id,\n );\n if (conflictingLoader) {\n throw new Error(\n `Duplicate service implementations provided for ${feature.service.id} by both feature loader ${loader.description} and feature loader ${conflictingLoader.description}`,\n );\n }\n\n // Check that this service wasn't already explicitly added by backend.add(serviceFactory)\n if (!this.#serviceRegistry.hasBeenAdded(feature.service)) {\n didAddServiceFactory = true;\n servicesAddedByLoaders.set(feature.service.id, loader);\n this.#addFeature(feature);\n }\n } else {\n this.#addFeature(feature);\n }\n }\n }\n\n // Every time we add a new service factory we need to make sure that we don't have circular dependencies\n if (didAddServiceFactory) {\n this.#serviceRegistry.checkForCircularDeps();\n }\n\n // Apply loaders recursively, depth-first\n if (newLoaders.length > 0) {\n await this.#applyBackendFeatureLoaders(newLoaders);\n }\n }\n }\n\n #getPluginBootFailurePredicate(pluginId: string, config?: Config): boolean {\n const defaultStartupBootFailureValue =\n config?.getOptionalString(\n 'backend.startup.default.onPluginBootFailure',\n ) ?? 'abort';\n\n const pluginStartupBootFailureValue =\n config?.getOptionalString(\n `backend.startup.plugins.${pluginId}.onPluginBootFailure`,\n ) ?? defaultStartupBootFailureValue;\n\n return pluginStartupBootFailureValue === 'continue';\n }\n\n #getPluginModuleBootFailurePredicate(\n pluginId: string,\n moduleId: string,\n config?: Config,\n ): boolean {\n const defaultStartupBootFailureValue =\n config?.getOptionalString(\n 'backend.startup.default.onPluginModuleBootFailure',\n ) ?? 'abort';\n\n const pluginModuleStartupBootFailureValue =\n config?.getOptionalString(\n `backend.startup.plugins.${pluginId}.modules.${moduleId}.onPluginModuleBootFailure`,\n ) ?? defaultStartupBootFailureValue;\n\n return pluginModuleStartupBootFailureValue === 'continue';\n }\n}\n\nfunction toInternalBackendFeature(\n feature: BackendFeature,\n): InternalBackendFeature {\n if (feature.$$type !== '@backstage/BackendFeature') {\n throw new Error(`Invalid BackendFeature, bad type '${feature.$$type}'`);\n }\n const internal = feature as InternalBackendFeature;\n if (internal.version !== 'v1') {\n throw new Error(\n `Invalid BackendFeature, bad version '${internal.version}'`,\n );\n }\n return internal;\n}\n\nfunction isServiceFactory(\n feature: BackendFeature,\n): feature is InternalServiceFactory {\n const internal = toInternalBackendFeature(feature);\n if (internal.featureType === 'service') {\n return true;\n }\n // Backwards compatibility for v1 registrations that use duck typing\n return 'service' in internal;\n}\n\nfunction isBackendRegistrations(\n feature: BackendFeature,\n): feature is InternalBackendRegistrations {\n const internal = toInternalBackendFeature(feature);\n if (internal.featureType === 'registrations') {\n return true;\n }\n // Backwards compatibility for v1 registrations that use duck typing\n return 'getRegistrations' in internal;\n}\n\nfunction isBackendFeatureLoader(\n feature: BackendFeature,\n): feature is InternalBackendFeatureLoader {\n return toInternalBackendFeature(feature).featureType === 'loader';\n}\n"],"names":["createServiceFactory","coreServices","deepFreeze","ServiceRegistry","createInitializationLogger","DependencyGraph","ConflictError","ForwardedError","assertError","lifecycleService","unwrapFeature"],"mappings":"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"}
1
+ {"version":3,"file":"BackendInitializer.cjs.js","sources":["../../src/wiring/BackendInitializer.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n BackendFeature,\n ExtensionPoint,\n coreServices,\n ServiceRef,\n ServiceFactory,\n LifecycleService,\n RootLifecycleService,\n createServiceFactory,\n} from '@backstage/backend-plugin-api';\nimport { ServiceOrExtensionPoint } from './types';\n// Direct internal import to avoid duplication\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport type {\n InternalBackendFeature,\n InternalBackendFeatureLoader,\n InternalBackendRegistrations,\n} from '../../../backend-plugin-api/src/wiring/types';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport type { InternalServiceFactory } from '../../../backend-plugin-api/src/services/system/types';\nimport { ForwardedError, ConflictError, assertError } from '@backstage/errors';\nimport { DependencyGraph } from '../lib/DependencyGraph';\nimport { ServiceRegistry } from './ServiceRegistry';\nimport { createInitializationResultCollector } from './createInitializationResultCollector';\nimport { deepFreeze, unwrapFeature } from './helpers';\nimport type { RootInstanceMetadataServicePluginInfo } from '@backstage/backend-plugin-api';\nimport { BackendStartupResult } from './types';\nimport { BackendStartupError } from './BackendStartupError';\nimport { createAllowBootFailurePredicate } from './createAllowBootFailurePredicate';\n\nexport interface BackendRegisterInit {\n consumes: Set<ServiceOrExtensionPoint>;\n provides: Set<ServiceOrExtensionPoint>;\n init: {\n deps: { [name: string]: ServiceOrExtensionPoint };\n func: (deps: { [name: string]: unknown }) => Promise<void>;\n };\n}\n\n/**\n * A registry of backend instances, used to manage process shutdown hooks across all instances.\n */\nconst instanceRegistry = new (class InstanceRegistry {\n #registered = false;\n #instances = new Set<BackendInitializer>();\n\n register(instance: BackendInitializer) {\n if (!this.#registered) {\n this.#registered = true;\n\n process.addListener('SIGTERM', this.#exitHandler);\n process.addListener('SIGINT', this.#exitHandler);\n process.addListener('beforeExit', this.#exitHandler);\n }\n\n this.#instances.add(instance);\n }\n\n unregister(instance: BackendInitializer) {\n this.#instances.delete(instance);\n }\n\n #exitHandler = async () => {\n try {\n const results = await Promise.allSettled(\n Array.from(this.#instances).map(b => b.stop()),\n );\n const errors = results.flatMap(r =>\n r.status === 'rejected' ? [r.reason] : [],\n );\n\n if (errors.length > 0) {\n for (const error of errors) {\n console.error(error);\n }\n process.exit(1);\n } else {\n process.exit(0);\n }\n } catch (error) {\n console.error(error);\n process.exit(1);\n }\n };\n})();\n\nfunction createRootInstanceMetadataServiceFactory(\n rawRegistrations: InternalBackendRegistrations[],\n) {\n const installedPlugins: Map<string, RootInstanceMetadataServicePluginInfo> =\n new Map();\n const registrations = rawRegistrations\n .filter(registration => registration.featureType === 'registrations')\n .flatMap(registration => registration.getRegistrations());\n const plugins = registrations.filter(\n registration => registration.type === 'plugin',\n );\n const modules = registrations.filter(\n registration => registration.type === 'module',\n );\n for (const plugin of plugins) {\n const { pluginId } = plugin;\n if (!installedPlugins.get(pluginId)) {\n installedPlugins.set(pluginId, {\n pluginId,\n modules: [],\n });\n }\n }\n for (const module of modules) {\n const { pluginId, moduleId } = module;\n const installedPlugin = installedPlugins.get(pluginId);\n if (installedPlugin) {\n (installedPlugin.modules as Array<{ moduleId: string }>).push({\n moduleId,\n });\n }\n }\n\n return createServiceFactory({\n service: coreServices.rootInstanceMetadata,\n deps: {},\n factory: async () => {\n const readonlyInstalledPlugins = deepFreeze([\n ...installedPlugins.values(),\n ]);\n const instanceMetadata = {\n getInstalledPlugins: () => Promise.resolve(readonlyInstalledPlugins),\n };\n\n return instanceMetadata;\n },\n });\n}\n\nexport class BackendInitializer {\n #startPromise?: Promise<{ result: BackendStartupResult }>;\n #stopPromise?: Promise<void>;\n #registrations = new Array<InternalBackendRegistrations>();\n #extensionPoints = new Map<string, { impl: unknown; pluginId: string }>();\n #serviceRegistry: ServiceRegistry;\n #registeredFeatures = new Array<Promise<BackendFeature>>();\n #registeredFeatureLoaders = new Array<InternalBackendFeatureLoader>();\n\n constructor(defaultApiFactories: ServiceFactory[]) {\n this.#serviceRegistry = ServiceRegistry.create([...defaultApiFactories]);\n }\n\n async #getInitDeps(\n deps: { [name: string]: ServiceOrExtensionPoint },\n pluginId: string,\n moduleId?: string,\n ) {\n const result = new Map<string, unknown>();\n const missingRefs = new Set<ServiceOrExtensionPoint>();\n\n for (const [name, ref] of Object.entries(deps)) {\n const ep = this.#extensionPoints.get(ref.id);\n if (ep) {\n if (ep.pluginId !== pluginId) {\n throw new Error(\n `Illegal dependency: Module '${moduleId}' for plugin '${pluginId}' attempted to depend on extension point '${ref.id}' for plugin '${ep.pluginId}'. Extension points can only be used within their plugin's scope.`,\n );\n }\n result.set(name, ep.impl);\n } else {\n const impl = await this.#serviceRegistry.get(\n ref as ServiceRef<unknown>,\n pluginId,\n );\n if (impl) {\n result.set(name, impl);\n } else {\n missingRefs.add(ref);\n }\n }\n }\n\n if (missingRefs.size > 0) {\n const missing = Array.from(missingRefs).join(', ');\n const target = moduleId\n ? `module '${moduleId}' for plugin '${pluginId}'`\n : `plugin '${pluginId}'`;\n throw new Error(\n `Service or extension point dependencies of ${target} are missing for the following ref(s): ${missing}`,\n );\n }\n\n return Object.fromEntries(result);\n }\n\n add(feature: BackendFeature | Promise<BackendFeature>) {\n if (this.#startPromise) {\n throw new Error('feature can not be added after the backend has started');\n }\n this.#registeredFeatures.push(Promise.resolve(feature));\n }\n\n #addFeature(feature: BackendFeature) {\n if (isServiceFactory(feature)) {\n this.#serviceRegistry.add(feature);\n } else if (isBackendFeatureLoader(feature)) {\n this.#registeredFeatureLoaders.push(feature);\n } else if (isBackendRegistrations(feature)) {\n this.#registrations.push(feature);\n } else {\n throw new Error(\n `Failed to add feature, invalid feature ${JSON.stringify(feature)}`,\n );\n }\n }\n\n async start(): Promise<{ result: BackendStartupResult }> {\n if (this.#startPromise) {\n throw new Error('Backend has already started');\n }\n if (this.#stopPromise) {\n throw new Error('Backend has already stopped');\n }\n\n instanceRegistry.register(this);\n\n this.#startPromise = this.#doStart();\n return await this.#startPromise;\n }\n\n async #doStart(): Promise<{ result: BackendStartupResult }> {\n this.#serviceRegistry.checkForCircularDeps();\n\n for (const feature of this.#registeredFeatures) {\n this.#addFeature(await feature);\n }\n\n await this.#applyBackendFeatureLoaders(this.#registeredFeatureLoaders);\n\n this.#serviceRegistry.add(\n createRootInstanceMetadataServiceFactory(this.#registrations),\n );\n\n // This makes sure that any uncaught errors or unhandled rejections are\n // caught and logged, rather than terminating the process. We register these\n // as early as possible while still using the root logger service, the\n // tradeoff that if there are any unhandled errors as part of the that\n // instationation, it will cause the process to crash. If there are multiple\n // backend instances, each instance will log the error, because we can't\n // determine which instance the error came from.\n if (process.env.NODE_ENV !== 'test') {\n const rootLogger = await this.#serviceRegistry.get(\n coreServices.rootLogger,\n 'root',\n );\n process.on('unhandledRejection', (reason: Error) => {\n rootLogger\n ?.child({ type: 'unhandledRejection' })\n ?.error('Unhandled rejection', reason);\n });\n process.on('uncaughtException', error => {\n rootLogger\n ?.child({ type: 'uncaughtException' })\n ?.error('Uncaught exception', error);\n });\n }\n\n // Initialize all root scoped services\n await this.#serviceRegistry.initializeEagerServicesWithScope('root');\n\n const pluginInits = new Map<string, BackendRegisterInit>();\n const moduleInits = new Map<string, Map<string, BackendRegisterInit>>();\n\n // Enumerate all registrations\n for (const feature of this.#registrations) {\n for (const r of feature.getRegistrations()) {\n const provides = new Set<ExtensionPoint<unknown>>();\n\n if (r.type === 'plugin' || r.type === 'module') {\n for (const [extRef, extImpl] of r.extensionPoints) {\n if (this.#extensionPoints.has(extRef.id)) {\n throw new Error(\n `ExtensionPoint with ID '${extRef.id}' is already registered`,\n );\n }\n this.#extensionPoints.set(extRef.id, {\n impl: extImpl,\n pluginId: r.pluginId,\n });\n provides.add(extRef);\n }\n }\n\n if (r.type === 'plugin') {\n if (pluginInits.has(r.pluginId)) {\n throw new Error(`Plugin '${r.pluginId}' is already registered`);\n }\n pluginInits.set(r.pluginId, {\n provides,\n consumes: new Set(Object.values(r.init.deps)),\n init: r.init,\n });\n } else if (r.type === 'module') {\n let modules = moduleInits.get(r.pluginId);\n if (!modules) {\n modules = new Map();\n moduleInits.set(r.pluginId, modules);\n }\n if (modules.has(r.moduleId)) {\n throw new Error(\n `Module '${r.moduleId}' for plugin '${r.pluginId}' is already registered`,\n );\n }\n modules.set(r.moduleId, {\n provides,\n consumes: new Set(Object.values(r.init.deps)),\n init: r.init,\n });\n } else {\n throw new Error(`Invalid registration type '${(r as any).type}'`);\n }\n }\n }\n\n const pluginIds = [...pluginInits.keys()];\n\n const rootConfig = await this.#serviceRegistry.get(\n coreServices.rootConfig,\n 'root',\n );\n const rootLogger = await this.#serviceRegistry.get(\n coreServices.rootLogger,\n 'root',\n );\n\n const resultCollector = createInitializationResultCollector({\n pluginIds,\n logger: rootLogger,\n allowBootFailurePredicate: createAllowBootFailurePredicate(rootConfig),\n });\n\n // All plugins are initialized in parallel\n await Promise.all(\n pluginIds.map(async pluginId => {\n try {\n // Initialize all eager services\n await this.#serviceRegistry.initializeEagerServicesWithScope(\n 'plugin',\n pluginId,\n );\n\n // Modules are initialized before plugins, so that they can provide extension to the plugin\n const modules = moduleInits.get(pluginId);\n if (modules) {\n const tree = DependencyGraph.fromIterable(\n Array.from(modules).map(([moduleId, moduleInit]) => ({\n value: { moduleId, moduleInit },\n // Relationships are reversed at this point since we're only interested in the extension points.\n // If a modules provides extension point A we want it to be initialized AFTER all modules\n // that depend on extension point A, so that they can provide their extensions.\n consumes: Array.from(moduleInit.provides).map(p => p.id),\n provides: Array.from(moduleInit.consumes).map(c => c.id),\n })),\n );\n const circular = tree.detectCircularDependency();\n if (circular) {\n throw new ConflictError(\n `Circular dependency detected for modules of plugin '${pluginId}', ${circular\n .map(({ moduleId }) => `'${moduleId}'`)\n .join(' -> ')}`,\n );\n }\n await tree.parallelTopologicalTraversal(\n async ({ moduleId, moduleInit }) => {\n try {\n const moduleDeps = await this.#getInitDeps(\n moduleInit.init.deps,\n pluginId,\n moduleId,\n );\n await moduleInit.init.func(moduleDeps);\n resultCollector.onPluginModuleResult(pluginId, moduleId);\n } catch (error: unknown) {\n assertError(error);\n resultCollector.onPluginModuleResult(\n pluginId,\n moduleId,\n error,\n );\n }\n },\n );\n }\n\n // Once all modules have been initialized, we can initialize the plugin itself\n const pluginInit = pluginInits.get(pluginId);\n // We allow modules to be installed without the accompanying plugin, so the plugin may not exist\n if (pluginInit) {\n const pluginDeps = await this.#getInitDeps(\n pluginInit.init.deps,\n pluginId,\n );\n await pluginInit.init.func(pluginDeps);\n }\n\n resultCollector.onPluginResult(pluginId);\n\n // Once the plugin and all modules have been initialized, we can signal that the plugin has stared up successfully\n const lifecycleService = await this.#getPluginLifecycleImpl(pluginId);\n await lifecycleService.startup();\n } catch (error: unknown) {\n assertError(error);\n resultCollector.onPluginResult(pluginId, error);\n }\n }),\n ).catch(error => {\n throw new ForwardedError(\n 'Unexpected uncaught backend startup error',\n error,\n );\n });\n\n const result = resultCollector.finalize();\n if (result.outcome === 'failure') {\n throw new BackendStartupError(result);\n }\n\n // Once all plugins and modules have been initialized, we can signal that the backend has started up successfully\n const lifecycleService = await this.#getRootLifecycleImpl();\n await lifecycleService.startup();\n\n return { result };\n }\n\n // It's fine to call .stop() multiple times, which for example can happen with manual stop + process exit\n async stop(): Promise<void> {\n instanceRegistry.unregister(this);\n\n if (!this.#stopPromise) {\n this.#stopPromise = this.#doStop();\n }\n await this.#stopPromise;\n }\n\n async #doStop(): Promise<void> {\n if (!this.#startPromise) {\n return;\n }\n\n try {\n await this.#startPromise;\n } catch (error) {\n // The startup failed, but we may still want to do cleanup so we continue silently\n }\n\n const rootLifecycleService = await this.#getRootLifecycleImpl();\n\n // Root services like the health one need to immediately be notified of the shutdown\n await rootLifecycleService.beforeShutdown();\n\n // Get all plugins.\n const allPlugins = new Set<string>();\n for (const feature of this.#registrations) {\n for (const r of feature.getRegistrations()) {\n if (r.type === 'plugin') {\n allPlugins.add(r.pluginId);\n }\n }\n }\n\n // Iterate through all plugins and run their shutdown hooks.\n await Promise.allSettled(\n [...allPlugins].map(async pluginId => {\n const lifecycleService = await this.#getPluginLifecycleImpl(pluginId);\n await lifecycleService.shutdown();\n }),\n );\n\n // Once all plugin shutdown hooks are done, run root shutdown hooks.\n await rootLifecycleService.shutdown();\n }\n\n // Bit of a hacky way to grab the lifecycle services, potentially find a nicer way to do this\n async #getRootLifecycleImpl(): Promise<\n RootLifecycleService & {\n startup(): Promise<void>;\n beforeShutdown(): Promise<void>;\n shutdown(): Promise<void>;\n }\n > {\n const lifecycleService = await this.#serviceRegistry.get(\n coreServices.rootLifecycle,\n 'root',\n );\n\n const service = lifecycleService as any;\n if (\n service &&\n typeof service.startup === 'function' &&\n typeof service.shutdown === 'function'\n ) {\n return service;\n }\n\n throw new Error('Unexpected root lifecycle service implementation');\n }\n\n async #getPluginLifecycleImpl(\n pluginId: string,\n ): Promise<\n LifecycleService & { startup(): Promise<void>; shutdown(): Promise<void> }\n > {\n const lifecycleService = await this.#serviceRegistry.get(\n coreServices.lifecycle,\n pluginId,\n );\n\n const service = lifecycleService as any;\n if (\n service &&\n typeof service.startup === 'function' &&\n typeof service.shutdown === 'function'\n ) {\n return service;\n }\n\n throw new Error('Unexpected plugin lifecycle service implementation');\n }\n\n async #applyBackendFeatureLoaders(loaders: InternalBackendFeatureLoader[]) {\n const servicesAddedByLoaders = new Map<\n string,\n InternalBackendFeatureLoader\n >();\n\n for (const loader of loaders) {\n const deps = new Map<string, unknown>();\n const missingRefs = new Set<ServiceOrExtensionPoint>();\n\n for (const [name, ref] of Object.entries(loader.deps ?? {})) {\n if (ref.scope !== 'root') {\n throw new Error(\n `Feature loaders can only depend on root scoped services, but '${name}' is scoped to '${ref.scope}'. Offending loader is ${loader.description}`,\n );\n }\n const impl = await this.#serviceRegistry.get(\n ref as ServiceRef<unknown>,\n 'root',\n );\n if (impl) {\n deps.set(name, impl);\n } else {\n missingRefs.add(ref);\n }\n }\n\n if (missingRefs.size > 0) {\n const missing = Array.from(missingRefs).join(', ');\n throw new Error(\n `No service available for the following ref(s): ${missing}, depended on by feature loader ${loader.description}`,\n );\n }\n\n const result = await loader\n .loader(Object.fromEntries(deps))\n .then(features => features.map(unwrapFeature))\n .catch(error => {\n throw new ForwardedError(\n `Feature loader ${loader.description} failed`,\n error,\n );\n });\n\n let didAddServiceFactory = false;\n const newLoaders = new Array<InternalBackendFeatureLoader>();\n\n for await (const feature of result) {\n if (isBackendFeatureLoader(feature)) {\n newLoaders.push(feature);\n } else {\n // This block makes sure that feature loaders do not provide duplicate\n // implementations for the same service, but at the same time allows\n // service factories provided by feature loaders to be overridden by\n // ones that are explicitly installed with backend.add(serviceFactory).\n //\n // If a factory has already been explicitly installed, the service\n // factory provided by the loader will simply be ignored.\n if (isServiceFactory(feature) && !feature.service.multiton) {\n const conflictingLoader = servicesAddedByLoaders.get(\n feature.service.id,\n );\n if (conflictingLoader) {\n throw new Error(\n `Duplicate service implementations provided for ${feature.service.id} by both feature loader ${loader.description} and feature loader ${conflictingLoader.description}`,\n );\n }\n\n // Check that this service wasn't already explicitly added by backend.add(serviceFactory)\n if (!this.#serviceRegistry.hasBeenAdded(feature.service)) {\n didAddServiceFactory = true;\n servicesAddedByLoaders.set(feature.service.id, loader);\n this.#addFeature(feature);\n }\n } else {\n this.#addFeature(feature);\n }\n }\n }\n\n // Every time we add a new service factory we need to make sure that we don't have circular dependencies\n if (didAddServiceFactory) {\n this.#serviceRegistry.checkForCircularDeps();\n }\n\n // Apply loaders recursively, depth-first\n if (newLoaders.length > 0) {\n await this.#applyBackendFeatureLoaders(newLoaders);\n }\n }\n }\n}\n\nfunction toInternalBackendFeature(\n feature: BackendFeature,\n): InternalBackendFeature {\n if (feature.$$type !== '@backstage/BackendFeature') {\n throw new Error(`Invalid BackendFeature, bad type '${feature.$$type}'`);\n }\n const internal = feature as InternalBackendFeature;\n if (internal.version !== 'v1') {\n throw new Error(\n `Invalid BackendFeature, bad version '${internal.version}'`,\n );\n }\n return internal;\n}\n\nfunction isServiceFactory(\n feature: BackendFeature,\n): feature is InternalServiceFactory {\n const internal = toInternalBackendFeature(feature);\n if (internal.featureType === 'service') {\n return true;\n }\n // Backwards compatibility for v1 registrations that use duck typing\n return 'service' in internal;\n}\n\nfunction isBackendRegistrations(\n feature: BackendFeature,\n): feature is InternalBackendRegistrations {\n const internal = toInternalBackendFeature(feature);\n if (internal.featureType === 'registrations') {\n return true;\n }\n // Backwards compatibility for v1 registrations that use duck typing\n return 'getRegistrations' in internal;\n}\n\nfunction isBackendFeatureLoader(\n feature: BackendFeature,\n): feature is InternalBackendFeatureLoader {\n return toInternalBackendFeature(feature).featureType === 'loader';\n}\n"],"names":["createServiceFactory","coreServices","deepFreeze","ServiceRegistry","rootLogger","createInitializationResultCollector","createAllowBootFailurePredicate","DependencyGraph","ConflictError","assertError","lifecycleService","ForwardedError","BackendStartupError","unwrapFeature"],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ 'use strict';
2
+
3
+ var errors = require('@backstage/errors');
4
+
5
+ function formatMessage(startupResult) {
6
+ const parts = [
7
+ "Backend startup failed due to the following errors:"
8
+ ];
9
+ const failures = [];
10
+ for (const plugin of startupResult.plugins) {
11
+ if (plugin.failure && !plugin.failure.allowed) {
12
+ failures.push(
13
+ ` Plugin '${plugin.pluginId}' startup failed; caused by ${plugin.failure.error}`
14
+ );
15
+ }
16
+ for (const mod of plugin.modules) {
17
+ if (mod.failure && !mod.failure.allowed) {
18
+ failures.push(
19
+ ` Module '${mod.moduleId}' for plugin '${plugin.pluginId}' startup failed; caused by ${mod.failure.error}`
20
+ );
21
+ }
22
+ }
23
+ }
24
+ if (failures.length > 0) {
25
+ parts.push(...failures);
26
+ }
27
+ return parts.join("\n");
28
+ }
29
+ class BackendStartupError extends errors.CustomErrorBase {
30
+ name = "BackendStartupError";
31
+ /**
32
+ * The startup results for all plugins and modules.
33
+ */
34
+ #startupResult;
35
+ constructor(startupResult) {
36
+ super(formatMessage(startupResult));
37
+ this.#startupResult = startupResult;
38
+ }
39
+ get result() {
40
+ return this.#startupResult;
41
+ }
42
+ }
43
+
44
+ exports.BackendStartupError = BackendStartupError;
45
+ //# sourceMappingURL=BackendStartupError.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BackendStartupError.cjs.js","sources":["../../src/wiring/BackendStartupError.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { CustomErrorBase } from '@backstage/errors';\nimport { BackendStartupResult } from './types';\n\nfunction formatMessage(startupResult: BackendStartupResult): string {\n const parts: string[] = [\n 'Backend startup failed due to the following errors:',\n ];\n const failures: string[] = [];\n\n for (const plugin of startupResult.plugins) {\n if (plugin.failure && !plugin.failure.allowed) {\n failures.push(\n ` Plugin '${plugin.pluginId}' startup failed; caused by ${plugin.failure.error}`,\n );\n }\n\n for (const mod of plugin.modules) {\n if (mod.failure && !mod.failure.allowed) {\n failures.push(\n ` Module '${mod.moduleId}' for plugin '${plugin.pluginId}' startup failed; caused by ${mod.failure.error}`,\n );\n }\n }\n }\n\n if (failures.length > 0) {\n parts.push(...failures);\n }\n\n return parts.join('\\n');\n}\n\n/**\n * Error thrown when backend startup fails.\n * Includes detailed startup results for all plugins and modules.\n *\n * @public\n */\nexport class BackendStartupError extends CustomErrorBase {\n name = 'BackendStartupError' as const;\n\n /**\n * The startup results for all plugins and modules.\n */\n readonly #startupResult: BackendStartupResult;\n\n constructor(startupResult: BackendStartupResult) {\n super(formatMessage(startupResult));\n this.#startupResult = startupResult;\n }\n\n get result(): BackendStartupResult {\n return this.#startupResult;\n }\n}\n"],"names":["CustomErrorBase"],"mappings":";;;;AAmBA,SAAS,cAAc,aAAA,EAA6C;AAClE,EAAA,MAAM,KAAA,GAAkB;AAAA,IACtB;AAAA,GACF;AACA,EAAA,MAAM,WAAqB,EAAC;AAE5B,EAAA,KAAA,MAAW,MAAA,IAAU,cAAc,OAAA,EAAS;AAC1C,IAAA,IAAI,MAAA,CAAO,OAAA,IAAW,CAAC,MAAA,CAAO,QAAQ,OAAA,EAAS;AAC7C,MAAA,QAAA,CAAS,IAAA;AAAA,QACP,aAAa,MAAA,CAAO,QAAQ,CAAA,4BAAA,EAA+B,MAAA,CAAO,QAAQ,KAAK,CAAA;AAAA,OACjF;AAAA,IACF;AAEA,IAAA,KAAA,MAAW,GAAA,IAAO,OAAO,OAAA,EAAS;AAChC,MAAA,IAAI,GAAA,CAAI,OAAA,IAAW,CAAC,GAAA,CAAI,QAAQ,OAAA,EAAS;AACvC,QAAA,QAAA,CAAS,IAAA;AAAA,UACP,CAAA,UAAA,EAAa,IAAI,QAAQ,CAAA,cAAA,EAAiB,OAAO,QAAQ,CAAA,4BAAA,EAA+B,GAAA,CAAI,OAAA,CAAQ,KAAK,CAAA;AAAA,SAC3G;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,EAAA,IAAI,QAAA,CAAS,SAAS,CAAA,EAAG;AACvB,IAAA,KAAA,CAAM,IAAA,CAAK,GAAG,QAAQ,CAAA;AAAA,EACxB;AAEA,EAAA,OAAO,KAAA,CAAM,KAAK,IAAI,CAAA;AACxB;AAQO,MAAM,4BAA4BA,sBAAA,CAAgB;AAAA,EACvD,IAAA,GAAO,qBAAA;AAAA;AAAA;AAAA;AAAA,EAKE,cAAA;AAAA,EAET,YAAY,aAAA,EAAqC;AAC/C,IAAA,KAAA,CAAM,aAAA,CAAc,aAAa,CAAC,CAAA;AAClC,IAAA,IAAA,CAAK,cAAA,GAAiB,aAAA;AAAA,EACxB;AAAA,EAEA,IAAI,MAAA,GAA+B;AACjC,IAAA,OAAO,IAAA,CAAK,cAAA;AAAA,EACd;AACF;;;;"}
@@ -16,7 +16,7 @@ class BackstageBackend {
16
16
  }
17
17
  }
18
18
  async start() {
19
- await this.#initializer.start();
19
+ return await this.#initializer.start();
20
20
  }
21
21
  async stop() {
22
22
  await this.#initializer.stop();
@@ -1 +1 @@
1
- {"version":3,"file":"BackstageBackend.cjs.js","sources":["../../src/wiring/BackstageBackend.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { BackendFeature, ServiceFactory } from '@backstage/backend-plugin-api';\nimport { BackendInitializer } from './BackendInitializer';\nimport { unwrapFeature } from './helpers';\nimport { Backend } from './types';\n\nexport class BackstageBackend implements Backend {\n #initializer: BackendInitializer;\n\n constructor(defaultServiceFactories: ServiceFactory[]) {\n this.#initializer = new BackendInitializer(defaultServiceFactories);\n }\n\n add(feature: BackendFeature | Promise<{ default: BackendFeature }>): void {\n if (isPromise(feature)) {\n this.#initializer.add(feature.then(f => unwrapFeature(f.default)));\n } else {\n this.#initializer.add(unwrapFeature(feature));\n }\n }\n\n async start(): Promise<void> {\n await this.#initializer.start();\n }\n\n async stop(): Promise<void> {\n await this.#initializer.stop();\n }\n}\n\nfunction isPromise<T>(value: unknown | Promise<T>): value is Promise<T> {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'then' in value &&\n typeof value.then === 'function'\n );\n}\n"],"names":["BackendInitializer","unwrapFeature"],"mappings":";;;;;AAqBO,MAAM,gBAAA,CAAoC;AAAA,EAC/C,YAAA;AAAA,EAEA,YAAY,uBAAA,EAA2C;AACrD,IAAA,IAAA,CAAK,YAAA,GAAe,IAAIA,qCAAA,CAAmB,uBAAuB,CAAA;AAAA,EACpE;AAAA,EAEA,IAAI,OAAA,EAAsE;AACxE,IAAA,IAAI,SAAA,CAAU,OAAO,CAAA,EAAG;AACtB,MAAA,IAAA,CAAK,YAAA,CAAa,IAAI,OAAA,CAAQ,IAAA,CAAK,OAAKC,qBAAA,CAAc,CAAA,CAAE,OAAO,CAAC,CAAC,CAAA;AAAA,IACnE,CAAA,MAAO;AACL,MAAA,IAAA,CAAK,YAAA,CAAa,GAAA,CAAIA,qBAAA,CAAc,OAAO,CAAC,CAAA;AAAA,IAC9C;AAAA,EACF;AAAA,EAEA,MAAM,KAAA,GAAuB;AAC3B,IAAA,MAAM,IAAA,CAAK,aAAa,KAAA,EAAM;AAAA,EAChC;AAAA,EAEA,MAAM,IAAA,GAAsB;AAC1B,IAAA,MAAM,IAAA,CAAK,aAAa,IAAA,EAAK;AAAA,EAC/B;AACF;AAEA,SAAS,UAAa,KAAA,EAAkD;AACtE,EAAA,OACE,OAAO,UAAU,QAAA,IACjB,KAAA,KAAU,QACV,MAAA,IAAU,KAAA,IACV,OAAO,KAAA,CAAM,IAAA,KAAS,UAAA;AAE1B;;;;"}
1
+ {"version":3,"file":"BackstageBackend.cjs.js","sources":["../../src/wiring/BackstageBackend.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { BackendFeature, ServiceFactory } from '@backstage/backend-plugin-api';\nimport { BackendInitializer } from './BackendInitializer';\nimport { unwrapFeature } from './helpers';\nimport { Backend, BackendStartupResult } from './types';\n\nexport class BackstageBackend implements Backend {\n #initializer: BackendInitializer;\n\n constructor(defaultServiceFactories: ServiceFactory[]) {\n this.#initializer = new BackendInitializer(defaultServiceFactories);\n }\n\n add(feature: BackendFeature | Promise<{ default: BackendFeature }>): void {\n if (isPromise(feature)) {\n this.#initializer.add(feature.then(f => unwrapFeature(f.default)));\n } else {\n this.#initializer.add(unwrapFeature(feature));\n }\n }\n\n async start(): Promise<{ result: BackendStartupResult }> {\n return await this.#initializer.start();\n }\n\n async stop(): Promise<void> {\n await this.#initializer.stop();\n }\n}\n\nfunction isPromise<T>(value: unknown | Promise<T>): value is Promise<T> {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'then' in value &&\n typeof value.then === 'function'\n );\n}\n"],"names":["BackendInitializer","unwrapFeature"],"mappings":";;;;;AAqBO,MAAM,gBAAA,CAAoC;AAAA,EAC/C,YAAA;AAAA,EAEA,YAAY,uBAAA,EAA2C;AACrD,IAAA,IAAA,CAAK,YAAA,GAAe,IAAIA,qCAAA,CAAmB,uBAAuB,CAAA;AAAA,EACpE;AAAA,EAEA,IAAI,OAAA,EAAsE;AACxE,IAAA,IAAI,SAAA,CAAU,OAAO,CAAA,EAAG;AACtB,MAAA,IAAA,CAAK,YAAA,CAAa,IAAI,OAAA,CAAQ,IAAA,CAAK,OAAKC,qBAAA,CAAc,CAAA,CAAE,OAAO,CAAC,CAAC,CAAA;AAAA,IACnE,CAAA,MAAO;AACL,MAAA,IAAA,CAAK,YAAA,CAAa,GAAA,CAAIA,qBAAA,CAAc,OAAO,CAAC,CAAA;AAAA,IAC9C;AAAA,EACF;AAAA,EAEA,MAAM,KAAA,GAAmD;AACvD,IAAA,OAAO,MAAM,IAAA,CAAK,YAAA,CAAa,KAAA,EAAM;AAAA,EACvC;AAAA,EAEA,MAAM,IAAA,GAAsB;AAC1B,IAAA,MAAM,IAAA,CAAK,aAAa,IAAA,EAAK;AAAA,EAC/B;AACF;AAEA,SAAS,UAAa,KAAA,EAAkD;AACtE,EAAA,OACE,OAAO,UAAU,QAAA,IACjB,KAAA,KAAU,QACV,MAAA,IAAU,KAAA,IACV,OAAO,KAAA,CAAM,IAAA,KAAS,UAAA;AAE1B;;;;"}
@@ -0,0 +1,50 @@
1
+ 'use strict';
2
+
3
+ function createAllowBootFailurePredicate(config) {
4
+ const defaultPluginBootFailure = config?.getOptionalString("backend.startup.default.onPluginBootFailure") ?? "abort";
5
+ const defaultModuleBootFailure = config?.getOptionalString(
6
+ "backend.startup.default.onPluginModuleBootFailure"
7
+ ) ?? "abort";
8
+ const pluginOverrides = /* @__PURE__ */ new Map();
9
+ const moduleOverrides = /* @__PURE__ */ new Map();
10
+ const pluginsConfig = config?.getOptionalConfig("backend.startup.plugins");
11
+ if (pluginsConfig) {
12
+ for (const pluginId of pluginsConfig.keys()) {
13
+ const pluginConfig = pluginsConfig.getConfig(pluginId);
14
+ const pluginBootFailure = pluginConfig.getOptionalString(
15
+ "onPluginBootFailure"
16
+ );
17
+ if (pluginBootFailure) {
18
+ pluginOverrides.set(pluginId, pluginBootFailure);
19
+ }
20
+ const modulesConfig = pluginConfig.getOptionalConfig("modules");
21
+ if (modulesConfig) {
22
+ const moduleMap = /* @__PURE__ */ new Map();
23
+ for (const moduleId of modulesConfig.keys()) {
24
+ const moduleConfig = modulesConfig.getConfig(moduleId);
25
+ const moduleBootFailure = moduleConfig.getOptionalString(
26
+ "onPluginModuleBootFailure"
27
+ );
28
+ if (moduleBootFailure) {
29
+ moduleMap.set(moduleId, moduleBootFailure);
30
+ }
31
+ }
32
+ if (moduleMap.size > 0) {
33
+ moduleOverrides.set(pluginId, moduleMap);
34
+ }
35
+ }
36
+ }
37
+ }
38
+ return (pluginId, moduleId) => {
39
+ if (moduleId !== void 0) {
40
+ const moduleMap = moduleOverrides.get(pluginId);
41
+ const moduleBootFailure = moduleMap?.get(moduleId) ?? defaultModuleBootFailure;
42
+ return moduleBootFailure === "continue";
43
+ }
44
+ const pluginBootFailure = pluginOverrides.get(pluginId) ?? defaultPluginBootFailure;
45
+ return pluginBootFailure === "continue";
46
+ };
47
+ }
48
+
49
+ exports.createAllowBootFailurePredicate = createAllowBootFailurePredicate;
50
+ //# sourceMappingURL=createAllowBootFailurePredicate.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createAllowBootFailurePredicate.cjs.js","sources":["../../src/wiring/createAllowBootFailurePredicate.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\n\nexport type AllowBootFailurePredicate = (\n pluginId: string,\n moduleId?: string,\n) => boolean;\n\n/**\n * Creates a predicate function that determines whether a boot failure should be\n * allowed for a given plugin or module based on configuration.\n *\n * @param config - The configuration object to read boot failure settings from\n * @returns A predicate function that accepts a pluginId and optional moduleId,\n * and returns true if boot failures should be allowed, false otherwise.\n */\nexport function createAllowBootFailurePredicate(\n config?: Config,\n): AllowBootFailurePredicate {\n // Read default values upfront\n const defaultPluginBootFailure =\n config?.getOptionalString('backend.startup.default.onPluginBootFailure') ??\n 'abort';\n const defaultModuleBootFailure =\n config?.getOptionalString(\n 'backend.startup.default.onPluginModuleBootFailure',\n ) ?? 'abort';\n\n // Read plugin-specific overrides upfront\n const pluginOverrides = new Map<string, string>();\n const moduleOverrides = new Map<string, Map<string, string>>();\n\n const pluginsConfig = config?.getOptionalConfig('backend.startup.plugins');\n if (pluginsConfig) {\n for (const pluginId of pluginsConfig.keys()) {\n const pluginConfig = pluginsConfig.getConfig(pluginId);\n const pluginBootFailure = pluginConfig.getOptionalString(\n 'onPluginBootFailure',\n );\n if (pluginBootFailure) {\n pluginOverrides.set(pluginId, pluginBootFailure);\n }\n\n // Read module-specific overrides\n const modulesConfig = pluginConfig.getOptionalConfig('modules');\n if (modulesConfig) {\n const moduleMap = new Map<string, string>();\n for (const moduleId of modulesConfig.keys()) {\n const moduleConfig = modulesConfig.getConfig(moduleId);\n const moduleBootFailure = moduleConfig.getOptionalString(\n 'onPluginModuleBootFailure',\n );\n if (moduleBootFailure) {\n moduleMap.set(moduleId, moduleBootFailure);\n }\n }\n if (moduleMap.size > 0) {\n moduleOverrides.set(pluginId, moduleMap);\n }\n }\n }\n }\n\n return (pluginId: string, moduleId?: string): boolean => {\n if (moduleId !== undefined) {\n // Module-specific boot failure predicate\n const moduleMap = moduleOverrides.get(pluginId);\n const moduleBootFailure =\n moduleMap?.get(moduleId) ?? defaultModuleBootFailure;\n return moduleBootFailure === 'continue';\n }\n // Plugin-specific boot failure predicate\n const pluginBootFailure =\n pluginOverrides.get(pluginId) ?? defaultPluginBootFailure;\n return pluginBootFailure === 'continue';\n };\n}\n"],"names":[],"mappings":";;AA+BO,SAAS,gCACd,MAAA,EAC2B;AAE3B,EAAA,MAAM,wBAAA,GACJ,MAAA,EAAQ,iBAAA,CAAkB,6CAA6C,CAAA,IACvE,OAAA;AACF,EAAA,MAAM,2BACJ,MAAA,EAAQ,iBAAA;AAAA,IACN;AAAA,GACF,IAAK,OAAA;AAGP,EAAA,MAAM,eAAA,uBAAsB,GAAA,EAAoB;AAChD,EAAA,MAAM,eAAA,uBAAsB,GAAA,EAAiC;AAE7D,EAAA,MAAM,aAAA,GAAgB,MAAA,EAAQ,iBAAA,CAAkB,yBAAyB,CAAA;AACzE,EAAA,IAAI,aAAA,EAAe;AACjB,IAAA,KAAA,MAAW,QAAA,IAAY,aAAA,CAAc,IAAA,EAAK,EAAG;AAC3C,MAAA,MAAM,YAAA,GAAe,aAAA,CAAc,SAAA,CAAU,QAAQ,CAAA;AACrD,MAAA,MAAM,oBAAoB,YAAA,CAAa,iBAAA;AAAA,QACrC;AAAA,OACF;AACA,MAAA,IAAI,iBAAA,EAAmB;AACrB,QAAA,eAAA,CAAgB,GAAA,CAAI,UAAU,iBAAiB,CAAA;AAAA,MACjD;AAGA,MAAA,MAAM,aAAA,GAAgB,YAAA,CAAa,iBAAA,CAAkB,SAAS,CAAA;AAC9D,MAAA,IAAI,aAAA,EAAe;AACjB,QAAA,MAAM,SAAA,uBAAgB,GAAA,EAAoB;AAC1C,QAAA,KAAA,MAAW,QAAA,IAAY,aAAA,CAAc,IAAA,EAAK,EAAG;AAC3C,UAAA,MAAM,YAAA,GAAe,aAAA,CAAc,SAAA,CAAU,QAAQ,CAAA;AACrD,UAAA,MAAM,oBAAoB,YAAA,CAAa,iBAAA;AAAA,YACrC;AAAA,WACF;AACA,UAAA,IAAI,iBAAA,EAAmB;AACrB,YAAA,SAAA,CAAU,GAAA,CAAI,UAAU,iBAAiB,CAAA;AAAA,UAC3C;AAAA,QACF;AACA,QAAA,IAAI,SAAA,CAAU,OAAO,CAAA,EAAG;AACtB,UAAA,eAAA,CAAgB,GAAA,CAAI,UAAU,SAAS,CAAA;AAAA,QACzC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,EAAA,OAAO,CAAC,UAAkB,QAAA,KAA+B;AACvD,IAAA,IAAI,aAAa,MAAA,EAAW;AAE1B,MAAA,MAAM,SAAA,GAAY,eAAA,CAAgB,GAAA,CAAI,QAAQ,CAAA;AAC9C,MAAA,MAAM,iBAAA,GACJ,SAAA,EAAW,GAAA,CAAI,QAAQ,CAAA,IAAK,wBAAA;AAC9B,MAAA,OAAO,iBAAA,KAAsB,UAAA;AAAA,IAC/B;AAEA,IAAA,MAAM,iBAAA,GACJ,eAAA,CAAgB,GAAA,CAAI,QAAQ,CAAA,IAAK,wBAAA;AACnC,IAAA,OAAO,iBAAA,KAAsB,UAAA;AAAA,EAC/B,CAAA;AACF;;;;"}
@@ -0,0 +1,130 @@
1
+ 'use strict';
2
+
3
+ const LOGGER_INTERVAL_MAX = 6e4;
4
+ function joinIds(ids) {
5
+ return [...ids].map((id) => `'${id}'`).join(", ");
6
+ }
7
+ function createInitializationResultCollector(options) {
8
+ const logger = options.logger?.child({ type: "initialization" });
9
+ const beginAt = /* @__PURE__ */ new Date();
10
+ const starting = new Set(options.pluginIds.toSorted());
11
+ const started = /* @__PURE__ */ new Set();
12
+ let hasDisallowedFailures = false;
13
+ const pluginResults = [];
14
+ const moduleResultsByPlugin = new Map(
15
+ Array.from(starting).map((pluginId) => [pluginId, []])
16
+ );
17
+ logger?.info(`Plugin initialization started: ${joinIds(starting)}`);
18
+ const getInitStatus = () => {
19
+ let status = "";
20
+ if (started.size > 0) {
21
+ status = `, newly initialized: ${joinIds(started)}`;
22
+ started.clear();
23
+ }
24
+ if (starting.size > 0) {
25
+ status += `, still initializing: ${joinIds(starting)}`;
26
+ }
27
+ return status;
28
+ };
29
+ let interval = 1e3;
30
+ let prevInterval = 0;
31
+ let timeout;
32
+ const onTimeout = () => {
33
+ logger?.info(`Plugin initialization in progress${getInitStatus()}`);
34
+ const nextInterval = Math.min(interval + prevInterval, LOGGER_INTERVAL_MAX);
35
+ prevInterval = interval;
36
+ interval = nextInterval;
37
+ timeout = setTimeout(onTimeout, nextInterval);
38
+ };
39
+ timeout = setTimeout(onTimeout, interval);
40
+ return {
41
+ onPluginResult(pluginId, error) {
42
+ starting.delete(pluginId);
43
+ started.add(pluginId);
44
+ const modules = moduleResultsByPlugin.get(pluginId);
45
+ if (!modules) {
46
+ throw new Error(
47
+ `Failed to push plugin result for nonexistent plugin '${pluginId}'`
48
+ );
49
+ }
50
+ if (!error) {
51
+ pluginResults.push({
52
+ pluginId,
53
+ resultAt: /* @__PURE__ */ new Date(),
54
+ modules
55
+ });
56
+ } else {
57
+ const allowed = options.allowBootFailurePredicate(pluginId);
58
+ pluginResults.push({
59
+ pluginId,
60
+ resultAt: /* @__PURE__ */ new Date(),
61
+ modules,
62
+ failure: {
63
+ error,
64
+ allowed
65
+ }
66
+ });
67
+ if (allowed) {
68
+ logger?.error(
69
+ `Plugin '${pluginId}' threw an error during startup, but boot failure is permitted for this plugin so startup will continue.`,
70
+ error
71
+ );
72
+ } else {
73
+ hasDisallowedFailures = true;
74
+ const status = starting.size > 0 ? `, waiting for ${starting.size} other plugins to finish before shutting down the process` : "";
75
+ logger?.error(
76
+ `Plugin '${pluginId}' threw an error during startup${status}.`,
77
+ error
78
+ );
79
+ }
80
+ }
81
+ },
82
+ onPluginModuleResult(pluginId, moduleId, error) {
83
+ const moduleResults = moduleResultsByPlugin.get(pluginId);
84
+ if (!moduleResults) {
85
+ throw new Error(
86
+ `Failed to push module result for nonexistent plugin '${pluginId}'`
87
+ );
88
+ }
89
+ if (!error) {
90
+ moduleResults.push({ moduleId, resultAt: /* @__PURE__ */ new Date() });
91
+ } else {
92
+ const allowed = options.allowBootFailurePredicate(pluginId, moduleId);
93
+ moduleResults.push({
94
+ moduleId,
95
+ resultAt: /* @__PURE__ */ new Date(),
96
+ failure: { error, allowed }
97
+ });
98
+ if (allowed) {
99
+ logger?.error(
100
+ `Module ${moduleId} in Plugin '${pluginId}' threw an error during startup, but boot failure is permitted for this plugin module so startup will continue.`,
101
+ error
102
+ );
103
+ } else {
104
+ hasDisallowedFailures = true;
105
+ const status = starting.size > 0 ? `, waiting for ${starting.size} other plugins to finish before shutting down the process` : "";
106
+ logger?.error(
107
+ `Module ${moduleId} in Plugin '${pluginId}' threw an error during startup${status}.`,
108
+ error
109
+ );
110
+ }
111
+ }
112
+ },
113
+ finalize() {
114
+ logger?.info(`Plugin initialization complete${getInitStatus()}`);
115
+ if (timeout) {
116
+ clearTimeout(timeout);
117
+ timeout = void 0;
118
+ }
119
+ return {
120
+ beginAt,
121
+ resultAt: /* @__PURE__ */ new Date(),
122
+ outcome: hasDisallowedFailures ? "failure" : "success",
123
+ plugins: pluginResults
124
+ };
125
+ }
126
+ };
127
+ }
128
+
129
+ exports.createInitializationResultCollector = createInitializationResultCollector;
130
+ //# sourceMappingURL=createInitializationResultCollector.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createInitializationResultCollector.cjs.js","sources":["../../src/wiring/createInitializationResultCollector.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { RootLoggerService } from '@backstage/backend-plugin-api';\nimport { AllowBootFailurePredicate } from './createAllowBootFailurePredicate';\nimport {\n BackendStartupResult,\n PluginStartupResult,\n ModuleStartupResult,\n} from './types';\n\nconst LOGGER_INTERVAL_MAX = 60_000;\n\nfunction joinIds(ids: Iterable<string>): string {\n return [...ids].map(id => `'${id}'`).join(', ');\n}\n\nexport function createInitializationResultCollector(options: {\n pluginIds: string[];\n logger?: RootLoggerService;\n allowBootFailurePredicate: AllowBootFailurePredicate;\n}): {\n onPluginResult(pluginId: string, error?: Error): void;\n onPluginModuleResult(pluginId: string, moduleId: string, error?: Error): void;\n finalize(): BackendStartupResult;\n} {\n const logger = options.logger?.child({ type: 'initialization' });\n const beginAt = new Date();\n const starting = new Set(options.pluginIds.toSorted());\n const started = new Set<string>();\n\n let hasDisallowedFailures = false;\n\n const pluginResults: PluginStartupResult[] = [];\n const moduleResultsByPlugin: Map<string, ModuleStartupResult[]> = new Map(\n Array.from(starting).map(pluginId => [pluginId, []]),\n );\n\n logger?.info(`Plugin initialization started: ${joinIds(starting)}`);\n\n const getInitStatus = () => {\n let status = '';\n if (started.size > 0) {\n status = `, newly initialized: ${joinIds(started)}`;\n started.clear();\n }\n if (starting.size > 0) {\n status += `, still initializing: ${joinIds(starting)}`;\n }\n return status;\n };\n\n // Periodically log the initialization status with a fibonacci backoff\n let interval = 1000;\n let prevInterval = 0;\n let timeout: NodeJS.Timeout | undefined;\n const onTimeout = () => {\n logger?.info(`Plugin initialization in progress${getInitStatus()}`);\n\n const nextInterval = Math.min(interval + prevInterval, LOGGER_INTERVAL_MAX);\n prevInterval = interval;\n interval = nextInterval;\n\n timeout = setTimeout(onTimeout, nextInterval);\n };\n timeout = setTimeout(onTimeout, interval);\n\n return {\n onPluginResult(pluginId: string, error?: Error) {\n starting.delete(pluginId);\n started.add(pluginId);\n\n const modules = moduleResultsByPlugin.get(pluginId);\n if (!modules) {\n throw new Error(\n `Failed to push plugin result for nonexistent plugin '${pluginId}'`,\n );\n }\n\n if (!error) {\n pluginResults.push({\n pluginId,\n resultAt: new Date(),\n modules,\n });\n } else {\n const allowed = options.allowBootFailurePredicate(pluginId);\n pluginResults.push({\n pluginId,\n resultAt: new Date(),\n modules,\n failure: {\n error,\n allowed,\n },\n });\n if (allowed) {\n logger?.error(\n `Plugin '${pluginId}' threw an error during startup, but boot failure is permitted for this plugin so startup will continue.`,\n error,\n );\n } else {\n hasDisallowedFailures = true;\n const status =\n starting.size > 0\n ? `, waiting for ${starting.size} other plugins to finish before shutting down the process`\n : '';\n logger?.error(\n `Plugin '${pluginId}' threw an error during startup${status}.`,\n error,\n );\n }\n }\n },\n onPluginModuleResult(pluginId: string, moduleId: string, error?: Error) {\n const moduleResults = moduleResultsByPlugin.get(pluginId);\n if (!moduleResults) {\n throw new Error(\n `Failed to push module result for nonexistent plugin '${pluginId}'`,\n );\n }\n\n if (!error) {\n moduleResults.push({ moduleId, resultAt: new Date() });\n } else {\n const allowed = options.allowBootFailurePredicate(pluginId, moduleId);\n moduleResults.push({\n moduleId,\n resultAt: new Date(),\n failure: { error, allowed },\n });\n if (allowed) {\n logger?.error(\n `Module ${moduleId} in Plugin '${pluginId}' threw an error during startup, but boot failure is permitted for this plugin module so startup will continue.`,\n error,\n );\n } else {\n hasDisallowedFailures = true;\n const status =\n starting.size > 0\n ? `, waiting for ${starting.size} other plugins to finish before shutting down the process`\n : '';\n logger?.error(\n `Module ${moduleId} in Plugin '${pluginId}' threw an error during startup${status}.`,\n error,\n );\n }\n }\n },\n finalize() {\n logger?.info(`Plugin initialization complete${getInitStatus()}`);\n\n if (timeout) {\n clearTimeout(timeout);\n timeout = undefined;\n }\n return {\n beginAt,\n resultAt: new Date(),\n outcome: hasDisallowedFailures ? 'failure' : 'success',\n plugins: pluginResults,\n };\n },\n };\n}\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/backend-app-api",
3
- "version": "1.3.0-next.1",
3
+ "version": "1.4.0-next.0",
4
4
  "description": "Core API used by Backstage backend apps",
5
5
  "backstage": {
6
6
  "role": "node-library"
@@ -50,14 +50,14 @@
50
50
  "test": "backstage-cli package test"
51
51
  },
52
52
  "dependencies": {
53
- "@backstage/backend-plugin-api": "1.5.0-next.1",
54
- "@backstage/config": "1.3.6-next.0",
53
+ "@backstage/backend-plugin-api": "1.5.1-next.0",
54
+ "@backstage/config": "1.3.6",
55
55
  "@backstage/errors": "1.2.7"
56
56
  },
57
57
  "devDependencies": {
58
- "@backstage/backend-defaults": "0.13.1-next.1",
59
- "@backstage/backend-test-utils": "1.10.0-next.1",
60
- "@backstage/cli": "0.34.5-next.1"
58
+ "@backstage/backend-defaults": "0.14.0-next.0",
59
+ "@backstage/backend-test-utils": "1.10.1-next.0",
60
+ "@backstage/cli": "0.34.6-next.0"
61
61
  },
62
62
  "configSchema": "config.d.ts"
63
63
  }
@@ -1,78 +0,0 @@
1
- 'use strict';
2
-
3
- const LOGGER_INTERVAL_MAX = 6e4;
4
- function joinIds(ids) {
5
- return [...ids].map((id) => `'${id}'`).join(", ");
6
- }
7
- function createInitializationLogger(pluginIds, rootLogger) {
8
- const logger = rootLogger?.child({ type: "initialization" });
9
- const starting = new Set(pluginIds);
10
- const started = /* @__PURE__ */ new Set();
11
- logger?.info(`Plugin initialization started: ${joinIds(pluginIds)}`);
12
- const getInitStatus = () => {
13
- let status = "";
14
- if (started.size > 0) {
15
- status = `, newly initialized: ${joinIds(started)}`;
16
- started.clear();
17
- }
18
- if (starting.size > 0) {
19
- status += `, still initializing: ${joinIds(starting)}`;
20
- }
21
- return status;
22
- };
23
- let interval = 1e3;
24
- let prevInterval = 0;
25
- let timeout;
26
- const onTimeout = () => {
27
- logger?.info(`Plugin initialization in progress${getInitStatus()}`);
28
- const nextInterval = Math.min(interval + prevInterval, LOGGER_INTERVAL_MAX);
29
- prevInterval = interval;
30
- interval = nextInterval;
31
- timeout = setTimeout(onTimeout, nextInterval);
32
- };
33
- timeout = setTimeout(onTimeout, interval);
34
- return {
35
- onPluginStarted(pluginId) {
36
- starting.delete(pluginId);
37
- started.add(pluginId);
38
- },
39
- onPluginFailed(pluginId, error) {
40
- starting.delete(pluginId);
41
- const status = starting.size > 0 ? `, waiting for ${starting.size} other plugins to finish before shutting down the process` : "";
42
- logger?.error(
43
- `Plugin '${pluginId}' threw an error during startup${status}.`,
44
- error
45
- );
46
- },
47
- onPermittedPluginFailure(pluginId, error) {
48
- starting.delete(pluginId);
49
- logger?.error(
50
- `Plugin '${pluginId}' threw an error during startup, but boot failure is permitted for this plugin so startup will continue.`,
51
- error
52
- );
53
- },
54
- onPluginModuleFailed(pluginId, moduleId, error) {
55
- const status = starting.size > 0 ? `, waiting for ${starting.size} other plugins to finish before shutting down the process` : "";
56
- logger?.error(
57
- `Module ${moduleId} in Plugin '${pluginId}' threw an error during startup${status}.`,
58
- error
59
- );
60
- },
61
- onPermittedPluginModuleFailure(pluginId, moduleId, error) {
62
- logger?.error(
63
- `Module ${moduleId} in Plugin '${pluginId}' threw an error during startup, but boot failure is permitted for this plugin module so startup will continue.`,
64
- error
65
- );
66
- },
67
- onAllStarted() {
68
- logger?.info(`Plugin initialization complete${getInitStatus()}`);
69
- if (timeout) {
70
- clearTimeout(timeout);
71
- timeout = void 0;
72
- }
73
- }
74
- };
75
- }
76
-
77
- exports.createInitializationLogger = createInitializationLogger;
78
- //# sourceMappingURL=createInitializationLogger.cjs.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"createInitializationLogger.cjs.js","sources":["../../src/wiring/createInitializationLogger.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { RootLoggerService } from '@backstage/backend-plugin-api';\n\nconst LOGGER_INTERVAL_MAX = 60_000;\n\nfunction joinIds(ids: Iterable<string>): string {\n return [...ids].map(id => `'${id}'`).join(', ');\n}\n\nexport function createInitializationLogger(\n pluginIds: string[],\n rootLogger?: RootLoggerService,\n): {\n onPluginStarted(pluginId: string): void;\n onPluginFailed(pluginId: string, error: Error): void;\n onPermittedPluginFailure(pluginId: string, error: Error): void;\n onPluginModuleFailed(pluginId: string, moduleId: string, error: Error): void;\n onPermittedPluginModuleFailure(\n pluginId: string,\n moduleId: string,\n error: Error,\n ): void;\n onAllStarted(): void;\n} {\n const logger = rootLogger?.child({ type: 'initialization' });\n const starting = new Set(pluginIds);\n const started = new Set<string>();\n\n logger?.info(`Plugin initialization started: ${joinIds(pluginIds)}`);\n\n const getInitStatus = () => {\n let status = '';\n if (started.size > 0) {\n status = `, newly initialized: ${joinIds(started)}`;\n started.clear();\n }\n if (starting.size > 0) {\n status += `, still initializing: ${joinIds(starting)}`;\n }\n return status;\n };\n\n // Periodically log the initialization status with a fibonacci backoff\n let interval = 1000;\n let prevInterval = 0;\n let timeout: NodeJS.Timeout | undefined;\n const onTimeout = () => {\n logger?.info(`Plugin initialization in progress${getInitStatus()}`);\n\n const nextInterval = Math.min(interval + prevInterval, LOGGER_INTERVAL_MAX);\n prevInterval = interval;\n interval = nextInterval;\n\n timeout = setTimeout(onTimeout, nextInterval);\n };\n timeout = setTimeout(onTimeout, interval);\n\n return {\n onPluginStarted(pluginId: string) {\n starting.delete(pluginId);\n started.add(pluginId);\n },\n onPluginFailed(pluginId: string, error: Error) {\n starting.delete(pluginId);\n const status =\n starting.size > 0\n ? `, waiting for ${starting.size} other plugins to finish before shutting down the process`\n : '';\n logger?.error(\n `Plugin '${pluginId}' threw an error during startup${status}.`,\n error,\n );\n },\n onPermittedPluginFailure(pluginId: string, error: Error) {\n starting.delete(pluginId);\n logger?.error(\n `Plugin '${pluginId}' threw an error during startup, but boot failure is permitted for this plugin so startup will continue.`,\n error,\n );\n },\n onPluginModuleFailed(pluginId: string, moduleId: string, error: Error) {\n const status =\n starting.size > 0\n ? `, waiting for ${starting.size} other plugins to finish before shutting down the process`\n : '';\n logger?.error(\n `Module ${moduleId} in Plugin '${pluginId}' threw an error during startup${status}.`,\n error,\n );\n },\n onPermittedPluginModuleFailure(\n pluginId: string,\n moduleId: string,\n error: Error,\n ) {\n logger?.error(\n `Module ${moduleId} in Plugin '${pluginId}' threw an error during startup, but boot failure is permitted for this plugin module so startup will continue.`,\n error,\n );\n },\n onAllStarted() {\n logger?.info(`Plugin initialization complete${getInitStatus()}`);\n\n if (timeout) {\n clearTimeout(timeout);\n timeout = undefined;\n }\n },\n };\n}\n"],"names":[],"mappings":"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"}