@@ -5,7 +5,6 @@ import { Buffer } from 'node:buffer'
5
5
import { join } from 'node:path'
6
6
import { join as posixJoin } from 'node:path/posix'
7
7
8
- import { Store } from '@netlify/blobs'
9
8
import { purgeCache } from '@netlify/functions'
10
9
import { type Span } from '@opentelemetry/api'
11
10
import type { PrerenderManifest } from 'next/dist/build/index.js'
@@ -21,37 +20,34 @@ import {
21
20
type NetlifyCachedRouteValue ,
22
21
type NetlifyCacheHandlerValue ,
23
22
type NetlifyIncrementalCacheValue ,
23
+ type TagManifest ,
24
24
} from '../../shared/cache-types.cjs'
25
- import { getRegionalBlobStore } from '../regional-blob-store.cjs'
25
+ import {
26
+ getMemoizedKeyValueStoreBackedByRegionalBlobStore ,
27
+ MemoizedKeyValueStoreBackedByRegionalBlobStore ,
28
+ } from '../regional-blob-store.cjs'
26
29
27
30
import { getLogger , getRequestContext } from './request-context.cjs'
28
31
import { getTracer } from './tracer.cjs'
29
32
30
- type TagManifest = { revalidatedAt : number }
31
-
32
- type TagManifestBlobCache = Record < string , Promise < TagManifest > >
33
+ type TagManifestBlobCache = Record < string , Promise < TagManifest | null > >
33
34
34
35
const purgeCacheUserAgent = `${ nextRuntimePkgName } @${ nextRuntimePkgVersion } `
35
36
36
37
export class NetlifyCacheHandler implements CacheHandlerForMultipleVersions {
37
38
options : CacheHandlerContext
38
39
revalidatedTags : string [ ]
39
- blobStore : Store
40
+ cacheStore : MemoizedKeyValueStoreBackedByRegionalBlobStore
40
41
tracer = getTracer ( )
41
42
tagManifestsFetchedFromBlobStoreInCurrentRequest : TagManifestBlobCache
42
43
43
44
constructor ( options : CacheHandlerContext ) {
44
45
this . options = options
45
46
this . revalidatedTags = options . revalidatedTags
46
- this . blobStore = getRegionalBlobStore ( { consistency : 'strong' } )
47
+ this . cacheStore = getMemoizedKeyValueStoreBackedByRegionalBlobStore ( { consistency : 'strong' } )
47
48
this . tagManifestsFetchedFromBlobStoreInCurrentRequest = { }
48
49
}
49
50
50
- private async encodeBlobKey ( key : string ) {
51
- const { encodeBlobKey } = await import ( '../../shared/blobkey.js' )
52
- return await encodeBlobKey ( key )
53
- }
54
-
55
51
private getTTL ( blob : NetlifyCacheHandlerValue ) {
56
52
if (
57
53
blob . value ?. kind === 'FETCH' ||
@@ -245,19 +241,13 @@ export class NetlifyCacheHandler implements CacheHandlerForMultipleVersions {
245
241
const [ key , ctx = { } ] = args
246
242
getLogger ( ) . debug ( `[NetlifyCacheHandler.get]: ${ key } ` )
247
243
248
- const blobKey = await this . encodeBlobKey ( key )
249
- span . setAttributes ( { key, blobKey } )
244
+ span . setAttributes ( { key } )
250
245
251
- const blob = ( await this . tracer . withActiveSpan ( 'blobStore.get' , async ( blobGetSpan ) => {
252
- blobGetSpan . setAttributes ( { key, blobKey } )
253
- return await this . blobStore . get ( blobKey , {
254
- type : 'json' ,
255
- } )
256
- } ) ) as NetlifyCacheHandlerValue | null
246
+ const blob = await this . cacheStore . get < NetlifyCacheHandlerValue > ( key , 'blobStore.get' )
257
247
258
248
// if blob is null then we don't have a cache entry
259
249
if ( ! blob ) {
260
- span . addEvent ( 'Cache miss' , { key, blobKey } )
250
+ span . addEvent ( 'Cache miss' , { key } )
261
251
return null
262
252
}
263
253
@@ -268,7 +258,6 @@ export class NetlifyCacheHandler implements CacheHandlerForMultipleVersions {
268
258
// but opt to discard STALE data, so that Next.js generate fresh response
269
259
span . addEvent ( 'Discarding stale entry due to SWR background revalidation request' , {
270
260
key,
271
- blobKey,
272
261
ttl,
273
262
} )
274
263
getLogger ( )
@@ -285,7 +274,7 @@ export class NetlifyCacheHandler implements CacheHandlerForMultipleVersions {
285
274
const staleByTags = await this . checkCacheEntryStaleByTags ( blob , ctx . tags , ctx . softTags )
286
275
287
276
if ( staleByTags ) {
288
- span . addEvent ( 'Stale' , { staleByTags, key, blobKey , ttl } )
277
+ span . addEvent ( 'Stale' , { staleByTags, key, ttl } )
289
278
return null
290
279
}
291
280
@@ -403,9 +392,8 @@ export class NetlifyCacheHandler implements CacheHandlerForMultipleVersions {
403
392
async set ( ...args : Parameters < CacheHandlerForMultipleVersions [ 'set' ] > ) {
404
393
return this . tracer . withActiveSpan ( 'set cache key' , async ( span ) => {
405
394
const [ key , data , context ] = args
406
- const blobKey = await this . encodeBlobKey ( key )
407
395
const lastModified = Date . now ( )
408
- span . setAttributes ( { key, lastModified, blobKey } )
396
+ span . setAttributes ( { key, lastModified } )
409
397
410
398
getLogger ( ) . debug ( `[NetlifyCacheHandler.set]: ${ key } ` )
411
399
@@ -415,10 +403,7 @@ export class NetlifyCacheHandler implements CacheHandlerForMultipleVersions {
415
403
// and we didn't yet capture cache tags, we try to get cache tags from freshly produced cache value
416
404
this . captureCacheTags ( value , key )
417
405
418
- await this . blobStore . setJSON ( blobKey , {
419
- lastModified,
420
- value,
421
- } )
406
+ await this . cacheStore . set ( key , { lastModified, value } , 'blobStore.set' )
422
407
423
408
if ( data ?. kind === 'PAGE' || data ?. kind === 'PAGES' ) {
424
409
const requestContext = getRequestContext ( )
@@ -476,7 +461,7 @@ export class NetlifyCacheHandler implements CacheHandlerForMultipleVersions {
476
461
await Promise . all (
477
462
tags . map ( async ( tag ) => {
478
463
try {
479
- await this . blobStore . setJSON ( await this . encodeBlobKey ( tag ) , data )
464
+ await this . cacheStore . set ( tag , data , 'tagManifest.set' )
480
465
} catch ( error ) {
481
466
getLogger ( ) . withError ( error ) . log ( `Failed to update tag manifest for ${ tag } ` )
482
467
}
@@ -544,23 +529,21 @@ export class NetlifyCacheHandler implements CacheHandlerForMultipleVersions {
544
529
const tagManifestPromises : Promise < boolean > [ ] = [ ]
545
530
546
531
for ( const tag of cacheTags ) {
547
- let tagManifestPromise : Promise < TagManifest > =
532
+ let tagManifestPromise : Promise < TagManifest | null > =
548
533
this . tagManifestsFetchedFromBlobStoreInCurrentRequest [ tag ]
549
534
550
535
if ( ! tagManifestPromise ) {
551
- tagManifestPromise = this . encodeBlobKey ( tag ) . then ( ( blobKey ) => {
552
- return this . tracer . withActiveSpan ( `get tag manifest` , async ( span ) => {
553
- span . setAttributes ( { tag, blobKey } )
554
- return this . blobStore . get ( blobKey , { type : 'json' } )
555
- } )
556
- } )
536
+ tagManifestPromise = this . cacheStore . get < TagManifest > ( tag , 'tagManifest.get' )
557
537
558
538
this . tagManifestsFetchedFromBlobStoreInCurrentRequest [ tag ] = tagManifestPromise
559
539
}
560
540
561
541
tagManifestPromises . push (
562
542
tagManifestPromise . then ( ( tagManifest ) => {
563
- const isStale = tagManifest ?. revalidatedAt >= ( cacheEntry . lastModified || Date . now ( ) )
543
+ if ( ! tagManifest ) {
544
+ return false
545
+ }
546
+ const isStale = tagManifest . revalidatedAt >= ( cacheEntry . lastModified || Date . now ( ) )
564
547
if ( isStale ) {
565
548
resolve ( true )
566
549
return true
0 commit comments