@@ -52,6 +52,29 @@ export class NetlifyCacheHandler implements CacheHandlerForMultipleVersions {
52
52
return await encodeBlobKey ( key )
53
53
}
54
54
55
+ private getTTL ( blob : NetlifyCacheHandlerValue ) {
56
+ if (
57
+ blob . value ?. kind === 'FETCH' ||
58
+ blob . value ?. kind === 'ROUTE' ||
59
+ blob . value ?. kind === 'APP_ROUTE' ||
60
+ blob . value ?. kind === 'PAGE' ||
61
+ blob . value ?. kind === 'PAGES' ||
62
+ blob . value ?. kind === 'APP_PAGE'
63
+ ) {
64
+ const { revalidate } = blob . value
65
+
66
+ if ( typeof revalidate === 'number' ) {
67
+ const revalidateAfter = revalidate * 1_000 + blob . lastModified
68
+ return ( revalidateAfter - Date . now ( ) ) / 1_000
69
+ }
70
+ if ( revalidate === false ) {
71
+ return 'PERMANENT'
72
+ }
73
+ }
74
+
75
+ return 'NOT SET'
76
+ }
77
+
55
78
private captureResponseCacheLastModified (
56
79
cacheValue : NetlifyCacheHandlerValue ,
57
80
key : string ,
@@ -219,10 +242,31 @@ export class NetlifyCacheHandler implements CacheHandlerForMultipleVersions {
219
242
return null
220
243
}
221
244
245
+ const ttl = this . getTTL ( blob )
246
+
247
+ if ( getRequestContext ( ) ?. isBackgroundRevalidation && typeof ttl === 'number' && ttl < 0 ) {
248
+ // background revalidation request should allow data that is not yet stale,
249
+ // but opt to discard STALE data, so that Next.js generate fresh response
250
+ span . addEvent ( 'Discarding stale entry due to SWR background revalidation request' , {
251
+ key,
252
+ blobKey,
253
+ ttl,
254
+ } )
255
+ getLogger ( )
256
+ . withFields ( {
257
+ ttl,
258
+ key,
259
+ } )
260
+ . debug (
261
+ `[NetlifyCacheHandler.get] Discarding stale entry due to SWR background revalidation request: ${ key } ` ,
262
+ )
263
+ return null
264
+ }
265
+
222
266
const staleByTags = await this . checkCacheEntryStaleByTags ( blob , ctx . tags , ctx . softTags )
223
267
224
268
if ( staleByTags ) {
225
- span . addEvent ( 'Stale' , { staleByTags } )
269
+ span . addEvent ( 'Stale' , { staleByTags, key , blobKey , ttl } )
226
270
return null
227
271
}
228
272
@@ -231,7 +275,11 @@ export class NetlifyCacheHandler implements CacheHandlerForMultipleVersions {
231
275
232
276
switch ( blob . value ?. kind ) {
233
277
case 'FETCH' :
234
- span . addEvent ( 'FETCH' , { lastModified : blob . lastModified , revalidate : ctx . revalidate } )
278
+ span . addEvent ( 'FETCH' , {
279
+ lastModified : blob . lastModified ,
280
+ revalidate : ctx . revalidate ,
281
+ ttl,
282
+ } )
235
283
return {
236
284
lastModified : blob . lastModified ,
237
285
value : blob . value ,
@@ -242,6 +290,8 @@ export class NetlifyCacheHandler implements CacheHandlerForMultipleVersions {
242
290
span . addEvent ( blob . value ?. kind , {
243
291
lastModified : blob . lastModified ,
244
292
status : blob . value . status ,
293
+ revalidate : blob . value . revalidate ,
294
+ ttl,
245
295
} )
246
296
247
297
const valueWithoutRevalidate = this . captureRouteRevalidateAndRemoveFromObject ( blob . value )
@@ -256,10 +306,10 @@ export class NetlifyCacheHandler implements CacheHandlerForMultipleVersions {
256
306
}
257
307
case 'PAGE' :
258
308
case 'PAGES' : {
259
- span . addEvent ( blob . value ?. kind , { lastModified : blob . lastModified } )
260
-
261
309
const { revalidate, ...restOfPageValue } = blob . value
262
310
311
+ span . addEvent ( blob . value ?. kind , { lastModified : blob . lastModified , revalidate, ttl } )
312
+
263
313
await this . injectEntryToPrerenderManifest ( key , revalidate )
264
314
265
315
return {
@@ -268,10 +318,10 @@ export class NetlifyCacheHandler implements CacheHandlerForMultipleVersions {
268
318
}
269
319
}
270
320
case 'APP_PAGE' : {
271
- span . addEvent ( blob . value ?. kind , { lastModified : blob . lastModified } )
272
-
273
321
const { revalidate, rscData, ...restOfPageValue } = blob . value
274
322
323
+ span . addEvent ( blob . value ?. kind , { lastModified : blob . lastModified , revalidate, ttl } )
324
+
275
325
await this . injectEntryToPrerenderManifest ( key , revalidate )
276
326
277
327
return {
0 commit comments