fix: reduce runner command poll latency
This commit is contained in:
@@ -174,6 +174,7 @@ function runnerEnv(options: RunnerJobRenderOptions, context: { namespace: string
|
|||||||
{ name: "AGENTRUN_K8S_JOB_NAME", value: context.jobName },
|
{ name: "AGENTRUN_K8S_JOB_NAME", value: context.jobName },
|
||||||
{ name: "AGENTRUN_LOG_PATH", value: "/tmp/agentrun-runner.jsonl" },
|
{ name: "AGENTRUN_LOG_PATH", value: "/tmp/agentrun-runner.jsonl" },
|
||||||
{ name: "AGENTRUN_RUNNER_IDLE_TIMEOUT_MS", value: "600000" },
|
{ name: "AGENTRUN_RUNNER_IDLE_TIMEOUT_MS", value: "600000" },
|
||||||
|
{ name: "AGENTRUN_RUNNER_POLL_INTERVAL_MS", value: "250" },
|
||||||
{ name: "HOME", value: "/home/agentrun" },
|
{ name: "HOME", value: "/home/agentrun" },
|
||||||
{ name: "CODEX_HOME", value: codexHome },
|
{ name: "CODEX_HOME", value: codexHome },
|
||||||
...(selectedSecret ? [{ name: "AGENTRUN_CODEX_SECRET_HOME", value: selectedSecret.projectionMountPath }] : []),
|
...(selectedSecret ? [{ name: "AGENTRUN_CODEX_SECRET_HOME", value: selectedSecret.projectionMountPath }] : []),
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ export async function runOnce(options: RunnerOnceOptions): Promise<JsonRecord> {
|
|||||||
|
|
||||||
const stopHeartbeat = startHeartbeat(api, options.runId, runner.id, leaseMs);
|
const stopHeartbeat = startHeartbeat(api, options.runId, runner.id, leaseMs);
|
||||||
const idleTimeoutMs = options.idleTimeoutMs ?? 120_000;
|
const idleTimeoutMs = options.idleTimeoutMs ?? 120_000;
|
||||||
const pollIntervalMs = options.pollIntervalMs ?? 2_000;
|
const pollIntervalMs = normalizePollIntervalMs(options.pollIntervalMs);
|
||||||
const commandResults: CommandExecutionResult[] = [];
|
const commandResults: CommandExecutionResult[] = [];
|
||||||
let workspacePath: string | undefined;
|
let workspacePath: string | undefined;
|
||||||
let materializationAttempted = false;
|
let materializationAttempted = false;
|
||||||
@@ -231,3 +231,8 @@ function noPendingResult(runner: RunnerRecord, claimed: RunRecord, commandResult
|
|||||||
function sleep(ms: number): Promise<void> {
|
function sleep(ms: number): Promise<void> {
|
||||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizePollIntervalMs(value: number | undefined): number {
|
||||||
|
if (!Number.isFinite(value ?? NaN)) return 250;
|
||||||
|
return Math.max(50, Math.min(2_000, Math.floor(value!)));
|
||||||
|
}
|
||||||
|
|||||||
@@ -156,6 +156,7 @@ function assertRunnerJobUsesWritableCodexHome(manifest: JsonRecord, expectedCode
|
|||||||
assert.equal(value("CODEX_HOME"), expectedCodexHome);
|
assert.equal(value("CODEX_HOME"), expectedCodexHome);
|
||||||
assert.equal(value("AGENTRUN_CODEX_SECRET_HOME"), projectionPath);
|
assert.equal(value("AGENTRUN_CODEX_SECRET_HOME"), projectionPath);
|
||||||
assert.equal(value("AGENTRUN_RUNNER_IDLE_TIMEOUT_MS"), "600000");
|
assert.equal(value("AGENTRUN_RUNNER_IDLE_TIMEOUT_MS"), "600000");
|
||||||
|
assert.equal(value("AGENTRUN_RUNNER_POLL_INTERVAL_MS"), "250");
|
||||||
assert.equal(value("AGENTRUN_RUNNER_ONE_SHOT"), undefined);
|
assert.equal(value("AGENTRUN_RUNNER_ONE_SHOT"), undefined);
|
||||||
assert.notEqual(value("CODEX_HOME"), value("AGENTRUN_CODEX_SECRET_HOME"));
|
assert.notEqual(value("CODEX_HOME"), value("AGENTRUN_CODEX_SECRET_HOME"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,6 +100,11 @@ console.log(JSON.stringify({ apiVersion: manifest.apiVersion, kind: manifest.kin
|
|||||||
assert.equal(starts.length, 1, "same-run multiturn runner must keep one codex app-server process alive instead of restarting per command");
|
assert.equal(starts.length, 1, "same-run multiturn runner must keep one codex app-server process alive instead of restarting per command");
|
||||||
const multiEventsResponse = await client.get(`/api/v1/runs/${multiTurn.runId}/events?afterSeq=0&limit=200`) as { items?: Array<{ type?: string; payload?: JsonRecord }> };
|
const multiEventsResponse = await client.get(`/api/v1/runs/${multiTurn.runId}/events?afterSeq=0&limit=200`) as { items?: Array<{ type?: string; payload?: JsonRecord }> };
|
||||||
const multiEvents = multiEventsResponse.items ?? [];
|
const multiEvents = multiEventsResponse.items ?? [];
|
||||||
|
const secondCommandCreatedAt = await commandCreatedAt(client, multiTurn.runId, secondCommand.id);
|
||||||
|
const reuseEvent = multiEvents.find((event) => event.type === "backend_status" && event.payload?.phase === "codex-app-server:reused" && event.payload?.commandId === secondCommand.id);
|
||||||
|
assert.ok(secondCommandCreatedAt, "second command must expose createdAt for pickup latency assertion");
|
||||||
|
assert.ok(reuseEvent?.payload, "second command must produce codex-app-server:reused event");
|
||||||
|
assert.ok(Date.parse(String((reuseEvent as JsonRecord).createdAt ?? "")) - Date.parse(secondCommandCreatedAt) < 1_000, "same-run runner should pick up the next command without multi-second polling latency");
|
||||||
assert.equal(multiEvents.filter((event) => event.type === "backend_status" && event.payload?.phase === "codex-app-server-starting").length, 1);
|
assert.equal(multiEvents.filter((event) => event.type === "backend_status" && event.payload?.phase === "codex-app-server-starting").length, 1);
|
||||||
assert.equal(multiEvents.filter((event) => event.type === "backend_status" && event.payload?.phase === "codex-app-server:reused").length, 1);
|
assert.equal(multiEvents.filter((event) => event.type === "backend_status" && event.payload?.phase === "codex-app-server:reused").length, 1);
|
||||||
assert.equal(multiEvents.filter((event) => event.type === "backend_status" && event.payload?.phase === "resource-bundle-materialized").length, 1);
|
assert.equal(multiEvents.filter((event) => event.type === "backend_status" && event.payload?.phase === "resource-bundle-materialized").length, 1);
|
||||||
@@ -164,6 +169,11 @@ async function waitForCommandState(client: ManagerClient, runId: string, command
|
|||||||
throw new Error(`command ${commandId} did not reach ${state}`);
|
throw new Error(`command ${commandId} did not reach ${state}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function commandCreatedAt(client: ManagerClient, runId: string, commandId: string): Promise<string> {
|
||||||
|
const command = await client.get(`/api/v1/runs/${runId}/commands/${commandId}`) as { createdAt?: string };
|
||||||
|
return command.createdAt ?? "";
|
||||||
|
}
|
||||||
|
|
||||||
async function readTextIfExists(filePath: string): Promise<string> {
|
async function readTextIfExists(filePath: string): Promise<string> {
|
||||||
try {
|
try {
|
||||||
return await readFile(filePath, "utf8");
|
return await readFile(filePath, "utf8");
|
||||||
|
|||||||
Reference in New Issue
Block a user