Expose workspace-scoped restricted artifact placement and live executor activity
Show per-export placement, static eligibility blockers, bounded metadata and live pool/idle/timing diagnostics. Attach inspector updates through one private shard stream and the existing authenticated SSE hub without waking graph views or VMs. Fix packed agent preparation to use OpenSSH and the worker’s own private systemd credential.
This commit is contained in:
@@ -148,6 +148,11 @@ export async function serveRestrictedRegistry(config, io = process) {
|
|||||||
engines = new Set(),
|
engines = new Set(),
|
||||||
idleEngines = [];
|
idleEngines = [];
|
||||||
const metrics = { starts: 0, reused: 0, completed: 0, peakRSSBytes: 0 };
|
const metrics = { starts: 0, reused: 0, completed: 0, peakRSSBytes: 0 };
|
||||||
|
const changed = () => {
|
||||||
|
try {
|
||||||
|
config.onChange?.();
|
||||||
|
} catch {}
|
||||||
|
};
|
||||||
let buffered = Buffer.alloc(0),
|
let buffered = Buffer.alloc(0),
|
||||||
stopped = false,
|
stopped = false,
|
||||||
failure;
|
failure;
|
||||||
@@ -244,6 +249,7 @@ export async function serveRestrictedRegistry(config, io = process) {
|
|||||||
// physical memory remains the supervising process/cgroup's contract.
|
// physical memory remains the supervising process/cgroup's contract.
|
||||||
if (rss <= 128 * 1024 * 1024) {
|
if (rss <= 128 * 1024 * 1024) {
|
||||||
idleEngines.push(engine);
|
idleEngines.push(engine);
|
||||||
|
engine.idleUntil = Date.now() + limits.engineIdleMs;
|
||||||
engine.idleTimer = setTimeout(() => void destroyEngine(engine).catch(fail), limits.engineIdleMs);
|
engine.idleTimer = setTimeout(() => void destroyEngine(engine).catch(fail), limits.engineIdleMs);
|
||||||
} else await destroyEngine(engine);
|
} else await destroyEngine(engine);
|
||||||
} else await destroyEngine(engine);
|
} else await destroyEngine(engine);
|
||||||
@@ -300,6 +306,7 @@ export async function serveRestrictedRegistry(config, io = process) {
|
|||||||
} finally {
|
} finally {
|
||||||
engines.delete(engine);
|
engines.delete(engine);
|
||||||
await engine.release?.();
|
await engine.release?.();
|
||||||
|
changed();
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
return engine.destroying;
|
return engine.destroying;
|
||||||
@@ -418,6 +425,7 @@ export async function serveRestrictedRegistry(config, io = process) {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
metrics.starts++;
|
metrics.starts++;
|
||||||
|
changed();
|
||||||
engine.exited = new Promise((resolve) => {
|
engine.exited = new Promise((resolve) => {
|
||||||
engine.child.once("exit", resolve);
|
engine.child.once("exit", resolve);
|
||||||
engine.child.once("error", resolve);
|
engine.child.once("error", resolve);
|
||||||
@@ -462,6 +470,9 @@ export async function serveRestrictedRegistry(config, io = process) {
|
|||||||
executionMs: call.executionMs ?? null,
|
executionMs: call.executionMs ?? null,
|
||||||
totalMs: performance.now() - call.receivedAt,
|
totalMs: performance.now() - call.receivedAt,
|
||||||
};
|
};
|
||||||
|
metrics.lastFailure =
|
||||||
|
reply.status === "failed" && /^[A-Z0-9_]{1,128}$/.test(reply.error?.code) ? reply.error.code : null;
|
||||||
|
changed();
|
||||||
send(call.cancellationReply ?? reply);
|
send(call.cancellationReply ?? reply);
|
||||||
pump();
|
pump();
|
||||||
})());
|
})());
|
||||||
@@ -470,6 +481,7 @@ export async function serveRestrictedRegistry(config, io = process) {
|
|||||||
const { message } = call;
|
const { message } = call;
|
||||||
call.startedAt = performance.now();
|
call.startedAt = performance.now();
|
||||||
active.set(message.invocation, call);
|
active.set(message.invocation, call);
|
||||||
|
changed();
|
||||||
const terminate = (code) => {
|
const terminate = (code) => {
|
||||||
if (!call.open) return;
|
if (!call.open) return;
|
||||||
void finish(call, fixedError(code), {
|
void finish(call, fixedError(code), {
|
||||||
@@ -687,6 +699,9 @@ export async function serveRestrictedRegistry(config, io = process) {
|
|||||||
queued: queued.length,
|
queued: queued.length,
|
||||||
engines: engines.size,
|
engines: engines.size,
|
||||||
idle: idleEngines.length,
|
idle: idleEngines.length,
|
||||||
|
idleDeadline: idleEngines.length
|
||||||
|
? new Date(Math.min(...idleEngines.map((engine) => engine.idleUntil))).toISOString()
|
||||||
|
: null,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -570,12 +570,25 @@ test("an expired frame token cannot borrow a later invocation's broker", async (
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("idle engines evict without a graph poll and restart with fresh state", async () => {
|
test("idle engines evict without a graph poll and restart with fresh state", async () => {
|
||||||
const f = await fixture(registry("return request.input;"), { engineIdleMs: 30 });
|
const updates = [];
|
||||||
|
const f = await fixture(registry("return request.input;"), {
|
||||||
|
engineIdleMs: 30,
|
||||||
|
onChange: () => updates.push(f.stats()),
|
||||||
|
});
|
||||||
try {
|
try {
|
||||||
f.start("first");
|
f.start("first");
|
||||||
assert.equal((await f.receive()).output, "first");
|
assert.equal((await f.receive()).output, "first");
|
||||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||||
assert.equal(f.stats().engines, 0);
|
assert.equal(f.stats().engines, 0);
|
||||||
|
assert.ok(
|
||||||
|
updates.some((s) => s.active > 0),
|
||||||
|
"Inspectors observe active invocation admission",
|
||||||
|
);
|
||||||
|
assert.ok(
|
||||||
|
updates.some((s) => s.idle > 0 && s.idleDeadline),
|
||||||
|
"Idle eviction deadline is visible",
|
||||||
|
);
|
||||||
|
assert.equal(updates.at(-1).engines, 0, "Eviction pushes an update without a graph poll");
|
||||||
f.start("second");
|
f.start("second");
|
||||||
assert.equal((await f.receive()).output, "second");
|
assert.equal((await f.receive()).output, "second");
|
||||||
assert.equal(f.stats().starts, 2);
|
assert.equal(f.stats().starts, 2);
|
||||||
|
|||||||
Reference in New Issue
Block a user