Skip to content

Commit

Permalink
Expire loading state cache separately from cache node data
Browse files Browse the repository at this point in the history
  • Loading branch information
ztanner committed Feb 22, 2024
1 parent 1c7b81e commit a1a0542
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ import type {
import { invalidateCacheByRouterState } from './invalidate-cache-by-router-state'
import { fillLazyItemsTillLeafWithHead } from './fill-lazy-items-till-leaf-with-head'
import { createRouterCacheKey } from './create-router-cache-key'
import type { PrefetchCacheEntry } from './router-reducer-types'
import {
PrefetchCacheEntryStatus,
type PrefetchCacheEntry,
} from './router-reducer-types'

/**
* Fill cache with rsc based on flightDataPath
Expand Down Expand Up @@ -49,11 +52,18 @@ export function fillCacheWithNewSubTreeData(
const seedData: CacheNodeSeedData = flightDataPath[3]
const rsc = seedData[2]
const loading = seedData[3]
const canReuseLoadingState =
prefetchEntry?.loadingStatus === PrefetchCacheEntryStatus.reusable

childCacheNode = {
lazyData: null,
rsc,
prefetchRsc: null,
loading,
// Preserve the existing loading node if it exists
loading:
canReuseLoadingState && existingChildCacheNode?.loading
? existingChildCacheNode?.loading
: loading,
// Ensure segments other than the one we got data for are preserved.
parallelRoutes: existingChildCacheNode
? new Map(existingChildCacheNode.parallelRoutes)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ export function getOrCreatePrefetchCacheEntry({
if (existingCacheEntry) {
// Grab the latest status of the cache entry and update it
existingCacheEntry.status = getPrefetchEntryCacheStatus(existingCacheEntry)
existingCacheEntry.loadingStatus = getLoadingCacheStatus(
existingCacheEntry.renewalTime
)

// when `kind` is provided, an explicit prefetch was requested.
// if the requested prefetch is "full" and the current cache entry wasn't, we want to re-prefetch with the new intent
Expand All @@ -91,6 +94,7 @@ export function getOrCreatePrefetchCacheEntry({
buildId,
nextUrl,
prefetchCache,
isRenewal: true,
// If we didn't get an explicit prefetch kind, we want to set a temporary kind
// rather than assuming the same intent as the previous entry, to be consistent with how we
// lazily create prefetch entries when intent is left unspecified.
Expand Down Expand Up @@ -174,8 +178,10 @@ export function createPrefetchCacheEntryForInitialLoad({
kind,
prefetchTime: Date.now(),
lastUsedTime: null,
renewalTime: null,
key: prefetchCacheKey,
status: PrefetchCacheEntryStatus.fresh,
loadingStatus: null,
}

prefetchCache.set(prefetchCacheKey, prefetchEntry)
Expand All @@ -193,12 +199,14 @@ function createLazyPrefetchEntry({
nextUrl,
buildId,
prefetchCache,
isRenewal,
}: Pick<
ReadonlyReducerState,
'nextUrl' | 'tree' | 'buildId' | 'prefetchCache'
> & {
url: URL
kind: PrefetchKind
isRenewal?: boolean
}): PrefetchCacheEntry {
const prefetchCacheKey = createPrefetchCacheKey(url)

Expand Down Expand Up @@ -226,8 +234,10 @@ function createLazyPrefetchEntry({
kind,
prefetchTime: Date.now(),
lastUsedTime: null,
renewalTime: isRenewal ? Date.now() : null,
key: prefetchCacheKey,
status: PrefetchCacheEntryStatus.fresh,
loadingStatus: PrefetchCacheEntryStatus.fresh,
}

prefetchCache.set(prefetchCacheKey, prefetchEntry)
Expand All @@ -251,6 +261,24 @@ export function prunePrefetchCache(
const FIVE_MINUTES = 5 * 60 * 1000
const THIRTY_SECONDS = 30 * 1000

/**
* This function is used to determine the cache status of the loading state of a prefetch cache entry.
*/
function getLoadingCacheStatus(time: number | null) {
if (!time) {
return PrefetchCacheEntryStatus.fresh
}

if (Date.now() < time + FIVE_MINUTES) {
return PrefetchCacheEntryStatus.reusable
}

return PrefetchCacheEntryStatus.expired
}

/**
* This function is used to determine the cache status of the data of a prefetch cache entry.
*/
function getPrefetchEntryCacheStatus({
kind,
prefetchTime,
Expand All @@ -263,14 +291,14 @@ function getPrefetchEntryCacheStatus({
: PrefetchCacheEntryStatus.fresh
}

// if the cache entry was prefetched less than 5 mins ago, then we want to re-use only the loading state
// if the cache entry was prefetched greater than 30s ago but less than 5 mins ago, then it's stale
if (kind === 'auto') {
if (Date.now() < prefetchTime + FIVE_MINUTES) {
return PrefetchCacheEntryStatus.stale
}
}

// if the cache entry was prefetched less than 5 mins ago and was a "full" prefetch, then we want to re-use it "full
// if the cache entry was prefetched less than 5 mins ago and was a "full" prefetch, then we want to re-use it
if (kind === 'full') {
if (Date.now() < prefetchTime + FIVE_MINUTES) {
return PrefetchCacheEntryStatus.reusable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,9 @@ describe('navigateReducer', () => {
"key": "/linking",
"kind": "auto",
"lastUsedTime": null,
"loadingStatus": null,
"prefetchTime": 1690329600000,
"renewalTime": null,
"status": "fresh",
"treeAtTimeOfPrefetch": [
"",
Expand All @@ -290,7 +292,9 @@ describe('navigateReducer', () => {
"key": "/linking/about",
"kind": "temporary",
"lastUsedTime": 1690329600000,
"loadingStatus": "fresh",
"prefetchTime": 1690329600000,
"renewalTime": null,
"status": "fresh",
"treeAtTimeOfPrefetch": [
"",
Expand Down Expand Up @@ -492,7 +496,9 @@ describe('navigateReducer', () => {
"key": "/linking",
"kind": "auto",
"lastUsedTime": null,
"loadingStatus": null,
"prefetchTime": 1690329600000,
"renewalTime": null,
"status": "fresh",
"treeAtTimeOfPrefetch": [
"",
Expand All @@ -517,7 +523,9 @@ describe('navigateReducer', () => {
"key": "/linking/about",
"kind": "temporary",
"lastUsedTime": 1690329600000,
"loadingStatus": "fresh",
"prefetchTime": 1690329600000,
"renewalTime": null,
"status": "fresh",
"treeAtTimeOfPrefetch": [
"",
Expand Down Expand Up @@ -689,7 +697,9 @@ describe('navigateReducer', () => {
"key": "/linking",
"kind": "auto",
"lastUsedTime": null,
"loadingStatus": null,
"prefetchTime": 1690329600000,
"renewalTime": null,
"status": "fresh",
"treeAtTimeOfPrefetch": [
"",
Expand Down Expand Up @@ -856,7 +866,9 @@ describe('navigateReducer', () => {
"key": "/linking",
"kind": "auto",
"lastUsedTime": null,
"loadingStatus": null,
"prefetchTime": 1690329600000,
"renewalTime": null,
"status": "fresh",
"treeAtTimeOfPrefetch": [
"",
Expand Down Expand Up @@ -1020,7 +1032,9 @@ describe('navigateReducer', () => {
"key": "/linking",
"kind": "auto",
"lastUsedTime": 1690329600000,
"loadingStatus": "fresh",
"prefetchTime": 1690329600000,
"renewalTime": null,
"status": "fresh",
"treeAtTimeOfPrefetch": [
"",
Expand Down Expand Up @@ -1254,7 +1268,9 @@ describe('navigateReducer', () => {
"key": "/linking",
"kind": "auto",
"lastUsedTime": null,
"loadingStatus": null,
"prefetchTime": 1690329600000,
"renewalTime": null,
"status": "fresh",
"treeAtTimeOfPrefetch": [
"",
Expand All @@ -1279,7 +1295,9 @@ describe('navigateReducer', () => {
"key": "/linking/about",
"kind": "auto",
"lastUsedTime": 1690329600000,
"loadingStatus": "fresh",
"prefetchTime": 1690329600000,
"renewalTime": null,
"status": "fresh",
"treeAtTimeOfPrefetch": [
"",
Expand Down Expand Up @@ -1545,7 +1563,9 @@ describe('navigateReducer', () => {
"key": "/parallel-tab-bar",
"kind": "auto",
"lastUsedTime": null,
"loadingStatus": null,
"prefetchTime": 1690329600000,
"renewalTime": null,
"status": "fresh",
"treeAtTimeOfPrefetch": [
"",
Expand Down Expand Up @@ -1578,7 +1598,9 @@ describe('navigateReducer', () => {
"key": "/parallel-tab-bar/demographics",
"kind": "temporary",
"lastUsedTime": 1690329600000,
"loadingStatus": "fresh",
"prefetchTime": 1690329600000,
"renewalTime": null,
"status": "fresh",
"treeAtTimeOfPrefetch": [
"",
Expand Down Expand Up @@ -1763,7 +1785,9 @@ describe('navigateReducer', () => {
"key": "/linking",
"kind": "auto",
"lastUsedTime": null,
"loadingStatus": null,
"prefetchTime": 1690329600000,
"renewalTime": null,
"status": "fresh",
"treeAtTimeOfPrefetch": [
"",
Expand Down Expand Up @@ -1959,7 +1983,9 @@ describe('navigateReducer', () => {
"key": "/linking",
"kind": "auto",
"lastUsedTime": null,
"loadingStatus": null,
"prefetchTime": 1690329600000,
"renewalTime": null,
"status": "fresh",
"treeAtTimeOfPrefetch": [
"",
Expand All @@ -1984,7 +2010,9 @@ describe('navigateReducer', () => {
"key": "/linking/about",
"kind": "temporary",
"lastUsedTime": 1690329600000,
"loadingStatus": "fresh",
"prefetchTime": 1690329600000,
"renewalTime": null,
"status": "fresh",
"treeAtTimeOfPrefetch": [
"",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,10 @@ describe('prefetchReducer', () => {
prefetchTime: expect.any(Number),
kind: PrefetchKind.AUTO,
lastUsedTime: null,
renewalTime: null,
treeAtTimeOfPrefetch: initialTree,
status: PrefetchCacheEntryStatus.fresh,
loadingStatus: null,
},
],
[
Expand All @@ -173,8 +175,10 @@ describe('prefetchReducer', () => {
data: prom,
kind: PrefetchKind.AUTO,
lastUsedTime: null,
renewalTime: null,
prefetchTime: expect.any(Number),
status: PrefetchCacheEntryStatus.fresh,
loadingStatus: PrefetchCacheEntryStatus.fresh,
treeAtTimeOfPrefetch: [
'',
{
Expand Down Expand Up @@ -331,6 +335,8 @@ describe('prefetchReducer', () => {
treeAtTimeOfPrefetch: initialTree,
key: '/linking',
status: PrefetchCacheEntryStatus.fresh,
renewalTime: null,
loadingStatus: PrefetchCacheEntryStatus.fresh,
})

const expectedState: ReturnType<typeof prefetchReducer> = {
Expand All @@ -357,6 +363,8 @@ describe('prefetchReducer', () => {
kind: PrefetchKind.AUTO,
lastUsedTime: null,
status: PrefetchCacheEntryStatus.fresh,
loadingStatus: PrefetchCacheEntryStatus.fresh,
renewalTime: null,
treeAtTimeOfPrefetch: [
'',
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,9 @@ describe('serverPatchReducer', () => {
"key": "/linking/about",
"kind": "auto",
"lastUsedTime": null,
"loadingStatus": null,
"prefetchTime": 1690329600000,
"renewalTime": null,
"status": "fresh",
"treeAtTimeOfPrefetch": [
"",
Expand Down Expand Up @@ -492,7 +494,9 @@ describe('serverPatchReducer', () => {
"key": "/linking",
"kind": "auto",
"lastUsedTime": null,
"loadingStatus": null,
"prefetchTime": 1690329600000,
"renewalTime": null,
"status": "fresh",
"treeAtTimeOfPrefetch": [
"",
Expand Down Expand Up @@ -522,7 +526,9 @@ describe('serverPatchReducer', () => {
"key": "/linking/about",
"kind": "temporary",
"lastUsedTime": 1690329600000,
"loadingStatus": "fresh",
"prefetchTime": 1690329600000,
"renewalTime": null,
"status": "fresh",
"treeAtTimeOfPrefetch": [
"",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,8 +204,10 @@ export type PrefetchCacheEntry = {
kind: PrefetchKind
prefetchTime: number
lastUsedTime: number | null
renewalTime: number | null
key: string
status: PrefetchCacheEntryStatus
loadingStatus: PrefetchCacheEntryStatus | null
}

export enum PrefetchCacheEntryStatus {
Expand Down
4 changes: 1 addition & 3 deletions test/e2e/app-dir/app-client-cache/client-cache.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -373,9 +373,7 @@ createNextDescribe(
expect(newNumber).toBe(initialNumber)
})

// TODO: Rather than reusing parts of a stale prefetch cache entry to make this work,
// we should be able to copy over the existing loading from a previous cache node on navigation.
it.skip('should refetch below the fold after 30 seconds', async () => {
it('should refetch below the fold after 30 seconds', async () => {
const randomLoadingNumber = await browser
.elementByCss('[href="/1?timeout=1000"]')
.click()
Expand Down

0 comments on commit a1a0542

Please sign in to comment.