fix(github): refreshed stale issue and pr views
Refresh soft-expired issue and PR view cache rows synchronously before returning content, while keeping PR diff rows on stale-first refresh semantics. Add stale fallback warnings when a live refresh fails and cover the cache/protocol behavior in tests. Fixes #2684
This commit is contained in:
@@ -299,7 +299,7 @@ describe("getOrFetchView (TTL semantics)", () => {
|
||||
expect(fetchFresh).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("returns cached row AND schedules a background refresh past soft TTL", async () => {
|
||||
it("refreshes issue rows synchronously past soft TTL", async () => {
|
||||
const settings = Settings.isolated({
|
||||
"github.cache.softTtlSec": 60,
|
||||
"github.cache.hardTtlSec": 86400,
|
||||
@@ -326,21 +326,94 @@ describe("getOrFetchView (TTL semantics)", () => {
|
||||
fetchFresh,
|
||||
settings,
|
||||
});
|
||||
expect(result.status).toBe("stale");
|
||||
expect(result.rendered).toBe("old");
|
||||
|
||||
// Background refresh runs on a microtask; flush + give the write a tick
|
||||
// to land before asserting.
|
||||
await Promise.resolve();
|
||||
// Wait for the chained .then() (writes) to settle.
|
||||
await new Promise<void>(resolve => setTimeout(resolve, 5));
|
||||
|
||||
expect(result.status).toBe("refreshed");
|
||||
expect(result.rendered).toBe("refreshed");
|
||||
expect(fetchFresh).toHaveBeenCalledTimes(1);
|
||||
|
||||
const updated = getCached<{ refreshed: boolean }>(TEST_REPO, "issue", 50, true);
|
||||
expect(updated?.rendered).toBe("refreshed");
|
||||
expect(updated?.payload.refreshed).toBe(true);
|
||||
});
|
||||
|
||||
it("falls back to stale issue rows when a soft-expired synchronous refresh fails", async () => {
|
||||
const settings = Settings.isolated({
|
||||
"github.cache.softTtlSec": 60,
|
||||
"github.cache.hardTtlSec": 86400,
|
||||
});
|
||||
const fetchFresh = vi.fn(
|
||||
async (): Promise<{
|
||||
rendered: string;
|
||||
sourceUrl: undefined;
|
||||
payload: { number: number; refreshed: boolean };
|
||||
}> => {
|
||||
throw new Error("offline");
|
||||
},
|
||||
);
|
||||
putCached({
|
||||
repo: TEST_REPO,
|
||||
kind: "issue",
|
||||
number: 51,
|
||||
includeComments: true,
|
||||
payload: { number: 51, refreshed: false },
|
||||
rendered: "old",
|
||||
fetchedAt: Date.now() - 5 * 60_000,
|
||||
});
|
||||
|
||||
const result = await getOrFetchView({
|
||||
repo: TEST_REPO,
|
||||
kind: "issue",
|
||||
number: 51,
|
||||
includeComments: true,
|
||||
fetchFresh,
|
||||
settings,
|
||||
});
|
||||
|
||||
expect(result.status).toBe("stale");
|
||||
expect(result.rendered).toBe("old");
|
||||
expect(fetchFresh).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("keeps PR diff rows stale-first past soft TTL", async () => {
|
||||
const settings = Settings.isolated({
|
||||
"github.cache.softTtlSec": 60,
|
||||
"github.cache.hardTtlSec": 86400,
|
||||
});
|
||||
const fetchFresh = vi.fn(async () => ({
|
||||
rendered: "refreshed-diff",
|
||||
sourceUrl: undefined,
|
||||
payload: { files: [], refreshed: true },
|
||||
}));
|
||||
putCached({
|
||||
repo: TEST_REPO,
|
||||
kind: "pr-diff",
|
||||
number: 52,
|
||||
includeComments: false,
|
||||
payload: { files: [], refreshed: false },
|
||||
rendered: "old-diff",
|
||||
fetchedAt: Date.now() - 5 * 60_000,
|
||||
});
|
||||
|
||||
const result = await getOrFetchView({
|
||||
repo: TEST_REPO,
|
||||
kind: "pr-diff",
|
||||
number: 52,
|
||||
includeComments: false,
|
||||
fetchFresh,
|
||||
settings,
|
||||
});
|
||||
|
||||
expect(result.status).toBe("stale");
|
||||
expect(result.rendered).toBe("old-diff");
|
||||
|
||||
await Promise.resolve();
|
||||
await Bun.sleep(5);
|
||||
|
||||
expect(fetchFresh).toHaveBeenCalledTimes(1);
|
||||
const updated = getCached<{ refreshed: boolean }>(TEST_REPO, "pr-diff", 52, false);
|
||||
expect(updated?.rendered).toBe("refreshed-diff");
|
||||
expect(updated?.payload.refreshed).toBe(true);
|
||||
});
|
||||
|
||||
it("treats past-hard-TTL rows as cache misses (fetcher runs)", async () => {
|
||||
const settings = Settings.isolated({
|
||||
"github.cache.softTtlSec": 60,
|
||||
|
||||
Reference in New Issue
Block a user