fix: reconcile runner job observations

This commit is contained in:
lyon
2026-06-20 15:45:43 +08:00
parent 2f96697bbb
commit f2f04ac2cf
7 changed files with 459 additions and 4 deletions
+37 -2
View File
@@ -20,7 +20,7 @@ export function runDiagnosis(input: RunDiagnosisInput): JsonRecord {
const staleClaimed = input.run.status === "claimed" && booleanValue(lease.leaseExpired) === true;
const terminalCommandOpenRun = input.run.status === "claimed" && input.terminalStatus !== null;
const runnerJob = input.latestJob ? runnerJobReference(input.latestJob, input.events) : null;
const runnerLost = staleClaimed && (runnerJob === null || runnerJob.phase === "created" || runnerJob.phase === "recorded");
const runnerLost = staleClaimed && (runnerJob === null || runnerJobPhaseIndicatesLost(runnerJob.phase));
const session = sessionReference(input.run);
const providerEvidence = stringValue(input.terminalClassification?.providerEvidence) ?? "not-applicable";
const providerInterruption = stringValue(input.terminalClassification?.providerInterruption) ?? "not-established";
@@ -69,14 +69,17 @@ export function runnerJobDiagnosis(job: RunnerJobRecord, events: RunEvent[] = []
const observation = runnerJobObservation(job, events);
const phase = stringValue(observation.phase) ?? "unknown";
const notStarted = phase === "created" || phase === "recorded";
const runnerLostSuspected = notStarted || runnerJobPhaseIndicatesLost(phase);
return {
category: stringValue(observation.category) ?? (notStarted ? "runner-job-created" : phase.startsWith("terminal:") ? "runner-job-terminal" : "runner-job-observed"),
runnerLostSuspected: notStarted,
runnerLostSuspected,
phase,
evidenceLevel: stringValue(observation.evidenceLevel) ?? (notStarted ? "medium" : "high"),
lastObservedSeq: numberValue(observation.lastObservedSeq),
lastObservedAt: stringValue(observation.lastObservedAt),
lastObservedKind: stringValue(observation.lastObservedKind),
terminalReportState: stringValue(observation.terminalReportState),
runReportState: stringValue(observation.runReportState),
runId: job.runId,
commandId: job.commandId,
runnerJobId: job.id,
@@ -131,6 +134,26 @@ export function runnerJobObservation(job: RunnerJobRecord, events: RunEvent[] =
};
}
const reconcilerObservation = recordAt(job.result, "observation");
const reconcilerPhase = stringValue(reconcilerObservation?.observedRunnerPhase) ?? stringValue(reconcilerObservation?.phase);
if (reconcilerObservation && reconcilerPhase) {
return {
phase: reconcilerPhase,
category: stringValue(reconcilerObservation.category) ?? "runner-job-observed",
terminalStatus: stringValue(reconcilerObservation.terminalStatus),
failureKind: stringValue(reconcilerObservation.failureKind),
startedAt: stringValue(recordAt(reconcilerObservation, "k8s")?.startTime),
finishedAt: stringValue(recordAt(reconcilerObservation, "k8s")?.completionTime),
lastObservedSeq: null,
lastObservedAt: stringValue(reconcilerObservation.lastK8sObservedAt) ?? stringValue(reconcilerObservation.lastObservedAt),
lastObservedKind: stringValue(reconcilerObservation.lastObservedKind) ?? `manager-reconciler:${reconcilerPhase}`,
terminalReportState: stringValue(reconcilerObservation.terminalReportState),
runReportState: stringValue(reconcilerObservation.runReportState),
evidenceLevel: stringValue(reconcilerObservation.evidenceLevel) ?? "high",
valuesPrinted: false,
};
}
const created = recordAt(job.result, "kubernetes")?.created === true;
return {
phase: created ? "created" : "recorded",
@@ -212,11 +235,23 @@ function runnerJobReference(job: RunnerJobRecord, events: RunEvent[]): JsonRecor
lastObservedSeq: numberValue(observation.lastObservedSeq),
lastObservedAt: stringValue(observation.lastObservedAt),
lastObservedKind: stringValue(observation.lastObservedKind),
terminalReportState: stringValue(observation.terminalReportState),
runReportState: stringValue(observation.runReportState),
logPath: stringValue(recordAt(job.result, "runner")?.logPath),
valuesPrinted: false,
};
}
function runnerJobPhaseIndicatesLost(value: JsonValue | undefined): boolean {
const phase = stringValue(value);
return phase === "created"
|| phase === "recorded"
|| phase === "k8s:failed"
|| phase === "k8s:missing"
|| phase === "k8s:succeeded"
|| phase === "k8s:observe-failed";
}
function sessionReference(run: RunRecord): JsonRecord {
if (!run.sessionRef) return { sessionId: null, sessionRefNull: true, sessionPath: null, valuesPrinted: false };
return { sessionId: run.sessionRef.sessionId, sessionRefNull: false, sessionPath: `/api/v1/sessions/${run.sessionRef.sessionId}`, valuesPrinted: false };