Skip to content

Commit 8a102c6

Browse files
committed
Allow ignored-abort fetches to update cache
Very niche edge case, but happens when a fetch implementation is aborted, but the underlying fetch implementation was not aborted, and no value existed in the cache already. In this case, it *should* update the stored cached value, but was not, because the pending fetch was not stored. Fix: isaacs#388
1 parent fa211ba commit 8a102c6

File tree

2 files changed

+30
-1
lines changed

2 files changed

+30
-1
lines changed

src/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2387,7 +2387,11 @@ export class LRUCache<K extends {}, V extends {}, FC = unknown> {
23872387
}
23882388
// either we didn't abort, and are still here, or we did, and ignored
23892389
const bf = p as BackgroundFetch<V>
2390-
if (this.#valList[index as Index] === p) {
2390+
// if nothing else has been written there but we're set to update the
2391+
// cache and ignore the abort, or if it's still pending on this specific
2392+
// background request, then write it to the cache.
2393+
const vl = this.#valList[index as Index]
2394+
if (vl === p || ignoreAbort && updateCache && vl === undefined) {
23912395
if (v === undefined) {
23922396
if (bf.__staleWhileFetching !== undefined) {
23932397
this.#valList[index as Index] = bf.__staleWhileFetching

test/fetch.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -870,3 +870,28 @@ t.test('properly dispose when using fetch', async t => {
870870
t.strictSame(disposes, [[0, 1, 'set']])
871871
t.strictSame(disposeAfters, [[0, 1, 'set']])
872872
})
873+
874+
t.test('allowStaleOnFetchAbort and ignoreFetchAbort', async t => {
875+
const c = new LRUCache<number, number, void>({
876+
ttl: 10,
877+
max: 10,
878+
ignoreFetchAbort: true,
879+
allowStaleOnFetchAbort: true,
880+
fetchMethod: async k => {
881+
return new Promise(res => {
882+
setTimeout(() => {
883+
res(k)
884+
}, 100)
885+
})
886+
},
887+
})
888+
const ac = new AbortController()
889+
const p = c.fetch(1, { signal: ac.signal })
890+
await new Promise<void>(res => queueMicrotask(res))
891+
ac.abort(new Error('gimme the stale value'))
892+
t.equal(await p, undefined)
893+
t.equal(c.get(1, { allowStale: true }), undefined)
894+
clock.advance(200)
895+
await new Promise<void>(res => queueMicrotask(res)).then(() => {})
896+
t.equal(c.get(1), 1)
897+
})

0 commit comments

Comments
 (0)