@@ -36,14 +36,16 @@ const isEdgeRuntime = process.env.NEXT_RUNTIME === 'edge'
36
36
37
37
type CacheEntry = {
38
38
value : ReadableStream
39
+ timestamp : number
39
40
// In-memory caches are fragile and should not use stale-while-revalidate
40
41
// semantics on the caches because it's not worth warming up an entry that's
41
42
// likely going to get evicted before we get to use it anyway. However,
42
43
// we also don't want to reuse a stale entry for too long so stale entries
43
44
// should be considered expired/missing in such CacheHandlers.
44
- stale : boolean
45
- tags : string [ ]
46
45
revalidate : number
46
+ expire : number
47
+ stale : number
48
+ tags : string [ ]
47
49
}
48
50
49
51
interface CacheHandler {
@@ -60,12 +62,22 @@ cacheHandlerMap.set('default', {
60
62
// TODO: Implement proper caching.
61
63
const entry = await defaultCacheStorage . get ( cacheKey )
62
64
if ( entry !== undefined ) {
65
+ if (
66
+ performance . timeOrigin + performance . now ( ) >
67
+ entry . timestamp + entry . revalidate * 1000
68
+ ) {
69
+ // In memory caches should expire after revalidate time because it is unlikely that
70
+ // a new entry will be able to be used before it is dropped from the cache.
71
+ return undefined
72
+ }
63
73
const [ returnStream , newSaved ] = entry . value . tee ( )
64
74
entry . value = newSaved
65
75
return {
66
76
value : returnStream ,
67
- stale : false ,
77
+ timestamp : entry . timestamp ,
68
78
revalidate : entry . revalidate ,
79
+ expire : entry . revalidate ,
80
+ stale : entry . stale ,
69
81
tags : entry . tags ,
70
82
}
71
83
}
@@ -217,6 +229,7 @@ async function collectResult(
217
229
savedStream : ReadableStream ,
218
230
outerWorkUnitStore : WorkUnitStore | undefined ,
219
231
innerCacheStore : UseCacheStore ,
232
+ startTime : number ,
220
233
errors : Array < unknown > // This is a live array that gets pushed into.
221
234
) : Promise < CacheEntry > {
222
235
// We create a buffered stream that collects all chunks until the end to
@@ -263,9 +276,11 @@ async function collectResult(
263
276
264
277
const entry = {
265
278
value : bufferStream ,
266
- stale : false , // TODO: rm
267
- tags : collectedTags === null ? [ ] : collectedTags ,
279
+ timestamp : startTime ,
268
280
revalidate : collectedRevalidate ,
281
+ expire : Infinity ,
282
+ stale : 0 ,
283
+ tags : collectedTags === null ? [ ] : collectedTags ,
269
284
}
270
285
// Propagate tags/revalidate to the parent context.
271
286
propagateCacheLifeAndTags ( outerWorkUnitStore , entry )
@@ -301,6 +316,8 @@ async function generateCacheEntryImpl(
301
316
}
302
317
)
303
318
319
+ // Track the timestamp when we started copmuting the result.
320
+ const startTime = performance . timeOrigin + performance . now ( )
304
321
// Invoke the inner function to load a new result.
305
322
const result = fn . apply ( null , args )
306
323
@@ -326,6 +343,7 @@ async function generateCacheEntryImpl(
326
343
savedStream ,
327
344
outerWorkUnitStore ,
328
345
innerCacheStore ,
346
+ startTime ,
329
347
errors
330
348
)
331
349
@@ -372,7 +390,13 @@ async function loadCacheEntry(
372
390
implicitTags
373
391
)
374
392
375
- if ( entry === undefined || ( entry . stale && workStore . isStaticGeneration ) ) {
393
+ const currentTime = performance . timeOrigin + performance . now ( )
394
+ if (
395
+ entry === undefined ||
396
+ currentTime > entry . timestamp + entry . expire * 1000 ||
397
+ ( workStore . isStaticGeneration &&
398
+ currentTime > entry . timestamp + entry . revalidate * 1000 )
399
+ ) {
376
400
// Miss. Generate a new result.
377
401
378
402
// If the cache entry is stale and we're prerendering, we don't want to use the
@@ -398,7 +422,7 @@ async function loadCacheEntry(
398
422
} else {
399
423
propagateCacheLifeAndTags ( workUnitStore , entry )
400
424
401
- if ( entry . stale ) {
425
+ if ( currentTime > entry . timestamp + entry . revalidate ) {
402
426
// If this is stale, and we're not in a prerender (i.e. this is dynamic render),
403
427
// then we should warm up the cache with a fresh revalidated entry.
404
428
const ignoredStream = await generateCacheEntry (
0 commit comments