Keep restricted engines reserved through asynchronous retirement

This commit is contained in:
Timothy J. Aveni
2026-10-08 05:21:10 -07:00
parent dec3aa475a
commit 1b91e21d49
2 changed files with 42 additions and 4 deletions
+6 -4
View File
@@ -239,15 +239,17 @@ export async function serveRestrictedRegistry(config, io = process) {
}
const engine = call.engine;
if (engine) {
// Revoke the frame token before returning an engine to the idle pool.
// A delayed child request can never acquire the next call's authority.
if (engine.current === call) engine.current = null;
if (!stopped && reason.code === "INVOCATION_ENDED" && !usageFailure && !engine.destroying) {
const rss = (await engineUsage(engine)).memoryBytes;
metrics.peakRSSBytes = Math.max(metrics.peakRSSBytes, rss);
// Bound retained engine heaps as well as lifetime. Hard aggregate
// physical memory remains the supervising process/cgroup's contract.
if (rss <= 128 * 1024 * 1024) {
// Keep the lease busy through every await. Another artifact can evict
// an idle lease immediately; never publish an engine still retiring
// or one whose process died while its final usage read was pending.
if (rss <= 128 * 1024 * 1024 && !stopped && !engine.destroying && engine.current === call) {
// Revoke the frame token atomically with publishing idle capacity.
engine.current = null;
idleEngines.push(engine);
engine.idleUntil = Date.now() + limits.engineIdleMs;
engine.idleTimer = setTimeout(() => void destroyEngine(engine).catch(fail), limits.engineIdleMs);
+36
View File
@@ -686,3 +686,39 @@ test("the shared engine budget evicts idle code families and rejects busy oversu
}
assert.equal(engineBudget.stats().engines, 0);
});
test("engine retirement accounting keeps its admission lease busy", async () => {
const observations = [];
let idle;
const engineBudget = new RestrictedEngineBudget(1, async () => ({
usage: async () => {
observations.push(idle());
await new Promise((done) => setImmediate(done));
return { cpuMicroseconds: 0, memoryBytes: 1024 };
},
release: async () => {},
}));
const acquire = engineBudget.acquire.bind(engineBudget);
engineBudget.acquire = (isIdle, evict) => {
idle = isIdle;
return acquire(isIdle, evict);
};
const f = await fixture(registry("return request.input;"), { engineBudget });
try {
f.start("first");
assert.equal((await f.receive()).output, "first");
assert.ok(observations.length > 0);
assert.ok(
observations.every((value) => !value),
"An engine must not become evictable during asynchronous retirement accounting",
);
assert.equal(f.stats().idle, 1);
assert.equal(idle(), true);
f.start("second");
assert.equal((await f.receive()).output, "second");
assert.equal(f.stats().starts, 1);
} finally {
await f.close();
}
assert.equal(engineBudget.stats().engines, 0);
});