Skip to content

Commit 57d4b57

Browse files
committed
fix: workaround Date heuristics
1 parent 3e46472 commit 57d4b57

File tree

5 files changed

+31
-5
lines changed

5 files changed

+31
-5
lines changed

src/run/handlers/cache.cts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export class NetlifyCacheHandler implements CacheHandlerForMultipleVersions {
5555

5656
if (typeof revalidate === 'number') {
5757
const revalidateAfter = revalidate * 1_000 + blob.lastModified
58-
return (revalidateAfter - Date.now()) / 1_000
58+
return (revalidateAfter - DateBeforeNextPatchedIt.now()) / 1_000
5959
}
6060
if (revalidate === false) {
6161
return 'PERMANENT'
@@ -441,7 +441,7 @@ export class NetlifyCacheHandler implements CacheHandlerForMultipleVersions {
441441
async set(...args: Parameters<CacheHandlerForMultipleVersions['set']>) {
442442
return this.tracer.withActiveSpan('set cache key', async (span) => {
443443
const [key, data, context] = args
444-
const lastModified = Date.now()
444+
const lastModified = DateBeforeNextPatchedIt.now()
445445
span.setAttributes({ key, lastModified })
446446

447447
getLogger().debug(`[NetlifyCacheHandler.set]: ${key}`)

src/run/handlers/server.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { configureUseCacheHandlers } from './use-cache-handler.js'
2222
import { setupWaitUntil } from './wait-until.cjs'
2323
// make use of global fetch before Next.js applies any patching
2424
setFetchBeforeNextPatchedIt(globalThis.fetch)
25+
globalThis.DateBeforeNextPatchedIt = Date
2526
// configure globals that Next.js make use of before we start importing any Next.js code
2627
// as some globals are consumed at import time
2728
const { nextConfig: initialNextConfig, enableUseCacheHandler } = await getRunConfig()
@@ -35,6 +36,30 @@ const nextImportPromise = import('../next.cjs')
3536

3637
let nextHandler: WorkerRequestHandler
3738

39+
// Lambda Runtime patches these methods to include timestamp with `new Date()` which ...
40+
// has tension with https://nextjs.org/docs/messages/next-prerender-current-time
41+
// as this timestamp is NOT impacting Next.js render we temporarily restore original Date
42+
// to not affect Next.js heuristics related to `Date` usage
43+
for (const consoleMethod of [
44+
'trace',
45+
'debug',
46+
'info',
47+
'log',
48+
'warn',
49+
'error',
50+
// fatal is not console method, but AWS Lambda Runtime adds it
51+
'fatal',
52+
] as const) {
53+
const originalMethod = console[consoleMethod].bind(console)
54+
console[consoleMethod] = (...args: unknown[]) => {
55+
const patchedDate = Date
56+
Date = DateBeforeNextPatchedIt
57+
const retval = originalMethod(...args)
58+
Date = patchedDate
59+
return retval
60+
}
61+
}
62+
3863
/**
3964
* When Next.js proxies requests externally, it writes the response back as-is.
4065
* In some cases, this includes Transfer-Encoding: chunked.

src/run/handlers/tags-handler.cts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ async function doRevalidateTagAndPurgeEdgeCache(tags: string[]): Promise<void> {
130130
}
131131

132132
const tagManifest: TagManifest = {
133-
revalidatedAt: Date.now(),
133+
revalidatedAt: DateBeforeNextPatchedIt.now(),
134134
}
135135

136136
const cacheStore = getMemoizedKeyValueStoreBackedByRegionalBlobStore({ consistency: 'strong' })

src/run/handlers/use-cache-handler.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,8 @@ export const NetlifyDefaultUseCacheHandler = {
112112
}
113113

114114
const { entry } = privateEntry
115-
const ttl = (entry.timestamp + entry.revalidate * 1000 - Date.now()) / 1000
115+
const ttl =
116+
(entry.timestamp + entry.revalidate * 1000 - DateBeforeNextPatchedIt.now()) / 1000
116117
if (ttl < 0) {
117118
// In-memory caches should expire after revalidate time because it is
118119
// unlikely that a new entry will be able to be used before it is dropped

src/run/headers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ export const adjustDateHeader = async ({
192192
return
193193
}
194194

195-
const lastModifiedDate = new Date(lastModified)
195+
const lastModifiedDate = new DateBeforeNextPatchedIt(lastModified)
196196
// Show actual date of the function call in the date header
197197
headers.set('x-nextjs-date', headers.get('date') ?? lastModifiedDate.toUTCString())
198198
// Setting Age also would work, but we already have the lastModified time so will use that.

0 commit comments

Comments
 (0)