Skip to content

Commit fb2f105

Browse files
committed
feat: add more comments
1 parent cb6d36d commit fb2f105

File tree

3 files changed

+62
-88
lines changed

3 files changed

+62
-88
lines changed

src/DeduplicatedRequestHandler.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,7 @@ export class DeduplicatedRequestHandler<
3636

3737
// Method to handle deduplicated requests
3838
deduplicatedFunction = (key: string): T => {
39-
debug(
40-
'cyan',
39+
debugVerbose(
4140
'DeduplicatedRequestHandler.deduplicatedFunction() called with',
4241
key,
4342
);
@@ -83,8 +82,7 @@ export class DeduplicatedRequestHandler<
8382
try {
8483
const ts = performance.now();
8584
const result = await promise;
86-
debug(
87-
'cyan',
85+
debugVerbose(
8886
'DeduplicatedRequestHandler.deduplicatedFunction().dedupedFn ',
8987
key,
9088
'promise resolved (in ',

src/RedisStringsHandler.ts

Lines changed: 59 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ export default class RedisStringsHandler {
195195
this.redisDeduplicationHandler.deduplicatedFunction;
196196
}
197197

198-
resetRequestCache(): void {}
198+
resetRequestCache(): void { }
199199

200200
private async assertClientIsReady(): Promise<void> {
201201
await Promise.all([
@@ -211,19 +211,19 @@ export default class RedisStringsHandler {
211211
key: string,
212212
ctx:
213213
| {
214-
kind: 'APP_ROUTE' | 'APP_PAGE';
215-
isRoutePPREnabled: boolean;
216-
isFallback: boolean;
217-
}
214+
kind: 'APP_ROUTE' | 'APP_PAGE';
215+
isRoutePPREnabled: boolean;
216+
isFallback: boolean;
217+
}
218218
| {
219-
kind: 'FETCH';
220-
revalidate: number;
221-
fetchUrl: string;
222-
fetchIdx: number;
223-
tags: string[];
224-
softTags: string[];
225-
isFallback: boolean;
226-
},
219+
kind: 'FETCH';
220+
revalidate: number;
221+
fetchUrl: string;
222+
fetchIdx: number;
223+
tags: string[];
224+
softTags: string[];
225+
isFallback: boolean;
226+
},
227227
): Promise<CacheEntry | null> {
228228
if (
229229
ctx.kind !== 'APP_ROUTE' &&
@@ -310,9 +310,11 @@ export default class RedisStringsHandler {
310310
return cacheEntry;
311311
}
312312

313-
// This code checks if any of the cache tags associated with this entry have been revalidated
314-
// since the entry was last modified. If any tag was revalidated more recently than the entry's
315-
// lastModified timestamp, then the cached content is considered stale and should be removed.
313+
// INFO: implicit tags (revalidate of nested fetch in api route/page on revalidatePath call of the page/api route). See revalidateTag() for more information
314+
//
315+
// This code checks if any of the cache tags associated with this entry (normally the internal tag of the parent page/api route containing the fetch request)
316+
// have been revalidated since the entry was last modified. If any tag was revalidated more recently than the entry's
317+
// lastModified timestamp, then the cached content is considered stale (therefore return null) and should be removed.
316318
for (const tag of combinedTags) {
317319
// Get the last revalidation time for this tag from our revalidatedTagsMap
318320
const revalidationTime = this.revalidatedTagsMap.get(tag);
@@ -364,37 +366,37 @@ export default class RedisStringsHandler {
364366
key: string,
365367
data:
366368
| {
367-
kind: 'APP_PAGE';
368-
status: number;
369-
headers: {
370-
'x-nextjs-stale-time': string; // timestamp in ms
371-
'x-next-cache-tags': string; // comma separated paths (tags)
372-
};
373-
html: string;
374-
rscData: Buffer;
375-
segmentData: unknown;
376-
postboned: unknown;
377-
}
369+
kind: 'APP_PAGE';
370+
status: number;
371+
headers: {
372+
'x-nextjs-stale-time': string; // timestamp in ms
373+
'x-next-cache-tags': string; // comma separated paths (tags)
374+
};
375+
html: string;
376+
rscData: Buffer;
377+
segmentData: unknown;
378+
postboned: unknown;
379+
}
378380
| {
379-
kind: 'APP_ROUTE';
380-
status: number;
381-
headers: {
382-
'cache-control'?: string;
383-
'x-nextjs-stale-time': string; // timestamp in ms
384-
'x-next-cache-tags': string; // comma separated paths (tags)
385-
};
386-
body: Buffer;
387-
}
381+
kind: 'APP_ROUTE';
382+
status: number;
383+
headers: {
384+
'cache-control'?: string;
385+
'x-nextjs-stale-time': string; // timestamp in ms
386+
'x-next-cache-tags': string; // comma separated paths (tags)
387+
};
388+
body: Buffer;
389+
}
388390
| {
389-
kind: 'FETCH';
390-
data: {
391-
headers: Record<string, string>;
392-
body: string; // base64 encoded
393-
status: number;
394-
url: string;
395-
};
396-
revalidate: number | false;
397-
},
391+
kind: 'FETCH';
392+
data: {
393+
headers: Record<string, string>;
394+
body: string; // base64 encoded
395+
status: number;
396+
url: string;
397+
};
398+
revalidate: number | false;
399+
},
398400
ctx: {
399401
revalidate: number | false;
400402
isRoutePPREnabled: boolean;
@@ -444,8 +446,8 @@ export default class RedisStringsHandler {
444446
// Constructing the expire time for the cache entry
445447
const expireAt =
446448
ctx.revalidate &&
447-
Number.isSafeInteger(ctx.revalidate) &&
448-
ctx.revalidate > 0
449+
Number.isSafeInteger(ctx.revalidate) &&
450+
ctx.revalidate > 0
449451
? this.estimateExpireAge(ctx.revalidate)
450452
: this.estimateExpireAge(this.defaultStaleAge);
451453

@@ -465,6 +467,8 @@ export default class RedisStringsHandler {
465467
'RedisStringsHandler.set() will set the following serializedCacheEntry',
466468
this.keyPrefix,
467469
key,
470+
data,
471+
ctx,
468472
serializedCacheEntry?.substring(0, 200),
469473
expireAt,
470474
);
@@ -510,43 +514,15 @@ export default class RedisStringsHandler {
510514
// find all keys that are related to this tag
511515
const keysToDelete: Set<string> = new Set();
512516

513-
// TODO right now this code is only tested for calls with revalidatePath. We need to test this code for calls with revalidateTag as well
514-
// a call to revalidatePath will result in revalidateTag(_N_T_...) -> therefore we could check of tagOrTags.startsWith(_N_T_) to only execute this code for revalidatePath calls
515-
516517
for (const tag of tags) {
517-
// If a page has a fetch request inside. This fetch request needs to be revalidated as well. This is done by the following code
518-
// sharedTags are containing all directly dependent tags. Need to find out the keys for these tags
519-
const sharedTags = this.sharedTagsMap.get(
520-
tag.replace(NEXT_CACHE_IMPLICIT_TAG_ID, ''),
521-
);
522-
for (const sharedTag of sharedTags || []) {
523-
// Implicit tags are not stored in cache therefore we can ignore them and only look at the non-implicit tags
524-
if (!sharedTag.startsWith(NEXT_CACHE_IMPLICIT_TAG_ID)) {
525-
// For these non-implicit tags we then need to find the keys that are dependent on each of these tags
526-
for (const [
527-
dependentKey,
528-
sharedTagsForDependentKey,
529-
] of this.sharedTagsMap.entries()) {
530-
// We can do so by scanning the whole sharedTagsMap for keys that contain this tag in there sharedTags array
531-
if (sharedTagsForDependentKey.includes(sharedTag)) {
532-
keysToDelete.add(dependentKey);
533-
}
534-
}
535-
}
536-
}
537-
538-
debug(
539-
'red',
540-
'RedisStringsHandler.revalidateTag() directly dependent keys',
541-
tag,
542-
sharedTags?.filter(
543-
(tag) => !tag.startsWith(NEXT_CACHE_IMPLICIT_TAG_ID),
544-
) || [],
545-
);
546-
547-
// TODO check if this can be deleted with the new logic --> Seems like it can not be deleted --> above implementation only works for pages and not for api routes
548-
// For Next.js implicit tags (route-based), store the revalidation timestamp
549-
// This is used to track when routes were last invalidated
518+
// INFO: implicit tags (revalidate of nested fetch in api route/page on revalidatePath call of the page/api route)
519+
//
520+
// Invalidation logic for fetch requests that are related to a invalidated page.
521+
// revalidateTag is called for the page tag (_N_T_...) and the fetch request needs to be invalidated as well
522+
// unfortunately this is not possible since the revalidateTag is not called with any data that would allow us to find the cache entry of the fetch request
523+
// in case of a fetch request get method call, the get method of the cache handler is called with some information about the pages/routes the fetch request is inside
524+
// therefore we only mark the page/route as stale here (with help of the revalidatedTagsMap)
525+
// and delete the cache entry of the fetch request on the next request to the get function
550526
if (tag.startsWith(NEXT_CACHE_IMPLICIT_TAG_ID)) {
551527
const now = Date.now();
552528
debug(

test/integration/next-app/src/app/api/nested-fetch-in-api-route/revalidated-fetch/route.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export async function GET() {
1010
`http://localhost:${process.env.NEXT_START_PORT || 3000}/api/uncached-fetch`,
1111
{
1212
next: {
13-
revalidate: 3,
13+
revalidate: 15,
1414
tags: ['revalidated-fetch-revalidate15-nested-fetch-in-api-route'],
1515
},
1616
},

0 commit comments

Comments
 (0)