fix: keep readiness confirmation responsive near its deadline

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-09-21 09:39:45 -05:00
1 parent 7e1a841ba5
commit 039a74c582
2 files changed
+24 -5

No files matched your search

@@ -46,5 +46,21 @@ it("does not reset the probe budget when readiness alternates", async () => {
.then(() => "unexpected-ready", error => String(error));
await vi.advanceTimersByTimeAsync(122_000);
expect(await result).toContain("native_runner_warm_attachment_not_quiescent");
expect(calls).toBeLessThan(250);
expect(calls).toBeLessThan(350);
});
it("confirms readiness near the deadline after one unsettled observation", async () => {
vi.useFakeTimers();
vi.setSystemTime(0);
let recoveredProbes = 0;
const result = waitForWarmAttachmentReadiness({
graceMs: 5_000,
waitForConnection: async () => {},
snapshot: async () => ({
warmAttachReady: Date.now() >= 4_400 && ++recoveredProbes !== 2,
warmAttachBlockers: [],
}),
}).then(() => "ready", error => String(error));
await vi.advanceTimersByTimeAsync(5_000);
expect(await result).toBe("ready");
});
@@ -8,13 +8,17 @@ export async function waitForWarmAttachmentReadiness(input: {
const deadline = Date.now() + input.graceMs;
let consecutiveReadyProbes = 0;
let lastBlockers: unknown = null;
let blockedDelayMs = 25;
let probes = 0;
// Each probe is a durable command. A 25 ms loop over the remote 120 second
// reconnect budget can exhaust its 500-command journal before that budget.
const maxBlockedDelayMs = Math.max(1_000, Math.ceil(input.graceMs / 100));
// Leave room for both ready-confirmation probes and ordinary commands. The
// interval is proportional to the deadline, so a short local deadline never
// inherits a one-second delay after a transient readiness regression.
const blockedDelayMs = Math.max(25, Math.ceil(input.graceMs / 160));
while (Date.now() < deadline) {
await input.waitForConnection(deadline);
const snapshot = await input.snapshot(deadline);
probes += 1;
if (snapshot.warmAttachReady !== true && JSON.stringify(snapshot.warmAttachBlockers) !== JSON.stringify(lastBlockers)) {
input.onBlocked?.(snapshot.warmAttachBlockers);
}
@@ -25,8 +29,7 @@ export async function waitForWarmAttachmentReadiness(input: {
} else {
consecutiveReadyProbes = 0;
}
const delayMs = snapshot.warmAttachReady === true ? 25 : blockedDelayMs;
if (snapshot.warmAttachReady !== true) blockedDelayMs = Math.min(blockedDelayMs * 2, maxBlockedDelayMs);
const delayMs = snapshot.warmAttachReady === true || probes < 8 ? 25 : blockedDelayMs;
await new Promise<void>(resolve => setTimeout(resolve, Math.min(delayMs, Math.max(0, deadline - Date.now()))));
}
throw new Error(`native_runner_warm_attachment_not_quiescent: ${JSON.stringify(lastBlockers)}`);