Skip to content

Commit 25646ec

Browse files
authored
fix(engine-bridge): enforce LRU bound after revalidation (#225)
1 parent 62890bf commit 25646ec

2 files changed

Lines changed: 47 additions & 0 deletions

File tree

engine-bridge/src/__tests__/chain-state-cache.test.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,17 @@ function makeRpc(): RpcClient {
99
return rpc;
1010
}
1111

12+
function deferred<T>(): {
13+
promise: Promise<T>;
14+
resolve: (value: T) => void;
15+
} {
16+
let resolve!: (value: T) => void;
17+
const promise = new Promise<T>(resolvePromise => {
18+
resolve = resolvePromise;
19+
});
20+
return { promise, resolve };
21+
}
22+
1223
describe("ChainStateCache", () => {
1324
describe("bounded cache (maxEntries)", () => {
1425
it("caps cache size at maxEntries when more distinct keys are inserted", async () => {
@@ -52,6 +63,41 @@ describe("ChainStateCache", () => {
5263

5364
expect((cache as any).cache.size).toBe(3);
5465
});
66+
67+
it("reapplies the LRU bound when revalidation resurrects an evicted entry", async () => {
68+
const rpc = makeRpc();
69+
const cache = new ChainStateCache(rpc, -1, 2);
70+
const initialFetcher = async () => ({ value: "initial" });
71+
72+
await cache.getSwr("a", initialFetcher);
73+
await cache.getSwr("b", initialFetcher);
74+
75+
const refreshStarted = deferred<void>();
76+
const refreshResult = deferred<{ value: string }>();
77+
const stale = await cache.getSwr("a", async () => {
78+
refreshStarted.resolve(undefined);
79+
return refreshResult.promise;
80+
});
81+
await refreshStarted.promise;
82+
expect(stale).toEqual({ value: "initial" });
83+
84+
await cache.getSwr("c", initialFetcher);
85+
await cache.getSwr("d", initialFetcher);
86+
87+
const cacheEntries = (
88+
cache as unknown as {
89+
cache: Map<string, { data: { value: string } }>;
90+
}
91+
).cache;
92+
expect([...cacheEntries.keys()]).toEqual(["c", "d"]);
93+
94+
refreshResult.resolve({ value: "refreshed" });
95+
await new Promise<void>(resolve => setImmediate(resolve));
96+
97+
expect(cacheEntries.size).toBe(2);
98+
expect([...cacheEntries.keys()]).toEqual(["d", "a"]);
99+
expect(cacheEntries.get("a")?.data).toEqual({ value: "refreshed" });
100+
});
55101
});
56102

57103
describe("SWR behavior", () => {

engine-bridge/src/chain-state-cache.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ export class ChainStateCache {
110110
try {
111111
const data = await fetcher(this.rpc);
112112
this.cache.set(key, { data, updatedAt: Date.now(), isRevalidating: false });
113+
this.evictIfNeeded();
113114
} catch (error) {
114115
const item = this.cache.get(key);
115116
if (item) {

0 commit comments

Comments
 (0)