@@ -5,7 +5,6 @@ import { Buffer } from 'node:buffer'
55import { join } from 'node:path'
66import { join as posixJoin } from 'node:path/posix'
77
8- import { Store } from '@netlify/blobs'
98import { purgeCache } from '@netlify/functions'
109import { type Span } from '@opentelemetry/api'
1110import type { PrerenderManifest } from 'next/dist/build/index.js'
@@ -21,37 +20,34 @@ import {
2120 type NetlifyCachedRouteValue ,
2221 type NetlifyCacheHandlerValue ,
2322 type NetlifyIncrementalCacheValue ,
23+ type TagManifest ,
2424} 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'
2629
2730import { getLogger , getRequestContext } from './request-context.cjs'
2831import { getTracer } from './tracer.cjs'
2932
30- type TagManifest = { revalidatedAt : number }
31-
32- type TagManifestBlobCache = Record < string , Promise < TagManifest > >
33+ type TagManifestBlobCache = Record < string , Promise < TagManifest | null > >
3334
3435const purgeCacheUserAgent = `${ nextRuntimePkgName } @${ nextRuntimePkgVersion } `
3536
3637export class NetlifyCacheHandler implements CacheHandlerForMultipleVersions {
3738 options : CacheHandlerContext
3839 revalidatedTags : string [ ]
39- blobStore : Store
40+ cacheStore : MemoizedKeyValueStoreBackedByRegionalBlobStore
4041 tracer = getTracer ( )
4142 tagManifestsFetchedFromBlobStoreInCurrentRequest : TagManifestBlobCache
4243
4344 constructor ( options : CacheHandlerContext ) {
4445 this . options = options
4546 this . revalidatedTags = options . revalidatedTags
46- this . blobStore = getRegionalBlobStore ( { consistency : 'strong' } )
47+ this . cacheStore = getMemoizedKeyValueStoreBackedByRegionalBlobStore ( { consistency : 'strong' } )
4748 this . tagManifestsFetchedFromBlobStoreInCurrentRequest = { }
4849 }
4950
50- private async encodeBlobKey ( key : string ) {
51- const { encodeBlobKey } = await import ( '../../shared/blobkey.js' )
52- return await encodeBlobKey ( key )
53- }
54-
5551 private getTTL ( blob : NetlifyCacheHandlerValue ) {
5652 if (
5753 blob . value ?. kind === 'FETCH' ||
@@ -245,19 +241,13 @@ export class NetlifyCacheHandler implements CacheHandlerForMultipleVersions {
245241 const [ key , ctx = { } ] = args
246242 getLogger ( ) . debug ( `[NetlifyCacheHandler.get]: ${ key } ` )
247243
248- const blobKey = await this . encodeBlobKey ( key )
249- span . setAttributes ( { key, blobKey } )
244+ span . setAttributes ( { key } )
250245
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' )
257247
258248 // if blob is null then we don't have a cache entry
259249 if ( ! blob ) {
260- span . addEvent ( 'Cache miss' , { key, blobKey } )
250+ span . addEvent ( 'Cache miss' , { key } )
261251 return null
262252 }
263253
@@ -268,7 +258,6 @@ export class NetlifyCacheHandler implements CacheHandlerForMultipleVersions {
268258 // but opt to discard STALE data, so that Next.js generate fresh response
269259 span . addEvent ( 'Discarding stale entry due to SWR background revalidation request' , {
270260 key,
271- blobKey,
272261 ttl,
273262 } )
274263 getLogger ( )
@@ -285,7 +274,7 @@ export class NetlifyCacheHandler implements CacheHandlerForMultipleVersions {
285274 const staleByTags = await this . checkCacheEntryStaleByTags ( blob , ctx . tags , ctx . softTags )
286275
287276 if ( staleByTags ) {
288- span . addEvent ( 'Stale' , { staleByTags, key, blobKey , ttl } )
277+ span . addEvent ( 'Stale' , { staleByTags, key, ttl } )
289278 return null
290279 }
291280
@@ -403,9 +392,8 @@ export class NetlifyCacheHandler implements CacheHandlerForMultipleVersions {
403392 async set ( ...args : Parameters < CacheHandlerForMultipleVersions [ 'set' ] > ) {
404393 return this . tracer . withActiveSpan ( 'set cache key' , async ( span ) => {
405394 const [ key , data , context ] = args
406- const blobKey = await this . encodeBlobKey ( key )
407395 const lastModified = Date . now ( )
408- span . setAttributes ( { key, lastModified, blobKey } )
396+ span . setAttributes ( { key, lastModified } )
409397
410398 getLogger ( ) . debug ( `[NetlifyCacheHandler.set]: ${ key } ` )
411399
@@ -415,10 +403,7 @@ export class NetlifyCacheHandler implements CacheHandlerForMultipleVersions {
415403 // and we didn't yet capture cache tags, we try to get cache tags from freshly produced cache value
416404 this . captureCacheTags ( value , key )
417405
418- await this . blobStore . setJSON ( blobKey , {
419- lastModified,
420- value,
421- } )
406+ await this . cacheStore . set ( key , { lastModified, value } , 'blobStore.set' )
422407
423408 if ( data ?. kind === 'PAGE' || data ?. kind === 'PAGES' ) {
424409 const requestContext = getRequestContext ( )
@@ -476,7 +461,7 @@ export class NetlifyCacheHandler implements CacheHandlerForMultipleVersions {
476461 await Promise . all (
477462 tags . map ( async ( tag ) => {
478463 try {
479- await this . blobStore . setJSON ( await this . encodeBlobKey ( tag ) , data )
464+ await this . cacheStore . set ( tag , data , 'tagManifest.set' )
480465 } catch ( error ) {
481466 getLogger ( ) . withError ( error ) . log ( `Failed to update tag manifest for ${ tag } ` )
482467 }
@@ -544,23 +529,21 @@ export class NetlifyCacheHandler implements CacheHandlerForMultipleVersions {
544529 const tagManifestPromises : Promise < boolean > [ ] = [ ]
545530
546531 for ( const tag of cacheTags ) {
547- let tagManifestPromise : Promise < TagManifest > =
532+ let tagManifestPromise : Promise < TagManifest | null > =
548533 this . tagManifestsFetchedFromBlobStoreInCurrentRequest [ tag ]
549534
550535 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' )
557537
558538 this . tagManifestsFetchedFromBlobStoreInCurrentRequest [ tag ] = tagManifestPromise
559539 }
560540
561541 tagManifestPromises . push (
562542 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 ( ) )
564547 if ( isStale ) {
565548 resolve ( true )
566549 return true
0 commit comments