Skip to content

Commit 770511a

Browse files
committed
allow revalidate in cache handler, fix revalidate write
1 parent 74ac764 commit 770511a

File tree

2 files changed

+66
-42
lines changed

2 files changed

+66
-42
lines changed

packages/next/src/server/lib/cache-handlers/default.external.ts

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -64,16 +64,18 @@ const DefaultCacheHandler: CacheHandler = {
6464
}
6565

6666
const entry = privateEntry.entry
67-
if (
68-
performance.timeOrigin + performance.now() >
69-
entry.timestamp + entry.revalidate * 1000
70-
) {
71-
// In-memory caches should expire after revalidate time because it is
72-
// unlikely that a new entry will be able to be used before it is dropped
73-
// from the cache.
74-
debug?.('get', cacheKey, 'expired')
75-
76-
return undefined
67+
if (process.env.NODE_ENV !== 'development') {
68+
if (
69+
performance.timeOrigin + performance.now() >
70+
entry.timestamp + entry.revalidate * 1000
71+
) {
72+
// In-memory caches should expire after revalidate time because it is
73+
// unlikely that a new entry will be able to be used before it is dropped
74+
// from the cache.
75+
debug?.('get', cacheKey, 'expired')
76+
77+
return undefined
78+
}
7779
}
7880

7981
let revalidate = entry.revalidate

packages/next/src/server/use-cache/use-cache-wrapper.ts

Lines changed: 54 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1508,43 +1508,65 @@ export function cache(
15081508
// If this is stale, and we're not in a prerender (i.e. this is
15091509
// dynamic render), then we should warm up the cache with a fresh
15101510
// revalidated entry.
1511-
const result = await generateCacheEntry(
1512-
workStore,
1513-
// This is not running within the context of this unit.
1514-
{ kind: cacheContext.kind, outerWorkUnitStore: undefined },
1515-
clientReferenceManifest,
1516-
encodedCacheKeyParts,
1517-
fn,
1518-
sharedErrorStack
1519-
)
1511+
const revalidateAndWriteNewEntry = async () => {
1512+
const result = await generateCacheEntry(
1513+
workStore,
1514+
// This is not running within the context of this unit.
1515+
{ kind: cacheContext.kind, outerWorkUnitStore: undefined },
1516+
clientReferenceManifest,
1517+
encodedCacheKeyParts,
1518+
fn,
1519+
sharedErrorStack
1520+
)
15201521

1521-
if (result.type === 'cached') {
1522-
const { stream: ignoredStream, pendingCacheEntry } = result
1523-
let savedCacheEntry: Promise<CacheEntry>
1524-
1525-
if (prerenderResumeDataCache) {
1526-
const split = clonePendingCacheEntry(pendingCacheEntry)
1527-
savedCacheEntry = getNthCacheEntry(split, 0)
1528-
prerenderResumeDataCache.cache.set(
1529-
serializedCacheKey,
1530-
getNthCacheEntry(split, 1)
1531-
)
1532-
} else {
1533-
savedCacheEntry = pendingCacheEntry
1534-
}
1522+
if (result.type === 'cached') {
1523+
const { stream: ignoredStream, pendingCacheEntry } = result
1524+
let savedCacheEntry: Promise<CacheEntry>
1525+
1526+
// TODO: do we ever want to mutate the `prerenderResumeDataCache` while a render is ongoing?
1527+
if (
1528+
prerenderResumeDataCache &&
1529+
// This is not covered by a cache read, so in a dev staged render
1530+
// we don't want to overwrite the existing cache entry
1531+
// both to avoid timing issues (with cache entries ehtat aren't finished yet) and tearing.
1532+
!(
1533+
process.env.NODE_ENV === 'development' &&
1534+
workUnitStore &&
1535+
// eslint-disable-next-line no-restricted-syntax
1536+
workUnitStore.type === 'request' &&
1537+
workUnitStore.stagedRendering
1538+
)
1539+
) {
1540+
const split = clonePendingCacheEntry(pendingCacheEntry)
1541+
savedCacheEntry = getNthCacheEntry(split, 0)
1542+
prerenderResumeDataCache.cache.set(
1543+
serializedCacheKey,
1544+
getNthCacheEntry(split, 1)
1545+
)
1546+
} else {
1547+
savedCacheEntry = pendingCacheEntry
1548+
}
15351549

1536-
if (cacheHandler) {
1537-
const promise = cacheHandler.set(
1538-
serializedCacheKey,
1539-
savedCacheEntry
1540-
)
1550+
let pendingWrite: Promise<void> | undefined
1551+
if (cacheHandler) {
1552+
pendingWrite = cacheHandler.set(
1553+
serializedCacheKey,
1554+
savedCacheEntry
1555+
)
1556+
}
15411557

1542-
workStore.pendingRevalidateWrites ??= []
1543-
workStore.pendingRevalidateWrites.push(promise)
1558+
await ignoredStream.cancel()
1559+
return pendingWrite
15441560
}
1545-
1546-
await ignoredStream.cancel()
15471561
}
1562+
1563+
// TODO: ideally, this'd be scheduled to run after the render is finished
1564+
// to avoid interfering with any critical work.
1565+
const pendingRevalidatePromise = new Promise((resolve) =>
1566+
setTimeout(resolve)
1567+
).then(() => revalidateAndWriteNewEntry())
1568+
workStore.pendingRevalidateWrites ??= []
1569+
workStore.pendingRevalidateWrites.push(pendingRevalidatePromise)
15481570
}
15491571
}
15501572
}

0 commit comments

Comments
 (0)