[IMP] web: make startServices promise reject when missing dependencies

Previously, the promise returned by startServices was resolved when some
services were missing dependencies. The rationale was that those
dependencies could be fulfilled by bundles that might be in the page
later.

This rationale ignored the fact that bundles or scripts that are in the
same page will be executed in the same microtick.

This commit changes the returned promise from startServices such that it
will throw if after all services that were registered in the registry at
call time that could be started are started, and there are still
services registered that could not be started for lack of dependencies.
This commit is contained in:
Samuel Degueldre
2021-06-18 21:31:30 +02:00
committed by Aaron Bohy
parent 60d3f7400b
commit 40fbbe2b52
+14 -11
View File
@@ -57,8 +57,11 @@ export const SERVICES_METADATA = {};
*/
export async function startServices(env) {
const toStart = new Set();
let timeoutId;
serviceRegistry.on("UPDATE", null, async (payload) => {
// Wait for all synchronous code so that if new services that depend on
// one another are added to the registry, they're all present before we
// start them.
await Promise.resolve();
const { operation, key: name, value: service } = payload;
if (operation === "delete") {
// We hardly see why it would be usefull to remove a service.
@@ -70,10 +73,10 @@ export async function startServices(env) {
const namedService = Object.assign(Object.create(service), { name });
toStart.add(namedService);
} else {
timeoutId = await _startServices(env, toStart, timeoutId);
await _startServices(env, toStart);
}
});
timeoutId = await _startServices(env, toStart, timeoutId);
await _startServices(env, toStart);
}
async function _startServices(env, toStart, timeoutId) {
@@ -128,17 +131,17 @@ async function _startServices(env, toStart, timeoutId) {
}
}
await start();
clearTimeout(timeoutId);
timeoutId = undefined;
if (toStart.size) {
const names = [...toStart].map((s) => s.name);
timeoutId = setTimeout(() => {
timeoutId = undefined;
throw new Error(`Some services could not be started: ${names}`);
}, 15000);
toStart.clear();
const missingDeps = new Set();
[...toStart].forEach((s) => s.dependencies.forEach((dep) => {
if (!(dep in services) && !names.includes(dep)) {
missingDeps.add(dep);
}
}));
const depNames = [...missingDeps].join(", ");
throw new Error(`Some services could not be started: ${names}. Missing dependencies: ${depNames}`);
}
return timeoutId;
function findNext() {
for (let s of toStart) {