mirror of https://github.com/openclaw/openclaw.git
fix: harden compaction timeout follow-ups
This commit is contained in:
parent
f77a684131
commit
6a458ef29e
|
|
@ -76,6 +76,20 @@ describe("compactWithSafetyTimeout", () => {
|
||||||
expect(onCancel).toHaveBeenCalledTimes(1);
|
expect(onCancel).toHaveBeenCalledTimes(1);
|
||||||
expect(vi.getTimerCount()).toBe(0);
|
expect(vi.getTimerCount()).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("ignores onCancel errors and still rejects with the timeout", async () => {
|
||||||
|
vi.useFakeTimers();
|
||||||
|
const compactPromise = compactWithSafetyTimeout(() => new Promise<never>(() => {}), 30, {
|
||||||
|
onCancel: () => {
|
||||||
|
throw new Error("abortCompaction failed");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const timeoutAssertion = expect(compactPromise).rejects.toThrow("Compaction timed out");
|
||||||
|
|
||||||
|
await vi.advanceTimersByTimeAsync(30);
|
||||||
|
await timeoutAssertion;
|
||||||
|
expect(vi.getTimerCount()).toBe(0);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("resolveCompactionTimeoutMs", () => {
|
describe("resolveCompactionTimeoutMs", () => {
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,12 @@ export async function compactWithSafetyTimeout<T>(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
canceled = true;
|
canceled = true;
|
||||||
opts?.onCancel?.();
|
try {
|
||||||
|
opts?.onCancel?.();
|
||||||
|
} catch {
|
||||||
|
// Best-effort cancellation hook. Keep the timeout/abort path intact even
|
||||||
|
// if the underlying compaction cancel operation throws.
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return await withTimeout(
|
return await withTimeout(
|
||||||
|
|
|
||||||
|
|
@ -132,6 +132,7 @@ import { flushPendingToolResultsAfterIdle } from "../wait-for-idle-before-flush.
|
||||||
import { waitForCompactionRetryWithAggregateTimeout } from "./compaction-retry-aggregate-timeout.js";
|
import { waitForCompactionRetryWithAggregateTimeout } from "./compaction-retry-aggregate-timeout.js";
|
||||||
import {
|
import {
|
||||||
resolveRunTimeoutDuringCompaction,
|
resolveRunTimeoutDuringCompaction,
|
||||||
|
resolveRunTimeoutWithCompactionGraceMs,
|
||||||
selectCompactionTimeoutSnapshot,
|
selectCompactionTimeoutSnapshot,
|
||||||
shouldFlagCompactionTimeout,
|
shouldFlagCompactionTimeout,
|
||||||
} from "./compaction-timeout.js";
|
} from "./compaction-timeout.js";
|
||||||
|
|
@ -1708,7 +1709,10 @@ export async function runEmbeddedAttempt(
|
||||||
const sessionLock = await acquireSessionWriteLock({
|
const sessionLock = await acquireSessionWriteLock({
|
||||||
sessionFile: params.sessionFile,
|
sessionFile: params.sessionFile,
|
||||||
maxHoldMs: resolveSessionLockMaxHoldFromTimeout({
|
maxHoldMs: resolveSessionLockMaxHoldFromTimeout({
|
||||||
timeoutMs: params.timeoutMs,
|
timeoutMs: resolveRunTimeoutWithCompactionGraceMs({
|
||||||
|
runTimeoutMs: params.timeoutMs,
|
||||||
|
compactionTimeoutMs: resolveCompactionTimeoutMs(params.config),
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import { describe, expect, it } from "vitest";
|
||||||
import { castAgentMessage } from "../../test-helpers/agent-message-fixtures.js";
|
import { castAgentMessage } from "../../test-helpers/agent-message-fixtures.js";
|
||||||
import {
|
import {
|
||||||
resolveRunTimeoutDuringCompaction,
|
resolveRunTimeoutDuringCompaction,
|
||||||
|
resolveRunTimeoutWithCompactionGraceMs,
|
||||||
selectCompactionTimeoutSnapshot,
|
selectCompactionTimeoutSnapshot,
|
||||||
shouldFlagCompactionTimeout,
|
shouldFlagCompactionTimeout,
|
||||||
} from "./compaction-timeout.js";
|
} from "./compaction-timeout.js";
|
||||||
|
|
@ -62,6 +63,15 @@ describe("compaction-timeout helpers", () => {
|
||||||
).toBe("abort");
|
).toBe("abort");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("adds one compaction grace window to the run timeout budget", () => {
|
||||||
|
expect(
|
||||||
|
resolveRunTimeoutWithCompactionGraceMs({
|
||||||
|
runTimeoutMs: 600_000,
|
||||||
|
compactionTimeoutMs: 900_000,
|
||||||
|
}),
|
||||||
|
).toBe(1_500_000);
|
||||||
|
});
|
||||||
|
|
||||||
it("uses pre-compaction snapshot when compaction timeout occurs", () => {
|
it("uses pre-compaction snapshot when compaction timeout occurs", () => {
|
||||||
const pre = [castAgentMessage({ role: "assistant", content: "pre" })] as const;
|
const pre = [castAgentMessage({ role: "assistant", content: "pre" })] as const;
|
||||||
const current = [castAgentMessage({ role: "assistant", content: "current" })] as const;
|
const current = [castAgentMessage({ role: "assistant", content: "current" })] as const;
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,13 @@ export function resolveRunTimeoutDuringCompaction(params: {
|
||||||
return params.graceAlreadyUsed ? "abort" : "extend";
|
return params.graceAlreadyUsed ? "abort" : "extend";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function resolveRunTimeoutWithCompactionGraceMs(params: {
|
||||||
|
runTimeoutMs: number;
|
||||||
|
compactionTimeoutMs: number;
|
||||||
|
}): number {
|
||||||
|
return params.runTimeoutMs + params.compactionTimeoutMs;
|
||||||
|
}
|
||||||
|
|
||||||
export type SnapshotSelectionParams = {
|
export type SnapshotSelectionParams = {
|
||||||
timedOutDuringCompaction: boolean;
|
timedOutDuringCompaction: boolean;
|
||||||
preCompactionSnapshot: AgentMessage[] | null;
|
preCompactionSnapshot: AgentMessage[] | null;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue