lib/project-lifecycle-runtime.js
Rama main · réplica de lectura del repositorio original.
// Retain failed shutdown handles so an explicitly reviewed recovery can retry them.
var crypto = require('crypto');
var witnesses = require('./project-lifecycle-process-witness');
function attachLifecycleRuntime(ctx) {
var epoch = crypto.randomUUID(), retired = new Map();
function target(slug, project) {
var status = project.getStatus();
return { slug: slug, path: status.path, projectKnowledgeId: status.projectKnowledgeId || null, epoch: epoch };
}
function key(item) { return JSON.stringify([item.slug, item.path, item.projectKnowledgeId]); }
function matches(item, project) { return key(item) === key(target(item.slug, project)); }
function targets(slug) {
var out = [], witness = witnesses.capture();
ctx.projects.forEach(function (project, candidate) {
if (candidate === slug || candidate.indexOf(slug + '--') === 0) out.push(Object.assign(target(candidate, project), { witness: witness }));
});
return out;
}
function stop(item, project) {
var id = key(item), previous = retired.get(id);
if (previous && previous.project !== project) {
if (!previous.closed) throw new Error('An earlier runtime with this identity has not confirmed closure.');
previous = null;
}
if (previous && previous.running) return previous.running;
if (previous && previous.closed) return Promise.resolve(true);
var state = previous || { project: project, target: item, closed: false };
retired.set(id, state);
state.running = Promise.resolve().then(function () { return state.project.destroy(); }).then(function (result) {
if (result !== true) throw new Error('Project runtime closure was not acknowledged: ' + item.slug);
state.closed = true; return true;
}).finally(function () { state.running = null; });
return state.running;
}
async function close(items, proof) {
for (var item of items) {
var live = ctx.projects.get(item.slug), previous = retired.get(key(item));
if (live) {
if (!matches(item, live)) throw new Error('A replacement runtime occupies this registration.');
ctx.projects.delete(item.slug);
await stop(item, live);
} else if (previous) await stop(item, previous.project);
else if (!proof && !witnesses.confirmsExit(item.witness)) throw new Error('Runtime closure evidence is unavailable on this host. Keep the operation pending until its original host confirms closure.');
}
return true;
}
function shutdown() { return Promise.all(Array.from(retired.values()).filter(function (item) { return !item.closed; }).map(function (item) { return stop(item.target, item.project); })); }
return { targets: targets, close: close, shutdown: shutdown };
}
module.exports = { attachLifecycleRuntime: attachLifecycleRuntime };