mirror of
https://github.com/morluto/rea.git
synced 2026-11-10 00:36:35 +00:00
fix(ci): record every agentenv run and retry only public ECR rate refusals
The receipt's agent_env_run is recorded in a finally block, so a failed receipt says how the last run ended, how many runs there were and which public ECR refusal ended it: public_ecr_quota is data_limit for the per-IP data-transfer cap and rate for a request-rate refusal. Only a rate refusal earns the one retry; the data cap fails the lane at once, since a pause on the same runner cannot lift it. Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5ebf777bec
commit
171da5591e
2 files changed
+65
-28
No files matched your search
@@ -16,9 +16,12 @@ import { createVerifierRun, completeVerifierRun } from "./lib/verifier-run.mjs";
|
||||
|
||||
const AGENTENV_PIN = "agentenv-framework 0.9.1334";
|
||||
// The framework builds its infra images from public ECR, whose anonymous pull quota hosted
|
||||
// runners share; that one external refusal earns one retry, anything else fails at once.
|
||||
// runners share; a rate refusal earns one retry, anything else fails at once.
|
||||
const PUBLIC_ECR_QUOTA =
|
||||
/public\.ecr\.aws[\s\S]{0,400}?(?:429 Too Many Requests|toomanyrequests)/u;
|
||||
// The anonymous data-transfer cap is counted per source IP, so a pause on the same runner
|
||||
// cannot lift it; the receipt names it instead of retrying.
|
||||
const PUBLIC_ECR_DATA_LIMIT = /toomanyrequests: Data limit exceeded/u;
|
||||
const QUOTA_RETRY_PAUSE_MS = 90_000;
|
||||
// Both bundle attempts share this budget inside the 30-minute job; a retry needs real time left.
|
||||
const RUN_BUDGET_MS = 22 * 60_000;
|
||||
@@ -155,18 +158,36 @@ try {
|
||||
// with this receipt rather than the runner's kill.
|
||||
const started = Date.now();
|
||||
const deadline = started + RUN_BUDGET_MS;
|
||||
const runBundle = (timeoutMs) =>
|
||||
runOwnedCommand(
|
||||
{
|
||||
command: agentEnv,
|
||||
arguments: ["run", bundle, "--sandbox", "local"],
|
||||
cwd: runtime.path,
|
||||
runId: `rea-agentenv-run-${randomUUID()}`,
|
||||
hostEnvironment: environment,
|
||||
},
|
||||
{ timeoutMs, diagnosticBytes: 4 * 1024 * 1024 },
|
||||
);
|
||||
let attempts = 1;
|
||||
let attempts = 0;
|
||||
const runBundle = async (timeoutMs) => {
|
||||
attempts += 1;
|
||||
let outcome;
|
||||
try {
|
||||
outcome = await runOwnedCommand(
|
||||
{
|
||||
command: agentEnv,
|
||||
arguments: ["run", bundle, "--sandbox", "local"],
|
||||
cwd: runtime.path,
|
||||
runId: `rea-agentenv-run-${randomUUID()}`,
|
||||
hostEnvironment: environment,
|
||||
},
|
||||
{ timeoutMs, diagnosticBytes: 4 * 1024 * 1024 },
|
||||
);
|
||||
return outcome;
|
||||
} catch (cause) {
|
||||
outcome =
|
||||
cause instanceof OwnedCommandFailure ? cause.snapshot : undefined;
|
||||
throw cause;
|
||||
} finally {
|
||||
// Recorded before the outcome is judged, so a failed receipt still says how the last
|
||||
// run ended, how many runs there were and whether the registry quota refused it.
|
||||
receipt.agent_env_run = runRecord(
|
||||
outcome,
|
||||
Date.now() - started,
|
||||
attempts,
|
||||
);
|
||||
}
|
||||
};
|
||||
let snapshot;
|
||||
try {
|
||||
snapshot = await runBundle(
|
||||
@@ -174,24 +195,13 @@ try {
|
||||
);
|
||||
} catch (cause) {
|
||||
if (
|
||||
!(cause instanceof OwnedCommandFailure) ||
|
||||
!PUBLIC_ECR_QUOTA.test(cause.snapshot?.stderr.text ?? "") ||
|
||||
receipt.agent_env_run?.public_ecr_quota !== "rate" ||
|
||||
deadline - Date.now() - QUOTA_RETRY_PAUSE_MS < MIN_RETRY_MS
|
||||
)
|
||||
throw cause;
|
||||
attempts = 2;
|
||||
await pause(QUOTA_RETRY_PAUSE_MS);
|
||||
snapshot = await runBundle(deadline - Date.now());
|
||||
}
|
||||
receipt.agent_env_run = {
|
||||
exit_code: snapshot.exitCode,
|
||||
seconds: Math.round((Date.now() - started) / 1000),
|
||||
attempts,
|
||||
...(attempts > 1
|
||||
? { retried_for: "public ECR anonymous pull quota (429)" }
|
||||
: {}),
|
||||
stdout_tail: snapshot.stdout.text.trim().split("\n").slice(-6),
|
||||
};
|
||||
assert.equal(snapshot.exitCode, 0);
|
||||
assert.match(snapshot.stdout.text, /tasks\/smoke\.json v\d+: passed/u);
|
||||
assert.match(
|
||||
@@ -281,6 +291,29 @@ async function cli(...args) {
|
||||
return JSON.parse(stdout);
|
||||
}
|
||||
|
||||
// The receipt's view of one `agent-env run`, passed or failed; `outcome` is absent when the
|
||||
// command failed before producing a snapshot.
|
||||
function runRecord(outcome, elapsedMs, attempts) {
|
||||
const quota = publicEcrQuota(outcome?.stderr.text ?? "");
|
||||
return {
|
||||
exit_code: outcome?.exitCode ?? null,
|
||||
...(outcome?.signal ? { signal: outcome.signal } : {}),
|
||||
seconds: Math.round(elapsedMs / 1000),
|
||||
attempts,
|
||||
...(attempts > 1
|
||||
? { retried_for: "public ECR anonymous pull rate limit (429)" }
|
||||
: {}),
|
||||
...(quota === undefined ? {} : { public_ecr_quota: quota }),
|
||||
stdout_tail: (outcome?.stdout.text ?? "").trim().split("\n").slice(-6),
|
||||
};
|
||||
}
|
||||
|
||||
// Which public ECR refusal ended a run: the per-IP data cap or a request-rate refusal.
|
||||
function publicEcrQuota(stderr) {
|
||||
if (!PUBLIC_ECR_QUOTA.test(stderr)) return undefined;
|
||||
return PUBLIC_ECR_DATA_LIMIT.test(stderr) ? "data_limit" : "rate";
|
||||
}
|
||||
|
||||
// npm 11 prints `npm pack --json` as a one-element array; npm 12 keys the same record by package name.
|
||||
function packedFilename(report) {
|
||||
const record = Array.isArray(report) ? report[0] : Object.values(report)[0];
|
||||
|
||||
Reference in new issue
Block a user