From a37dd0210bdad34f67ab6071d68a3111de9b1b08 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Fri, 19 Jun 2026 07:49:01 +0200 Subject: [PATCH] fix(e2e): bound upgrade survivor probe retries --- .../lib/upgrade-survivor/probe-gateway.mjs | 14 ++++++-- .../upgrade-survivor-probe-gateway.test.ts | 33 +++++++++++++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/scripts/e2e/lib/upgrade-survivor/probe-gateway.mjs b/scripts/e2e/lib/upgrade-survivor/probe-gateway.mjs index 875d990c2915..b708fdf35d01 100644 --- a/scripts/e2e/lib/upgrade-survivor/probe-gateway.mjs +++ b/scripts/e2e/lib/upgrade-survivor/probe-gateway.mjs @@ -107,7 +107,7 @@ function matchesDegradedReadyExpectation(body) { async function fetchProbeText() { const elapsedMs = Date.now() - startedAt; - const remainingMs = Math.max(1, timeoutMs - elapsedMs); + const remainingMs = timeoutMs - elapsedMs; const controller = new AbortController(); const attemptDeadlineMs = Math.min(attemptTimeoutMs, remainingMs); let timer; @@ -138,7 +138,7 @@ const startedAt = Date.now(); let lastError; let lastResult; -while (Date.now() - startedAt <= timeoutMs) { +while (Date.now() - startedAt < timeoutMs) { try { const { response, text } = await fetchProbeText(); let body; @@ -171,9 +171,17 @@ while (Date.now() - startedAt <= timeoutMs) { } catch (error) { lastError = error instanceof Error ? error.message : String(error); } + const remainingDelayMs = timeoutMs - (Date.now() - startedAt); + if (remainingDelayMs <= 0) { + break; + } + const delayMs = Math.min(500, remainingDelayMs); await new Promise((resolve) => { - setTimeout(resolve, 500); + setTimeout(resolve, delayMs); }); + if (delayMs === remainingDelayMs) { + break; + } } const suffix = lastResult ? ` (last HTTP ${lastResult.status}: ${lastResult.text})` : ""; diff --git a/test/scripts/upgrade-survivor-probe-gateway.test.ts b/test/scripts/upgrade-survivor-probe-gateway.test.ts index 67a82e5ae288..d10bc75f74b8 100644 --- a/test/scripts/upgrade-survivor-probe-gateway.test.ts +++ b/test/scripts/upgrade-survivor-probe-gateway.test.ts @@ -192,6 +192,39 @@ describe("scripts/e2e/lib/upgrade-survivor/probe-gateway.mjs", () => { } }); + it("keeps failed probe retries inside the total timeout", async () => { + const server = createHttpServer((_request, response) => { + response.writeHead(503, { "content-type": "application/json" }); + response.end(JSON.stringify({ ready: false, failing: ["gateway"] })); + }); + const baseUrl = await listen(server); + const out = path.join(makeTempDir(), "ready-timeout.json"); + const startedAt = Date.now(); + try { + const result = await runProbe([ + "--base-url", + baseUrl, + "--path", + "/readyz", + "--expect", + "ready", + "--out", + out, + "--timeout-ms", + "50", + "--attempt-timeout-ms", + "25", + ]); + + expect(result.status).not.toBe(0); + expect(Date.now() - startedAt).toBeLessThan(300); + expect(result.stderr).toContain("probe did not satisfy ready within 50ms"); + expect(fs.existsSync(out)).toBe(false); + } finally { + server.close(); + } + }); + it("allows degraded ready responses only when degraded readiness is explicit", async () => { const server = createHttpServer((_request, response) => { response.writeHead(503, { "content-type": "application/json" });