fix(github): preserved aborts during cache refresh
Re-throw ToolAbortError from soft-expired issue and PR synchronous refreshes instead of falling back to stale cached content. Cover the abort path in github-cache tests. Fixes #2684
This commit is contained in:
@@ -22,6 +22,7 @@ import * as os from "node:os";
|
||||
import * as path from "node:path";
|
||||
import { getGithubCacheDbPath, logger } from "@oh-my-pi/pi-utils";
|
||||
import type { Settings } from "../config/settings";
|
||||
import { ToolAbortError } from "./tool-errors";
|
||||
|
||||
// ────────────────────────────────────────────────────────────────────────────
|
||||
// Storage layer
|
||||
@@ -619,6 +620,7 @@ export async function getOrFetchView<T>(options: CacheLookupOptions<T>): Promise
|
||||
storeResult(authKey, options.repo, options.kind, options.number, options.includeComments, fresh, fetchedAt);
|
||||
return { ...fresh, status: "refreshed", fetchedAt };
|
||||
} catch (err) {
|
||||
if (err instanceof ToolAbortError) throw err;
|
||||
logger.debug("github cache: synchronous refresh failed; returning stale view", {
|
||||
err: String(err),
|
||||
repo: options.repo,
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
putCached,
|
||||
resetForTests as resetCacheForTests,
|
||||
} from "@oh-my-pi/pi-coding-agent/tools/github-cache";
|
||||
import { ToolAbortError, throwIfAborted } from "@oh-my-pi/pi-coding-agent/tools/tool-errors";
|
||||
import * as git from "@oh-my-pi/pi-coding-agent/utils/git";
|
||||
|
||||
const TEST_REPO = "owner/example";
|
||||
@@ -372,6 +373,43 @@ describe("getOrFetchView (TTL semantics)", () => {
|
||||
expect(result.rendered).toBe("old");
|
||||
expect(fetchFresh).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
it("propagates aborts during a soft-expired synchronous refresh", async () => {
|
||||
const settings = Settings.isolated({
|
||||
"github.cache.softTtlSec": 60,
|
||||
"github.cache.hardTtlSec": 86400,
|
||||
});
|
||||
const controller = new AbortController();
|
||||
controller.abort();
|
||||
const fetchFresh = vi.fn(async () => {
|
||||
throwIfAborted(controller.signal);
|
||||
return {
|
||||
rendered: "never",
|
||||
sourceUrl: undefined,
|
||||
payload: { number: 53 },
|
||||
};
|
||||
});
|
||||
putCached({
|
||||
repo: TEST_REPO,
|
||||
kind: "issue",
|
||||
number: 53,
|
||||
includeComments: true,
|
||||
payload: { number: 53 },
|
||||
rendered: "stale-after-abort",
|
||||
fetchedAt: Date.now() - 5 * 60_000,
|
||||
});
|
||||
|
||||
await expect(
|
||||
getOrFetchView({
|
||||
repo: TEST_REPO,
|
||||
kind: "issue",
|
||||
number: 53,
|
||||
includeComments: true,
|
||||
fetchFresh,
|
||||
settings,
|
||||
}),
|
||||
).rejects.toThrow(ToolAbortError);
|
||||
expect(fetchFresh).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("keeps PR diff rows stale-first past soft TTL", async () => {
|
||||
const settings = Settings.isolated({
|
||||
|
||||
Reference in New Issue
Block a user