Skip to content

Commit 2293422

Browse files
committed
feat: initial implementation
1 parent 8b059b2 commit 2293422

File tree

3 files changed

+337
-66
lines changed

3 files changed

+337
-66
lines changed

src/run/handlers/server.ts

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import { setupWaitUntil } from './wait-until.cjs'
2525
setFetchBeforeNextPatchedIt(globalThis.fetch)
2626
// configure some globals that Next.js make use of before we start importing any Next.js code
2727
// as some globals are consumed at import time
28+
// TODO: only call this if Next.js version is using CacheHandlerV2 as we don't have V1 compatible implementation
2829
configureUseCacheHandlers()
2930
setupWaitUntil()
3031

src/run/handlers/tags-handler.cts

+44-9
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,55 @@ import { purgeCache } from '@netlify/functions'
22

33
import { name as nextRuntimePkgName, version as nextRuntimePkgVersion } from '../../../package.json'
44
import { TagManifest } from '../../shared/blob-types.cjs'
5-
import { getMemoizedKeyValueStoreBackedByRegionalBlobStore } from '../storage/storage.cjs'
5+
import {
6+
getMemoizedKeyValueStoreBackedByRegionalBlobStore,
7+
MemoizedKeyValueStoreBackedByRegionalBlobStore,
8+
} from '../storage/storage.cjs'
69

710
import { getLogger, getRequestContext } from './request-context.cjs'
811

912
const purgeCacheUserAgent = `${nextRuntimePkgName}@${nextRuntimePkgVersion}`
1013

14+
/**
15+
* Get timestamp of the last revalidation for a tag
16+
*/
17+
async function lastTagRevalidationTimestamp(
18+
tag: string,
19+
cacheStore: MemoizedKeyValueStoreBackedByRegionalBlobStore,
20+
): Promise<number | null> {
21+
const tagManifest = await cacheStore.get<TagManifest>(tag, 'tagManifest.get')
22+
if (!tagManifest) {
23+
return null
24+
}
25+
return tagManifest.revalidatedAt
26+
}
27+
28+
/**
29+
*
30+
*/
31+
export async function getMostRecentTagRevalidationTimestamp(tags: string[]) {
32+
if (tags.length === 0) {
33+
return 0
34+
}
35+
36+
const cacheStore = getMemoizedKeyValueStoreBackedByRegionalBlobStore({ consistency: 'strong' })
37+
38+
const timestampsOrNulls = await Promise.all(
39+
tags.map((tag) => lastTagRevalidationTimestamp(tag, cacheStore)),
40+
)
41+
42+
const timestamps = timestampsOrNulls.filter((timestamp) => timestamp !== null)
43+
if (timestamps.length === 0) {
44+
return 0
45+
}
46+
return Math.max(...timestamps)
47+
}
48+
1149
/**
1250
* Check if any of the tags were invalidated since the given timestamp
1351
*/
1452
export function isAnyTagStale(tags: string[], timestamp: number): Promise<boolean> {
15-
if (tags.length === 0) {
53+
if (tags.length === 0 || !timestamp) {
1654
return Promise.resolve(false)
1755
}
1856

@@ -22,17 +60,14 @@ export function isAnyTagStale(tags: string[], timestamp: number): Promise<boolea
2260
const tagManifestPromises: Promise<boolean>[] = []
2361

2462
for (const tag of tags) {
25-
const tagManifestPromise: Promise<TagManifest | null> = cacheStore.get<TagManifest>(
26-
tag,
27-
'tagManifest.get',
28-
)
63+
const lastRevalidationTimestampPromise = lastTagRevalidationTimestamp(tag, cacheStore)
2964

3065
tagManifestPromises.push(
31-
tagManifestPromise.then((tagManifest) => {
32-
if (!tagManifest) {
66+
lastRevalidationTimestampPromise.then((lastRevalidationTimestamp) => {
67+
if (!lastRevalidationTimestamp) {
3368
return false
3469
}
35-
const isStale = tagManifest.revalidatedAt >= (timestamp || Date.now())
70+
const isStale = lastRevalidationTimestamp >= timestamp
3671
if (isStale) {
3772
resolve(true)
3873
return true

0 commit comments

Comments
 (0)