mirror of
https://github.com/hanzoai/next.js.git
synced 2026-09-24 17:00:51 +00:00
### What? When using the file system cache with `isrMemoryCacheSize: 0`, time-based revalidation is not working, and the file is constantly updated. I have also added some debug logging to mirror that in the `fetch-cache` handler Detailed explanation in #58507 ### Why? The cached object's tags are incorrectly accessed, causing the cache to be rewritten every hit. This is catastrophic for a caching system that relies on file modification timestamps. The tags are one level up in the object from where [they are currently being accessed](https://github.com/vercel/next.js/blob/9ab8828f72e96f5de86a7c50b67a1c5abe6e146c/packages/next/src/server/lib/incremental-cache/file-system-cache.ts#L178). Below shows a cached fetch representation on disk. When written, the tags reside at `obj.tags` instead of `obj.data.tags` ```json { "kind": "FETCH", "data": { "headers": { "connection": "keep-alive", "content-encoding": "br", "content-type": "application/json; charset=utf-8", "date": "Wed, 15 Nov 2023 21:17:42 GMT", "server": "nginx/1.18.0 (Ubuntu)", "transfer-encoding": "chunked", "vary": "Accept-Encoding" }, "body": "[SNIP]", "status": 200, "url": "https://timeapi.io/api/Time/current/zone?timeZone=UTC" # this is where the current code is trying to pull the tags # "tags": [ "time-with-fetch" ] }, "revalidate": 20, # tags actually live here "tags": [ "time-with-fetch" ] } ``` Fixes #58507
130 lines
2.9 KiB
TypeScript
130 lines
2.9 KiB
TypeScript
import { promises as fs } from 'node:fs'
|
|
import { fileURLToPath } from 'node:url'
|
|
import FileSystemCache from 'next/dist/server/lib/incremental-cache/file-system-cache'
|
|
import { nodeFs } from 'next/dist/server/lib/node-fs-methods'
|
|
|
|
const cacheDir = fileURLToPath(new URL('./cache', import.meta.url))
|
|
|
|
describe('FileSystemCache', () => {
|
|
it('set image route', async () => {
|
|
const fsCache = new FileSystemCache({
|
|
_appDir: true,
|
|
_pagesDir: true,
|
|
_requestHeaders: {},
|
|
flushToDisk: true,
|
|
fs: nodeFs,
|
|
serverDistDir: cacheDir,
|
|
revalidatedTags: [],
|
|
experimental: {
|
|
ppr: false,
|
|
},
|
|
})
|
|
|
|
const binary = await fs.readFile(
|
|
fileURLToPath(new URL('./images/icon.png', import.meta.url))
|
|
)
|
|
|
|
await fsCache.set(
|
|
'icon.png',
|
|
{
|
|
body: binary,
|
|
headers: {
|
|
'Content-Type': 'image/png',
|
|
},
|
|
status: 200,
|
|
kind: 'ROUTE',
|
|
},
|
|
{}
|
|
)
|
|
|
|
expect((await fsCache.get('icon.png')).value).toEqual({
|
|
body: binary,
|
|
headers: {
|
|
'Content-Type': 'image/png',
|
|
},
|
|
status: 200,
|
|
kind: 'ROUTE',
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('FileSystemCache (isrMemory 0)', () => {
|
|
const fsCache = new FileSystemCache({
|
|
_appDir: true,
|
|
_pagesDir: true,
|
|
_requestHeaders: {},
|
|
flushToDisk: true,
|
|
fs: nodeFs,
|
|
serverDistDir: cacheDir,
|
|
revalidatedTags: [],
|
|
experimental: {
|
|
ppr: false,
|
|
},
|
|
maxMemoryCacheSize: 0, // disable memory cache
|
|
})
|
|
|
|
it('should cache fetch', async () => {
|
|
await fsCache.set(
|
|
'fetch-cache',
|
|
{
|
|
kind: 'FETCH',
|
|
data: {
|
|
headers: {},
|
|
body: 'MTcwMDA1NjM4MQ==',
|
|
status: 200,
|
|
url: 'http://my-api.local',
|
|
},
|
|
revalidate: 30,
|
|
},
|
|
{
|
|
fetchCache: true,
|
|
revalidate: 30,
|
|
fetchUrl: 'http://my-api.local',
|
|
fetchIdx: 5,
|
|
tags: ['server-time'],
|
|
}
|
|
)
|
|
|
|
const res = await fsCache.get('fetch-cache', {
|
|
tags: ['server-time'],
|
|
kindHint: 'fetch',
|
|
})
|
|
|
|
expect(res.value).toEqual({
|
|
kind: 'FETCH',
|
|
data: {
|
|
headers: {},
|
|
body: 'MTcwMDA1NjM4MQ==',
|
|
status: 200,
|
|
url: 'http://my-api.local',
|
|
},
|
|
revalidate: 30,
|
|
tags: ['server-time'],
|
|
})
|
|
})
|
|
|
|
it('should cache unstable_cache', async () => {
|
|
await fsCache.set(
|
|
'unstable-cache',
|
|
{
|
|
kind: 'FETCH',
|
|
data: { headers: {}, body: '1700056381', status: 200, url: '' },
|
|
revalidate: 30,
|
|
},
|
|
{ revalidate: 30, fetchCache: true, tags: ['server-time2'] }
|
|
)
|
|
|
|
const res = await fsCache.get('unstable-cache', {
|
|
tags: ['server-time'],
|
|
kindHint: 'fetch',
|
|
})
|
|
|
|
expect(res.value).toEqual({
|
|
kind: 'FETCH',
|
|
data: { headers: {}, body: '1700056381', status: 200, url: '' },
|
|
revalidate: 30,
|
|
tags: ['server-time2'],
|
|
})
|
|
})
|
|
})
|