fix: honor compaction cancellation and replay identity
This commit is contained in:
@@ -5291,6 +5291,10 @@ impl<C: LlmClient + 'static, St: Store> Worker<C, St> {
|
||||
info!(new_segment_id = %new_segment_id, "Manual compaction succeeded");
|
||||
Ok(ManualCompactResult::Compacted { new_segment_id })
|
||||
}
|
||||
Err(WorkerError::CompactCancelled) => {
|
||||
info!("Manual compaction was cancelled");
|
||||
Err(WorkerError::CompactCancelled)
|
||||
}
|
||||
Err(e) => {
|
||||
warn!(error = %e, "Manual compaction failed");
|
||||
self.alert(
|
||||
|
||||
@@ -1736,7 +1736,11 @@ async fn manual_compact_cancel_clears_progress_before_returning_idle() {
|
||||
Event::CompactionProgress { compaction: None } => {
|
||||
saw_interrupted = true;
|
||||
}
|
||||
Event::Error { .. } => saw_cancel_error = true,
|
||||
Event::Error { .. }
|
||||
| Event::Alert(protocol::Alert {
|
||||
level: protocol::AlertLevel::Error,
|
||||
..
|
||||
}) => saw_cancel_error = true,
|
||||
Event::WorkerState { snapshot }
|
||||
if snapshot.catalog_status() == protocol::WorkerStatus::Idle =>
|
||||
{
|
||||
|
||||
@@ -376,6 +376,35 @@ Deno.test("durable compaction failure reconciles live alert and error in both vi
|
||||
assertEquals(merged.find((line) => line.kind === "error")?.entryId, "failed-entry");
|
||||
});
|
||||
|
||||
Deno.test("reapplying one committed run_error entry is idempotent in both views", () => {
|
||||
const committed = (eventId: string): ConsoleEventInput => ({
|
||||
eventId,
|
||||
event: {
|
||||
event: "session_entry_committed",
|
||||
data: {
|
||||
entry: {
|
||||
entry_id: "same-run-error",
|
||||
timestamp: 10,
|
||||
provenance: "legacy_unknown",
|
||||
kind: "run_error",
|
||||
message: "mid-run compaction failed: summary unavailable",
|
||||
failure: "compaction",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const projection = projectConsole([
|
||||
committed("live-delivery"),
|
||||
committed("snapshot-replay"),
|
||||
]);
|
||||
const errors = projection.lines.filter((line) => line.kind === "error");
|
||||
assertEquals(errors.length, 1);
|
||||
assertEquals(errors[0].entryId, "same-run-error");
|
||||
assertEquals(projectConsoleLines(projection.lines, "normal").length, 1);
|
||||
assertEquals(projectConsoleLines(projection.lines, "overview").length, 1);
|
||||
});
|
||||
|
||||
Deno.test("snapshot restores compaction terminal without reviving transition progress", () => {
|
||||
const projection = projectConsole([{
|
||||
eventId: "snapshot",
|
||||
|
||||
@@ -1287,15 +1287,19 @@ function hasDurableRunFailure(
|
||||
function appendDurableRunFailure(
|
||||
projection: ConsoleProjection,
|
||||
eventId: string,
|
||||
entryId: string | undefined,
|
||||
message: string,
|
||||
failure: string | undefined,
|
||||
): void {
|
||||
if (
|
||||
entryId && projection.lines.some((line) => line.entryId === entryId)
|
||||
) return;
|
||||
projection.lines = projection.lines.filter((line) => {
|
||||
if (isDurableRunFailure(line)) return true;
|
||||
return !(line.kind === "error" && runFailureMessagesMatch(line.body, message));
|
||||
});
|
||||
projection.lines.push(
|
||||
line(
|
||||
projection.lines.push({
|
||||
...line(
|
||||
eventId,
|
||||
"error",
|
||||
failure === "compaction" ? "Compaction failed" : "Run error",
|
||||
@@ -1304,7 +1308,8 @@ function appendDurableRunFailure(
|
||||
false,
|
||||
true,
|
||||
),
|
||||
);
|
||||
entryId,
|
||||
});
|
||||
}
|
||||
|
||||
function appendAlertLine(
|
||||
@@ -2198,6 +2203,7 @@ function applySessionEntry(
|
||||
appendDurableRunFailure(
|
||||
projection,
|
||||
eventId,
|
||||
stringField(value, "entry_id"),
|
||||
stringField(value, "message") ?? "Worker run failed.",
|
||||
stringField(value, "failure"),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user