Skip to content

Commit 8f4b5cc

Browse files
committed
Add debug logging to default cache handler and "use cache" wrapper
1 parent 6fdb464 commit 8f4b5cc

File tree

2 files changed

+65
-3
lines changed

2 files changed

+65
-3
lines changed

packages/next/src/server/lib/cache-handlers/default.ts

+36-3
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,23 @@ const memoryCache = new LRUCache<PrivateCacheEntry>(
4141
)
4242
const pendingSets = new Map<string, Promise<void>>()
4343

44+
const debug = process.env.NEXT_PRIVATE_DEBUG_CACHE
45+
? console.debug.bind(console, 'DefaultCacheHandler:')
46+
: () => {}
47+
4448
const DefaultCacheHandler: CacheHandlerV2 = {
4549
async get(cacheKey) {
46-
await pendingSets.get(cacheKey)
50+
const pendingPromise = pendingSets.get(cacheKey)
51+
52+
if (pendingPromise) {
53+
debug('get', cacheKey, 'pending')
54+
await pendingPromise
55+
}
4756

4857
const privateEntry = memoryCache.get(cacheKey)
4958

5059
if (!privateEntry) {
60+
debug('get', cacheKey, 'not found')
5161
return undefined
5262
}
5363

@@ -59,22 +69,35 @@ const DefaultCacheHandler: CacheHandlerV2 = {
5969
// In-memory caches should expire after revalidate time because it is
6070
// unlikely that a new entry will be able to be used before it is dropped
6171
// from the cache.
72+
debug('get', cacheKey, 'expired')
73+
6274
return undefined
6375
}
6476

6577
if (isStale(entry.tags, entry.timestamp)) {
78+
debug('get', cacheKey, 'had stale tag')
79+
6680
return undefined
6781
}
6882
const [returnStream, newSaved] = entry.value.tee()
6983
entry.value = newSaved
7084

85+
debug('get', cacheKey, 'found', {
86+
tags: entry.tags,
87+
timestamp: entry.timestamp,
88+
revalidate: entry.revalidate,
89+
expire: entry.expire,
90+
})
91+
7192
return {
7293
...entry,
7394
value: returnStream,
7495
}
7596
},
7697

7798
async set(cacheKey, pendingEntry) {
99+
debug('set', cacheKey, 'start')
100+
78101
let resolvePending: () => void = () => {}
79102
const pendingPromise = new Promise<void>((resolve) => {
80103
resolvePending = resolve
@@ -100,8 +123,11 @@ const DefaultCacheHandler: CacheHandlerV2 = {
100123
errorRetryCount: 0,
101124
size,
102125
})
103-
} catch {
126+
127+
debug('set', cacheKey, 'done')
128+
} catch (err) {
104129
// TODO: store partial buffer with error after we retry 3 times
130+
debug('set', cacheKey, 'failed', err)
105131
} finally {
106132
resolvePending()
107133
pendingSets.delete(cacheKey)
@@ -113,11 +139,18 @@ const DefaultCacheHandler: CacheHandlerV2 = {
113139
},
114140

115141
async getExpiration(...tags) {
116-
return Math.max(...tags.map((tag) => tagsManifest.get(tag) ?? 0))
142+
const expiration = Math.max(
143+
...tags.map((tag) => tagsManifest.get(tag) ?? 0)
144+
)
145+
146+
debug('getExpiration', { tags, expiration })
147+
148+
return expiration
117149
},
118150

119151
async expireTags(...tags) {
120152
const timestamp = Math.round(performance.timeOrigin + performance.now())
153+
debug('expireTags', { tags, timestamp })
121154

122155
for (const tag of tags) {
123156
// TODO: update file-system-cache?

packages/next/src/server/use-cache/use-cache-wrapper.ts

+29
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ export interface UseCachePageComponentProps {
6666

6767
const isEdgeRuntime = process.env.NEXT_RUNTIME === 'edge'
6868

69+
const debug = process.env.NEXT_PRIVATE_DEBUG_CACHE
70+
? console.debug.bind(console, 'use-cache:')
71+
: () => {}
72+
6973
function generateCacheEntry(
7074
workStore: WorkStore,
7175
outerWorkUnitStore: WorkUnitStore | undefined,
@@ -716,6 +720,7 @@ export function cache(
716720
entry &&
717721
(await shouldDiscardCacheEntry(entry, workStore, implicitTags))
718722
) {
723+
debug('discarding stale entry', serializedCacheKey)
719724
entry = undefined
720725
}
721726

@@ -756,6 +761,19 @@ export function cache(
756761
// Note: It is important that we await at least once before this because it lets us
757762
// pop out of any stack specific contexts as well - aka "Sync" Local Storage.
758763

764+
if (entry) {
765+
if (currentTime > entry.timestamp + entry.expire * 1000) {
766+
debug('entry is expired', serializedCacheKey)
767+
}
768+
769+
if (
770+
workStore.isStaticGeneration &&
771+
currentTime > entry.timestamp + entry.revalidate * 1000
772+
) {
773+
debug('static generation, entry is stale', serializedCacheKey)
774+
}
775+
}
776+
759777
const [newStream, pendingCacheEntry] = await generateCacheEntry(
760778
workStore,
761779
workUnitStore,
@@ -942,6 +960,13 @@ async function shouldDiscardCacheEntry(
942960
// If the cache entry was created before any of the implicit tags were
943961
// revalidated last, we also need to discard it.
944962
if (entry.timestamp <= (await implicitTags.expiration)) {
963+
debug(
964+
'entry was created at',
965+
entry.timestamp,
966+
'before implicit tags were revalidated at',
967+
implicitTags.expiration
968+
)
969+
945970
return true
946971
}
947972

@@ -962,13 +987,17 @@ function isRecentlyRevalidatedTag(tag: string, workStore: WorkStore): boolean {
962987

963988
// Was the tag previously revalidated (e.g. by a redirecting server action)?
964989
if (previouslyRevalidatedTags.includes(tag)) {
990+
debug('tag', tag, 'was previously revalidated')
991+
965992
return true
966993
}
967994

968995
// It could also have been revalidated by the currently running server action.
969996
// In this case the revalidation might not have been propagated to the cache
970997
// handler yet, so we read it from the pending tags in the work store.
971998
if (pendingRevalidatedTags?.includes(tag)) {
999+
debug('tag', tag, 'was just revalidated')
1000+
9721001
return true
9731002
}
9741003

0 commit comments

Comments
 (0)