Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 94 additions & 18 deletions .github/actions/test-system-io-dispatch-run/dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24540,6 +24540,16 @@ function getOctokit(token, options, ...additionalPlugins) {

// src/auth.ts
var TOKEN_REFRESH_AGE_MS = 5 * 60 * 1e3;
var TRANSIENT_HTTP_STATUS = /* @__PURE__ */ new Set([408, 429, 502, 503, 504]);
var JSON_REQUEST_TIMEOUT_MS = 3e4;
var UPLOAD_REQUEST_TIMEOUT_MS = 12e4;
var MAX_RETRY_AFTER_MS = 3e4;
function isTransientHTTPStatus(status) {
return TRANSIENT_HTTP_STATUS.has(status);
}
function timeoutSignal(ms) {
return AbortSignal.timeout(ms);
}
var cachedToken = null;
var cachedTokenMintedAt = 0;
function invalidateToken() {
Expand All @@ -24560,22 +24570,50 @@ async function getBearer(audience) {
function sleep(ms) {
return new Promise((r) => setTimeout(r, ms));
}
function parseRetryAfterMs(res) {
const raw = res.headers.get("retry-after");
if (!raw) {
return 0;
}
const asSeconds = Number(raw);
if (Number.isFinite(asSeconds) && asSeconds >= 0) {
return Math.min(asSeconds * 1e3, MAX_RETRY_AFTER_MS);
}
const asDate = Date.parse(raw);
if (!Number.isNaN(asDate)) {
return Math.min(MAX_RETRY_AFTER_MS, Math.max(0, asDate - Date.now()));
}
return 0;
}
function isRetryableFetchError(err) {
const e = err;
const code = e?.cause?.code ?? e?.code;
return e?.name === "TypeError" || e?.name === "TimeoutError" || e?.name === "AbortError" || code === "UND_ERR_SOCKET" || code === "UND_ERR_HEADERS_TIMEOUT" || code === "UND_ERR_BODY_TIMEOUT" || code === "ECONNRESET" || code === "ETIMEDOUT" || code === "EAI_AGAIN" || code === "ENOTFOUND";
}
async function fetchWithRetry(makeRequest, attempts = 4) {
let lastErr;
let lastRes;
for (let i = 0; i < attempts; i++) {
try {
return await makeRequest();
const res = await makeRequest();
if (!TRANSIENT_HTTP_STATUS.has(res.status) || i === attempts - 1) {
return res;
}
lastRes = res;
const backoffMs = 500 * 2 ** i;
const delayMs = Math.max(backoffMs, parseRetryAfterMs(res));
await res.text().catch(() => void 0);
info(`HTTP ${res.status} from upstream; retrying in ${delayMs}ms`);
await sleep(delayMs);
} catch (err) {
lastErr = err;
const e = err;
const code = e?.cause?.code ?? e?.code;
const retryable = e?.name === "TypeError" || code === "UND_ERR_SOCKET" || code === "ECONNRESET" || code === "ETIMEDOUT" || code === "EAI_AGAIN" || code === "ENOTFOUND";
if (!retryable || i === attempts - 1) throw err;
if (!isRetryableFetchError(err) || i === attempts - 1) throw err;
const delayMs = 500 * 2 ** i;
info(`fetch transient failure (${code ?? e.name}); retrying in ${delayMs}ms`);
info(`fetch transient failure; retrying in ${delayMs}ms`);
await sleep(delayMs);
}
}
if (lastRes) return lastRes;
throw lastErr;
}
async function fetchWithAuthRetry(makeRequest) {
Expand All @@ -24587,6 +24625,42 @@ async function fetchWithAuthRetry(makeRequest) {
}
return res;
}
async function requestTextWithRetry(makeRequest, attempts = 4) {
let lastErr;
let lastRes;
for (let i = 0; i < attempts; i++) {
try {
const res = await makeRequest();
if (TRANSIENT_HTTP_STATUS.has(res.status) && i < attempts - 1) {
lastRes = { status: res.status, text: "" };
const delayMs = Math.max(500 * 2 ** i, parseRetryAfterMs(res));
await res.text().catch(() => void 0);
info(`HTTP ${res.status} from upstream; retrying in ${delayMs}ms`);
await sleep(delayMs);
continue;
}
const text = await res.text();
return { status: res.status, text };
} catch (err) {
lastErr = err;
if (!isRetryableFetchError(err) || i === attempts - 1) throw err;
const delayMs = 500 * 2 ** i;
info(`fetch transient failure; retrying in ${delayMs}ms`);
await sleep(delayMs);
}
}
if (lastRes) return lastRes;
throw lastErr;
}
async function fetchTextWithAuthRetry(makeRequest) {
let res = await requestTextWithRetry(makeRequest);
if (res.status === 401) {
info("401 \u2014 invalidating cached OIDC token and retrying once");
invalidateToken();
res = await requestTextWithRetry(makeRequest);
}
return res;
}

// src/playwright.ts
var fs2 = __toESM(require("fs"));
Expand Down Expand Up @@ -24953,7 +25027,8 @@ async function uploadMultipart(cfg, urlPath, parts, defaultType) {
return fetch(`${cfg.baseURL}${urlPath}`, {
method: "POST",
headers: { Authorization: `Bearer ${bearer}` },
body: form
body: form,
signal: timeoutSignal(UPLOAD_REQUEST_TIMEOUT_MS)
});
});
if (res.status !== 200) {
Expand Down Expand Up @@ -25005,23 +25080,23 @@ function identityFields(c) {
return body;
}
async function postJSON(cfg, urlPath, body) {
const res = await fetchWithAuthRetry(async () => {
const { status, text } = await fetchTextWithAuthRetry(async () => {
const bearer = await getBearer(cfg.audience);
return fetch(`${cfg.baseURL}${urlPath}`, {
method: "POST",
headers: { "Content-Type": "application/json", Authorization: `Bearer ${bearer}` },
body: JSON.stringify(body)
body: JSON.stringify(body),
signal: timeoutSignal(JSON_REQUEST_TIMEOUT_MS)
});
});
const text = await res.text();
let parsed = null;
if (text.length) {
try {
parsed = JSON.parse(text);
} catch {
}
}
return { status: res.status, body: parsed };
return { status, body: parsed };
}

// src/main.ts
Expand Down Expand Up @@ -25239,19 +25314,19 @@ async function resolveJobId(token, ghJobName) {
async function postJSON2(cfg, urlPath, body) {
const delays = [500, 1500, 4e3];
for (let attempt = 0; attempt <= delays.length; attempt++) {
const res = await fetchWithAuthRetry(async () => {
const { status, text } = await fetchTextWithAuthRetry(async () => {
const bearer = await getBearer(cfg.audience);
return fetch(`${cfg.baseURL}${urlPath}`, {
method: "POST",
headers: { "Content-Type": "application/json", Authorization: `Bearer ${bearer}` },
body: JSON.stringify(body)
body: JSON.stringify(body),
signal: timeoutSignal(JSON_REQUEST_TIMEOUT_MS)
});
});
const text = await res.text();
if (res.status >= 500 && res.status < 600 && attempt < delays.length) {
if (status >= 500 && status < 600 && !isTransientHTTPStatus(status) && attempt < delays.length) {
const ms = delays[attempt] + Math.floor(Math.random() * 250);
warning(
`${urlPath}: HTTP ${res.status} (attempt ${attempt + 1}/${delays.length + 1}); retrying in ${ms}ms. body=${text.slice(0, 200)}`
`${urlPath}: HTTP ${status} (attempt ${attempt + 1}/${delays.length + 1}); retrying in ${ms}ms. body=${text.slice(0, 200)}`
);
await sleep2(ms);
continue;
Expand All @@ -25263,7 +25338,7 @@ async function postJSON2(cfg, urlPath, body) {
} catch {
}
}
return { status: res.status, body: parsed };
return { status, body: parsed };
}
return { status: 0, body: null };
}
Expand Down Expand Up @@ -25316,7 +25391,8 @@ async function uploadOrchScreenshot(cfg, specPath, absPath) {
return fetch(`${cfg.baseURL}/api/v1/orchestration/screenshots`, {
method: "POST",
headers: { Authorization: `Bearer ${bearer}` },
body: form
body: form,
signal: timeoutSignal(UPLOAD_REQUEST_TIMEOUT_MS)
});
});
} catch (err) {
Expand Down
Loading