From 9954a21c94de8e81b0736bee67ae2645120cb97b Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Thu, 2 May 2024 19:27:29 -0700 Subject: [PATCH] Update revalidateTag to batch tags in one request (#65296) As discussed this collects all `revalidateTag` calls and invokes in a single request to avoid race conditions and overhead from multiple pending requests. x-ref: [slack thread](https://vercel.slack.com/archives/C0676QZBWKS/p1714688045037509?thread_ts=1710902198.529179&cid=C0676QZBWKS) Closes NEXT-3306 --- .../src/server/app-render/action-handler.ts | 27 ++++++++++++------- .../next/src/server/app-render/app-render.tsx | 9 ++++--- .../future/route-modules/app-route/module.ts | 13 +++++---- .../server/web/spec-extension/revalidate.ts | 9 ------- 4 files changed, 32 insertions(+), 26 deletions(-) diff --git a/packages/next/src/server/app-render/action-handler.ts b/packages/next/src/server/app-render/action-handler.ts index 55c0234ec8933..6e404ca2a247e 100644 --- a/packages/next/src/server/app-render/action-handler.ts +++ b/packages/next/src/server/app-render/action-handler.ts @@ -117,9 +117,12 @@ async function addRevalidationHeader( requestStore: RequestStore } ) { - await Promise.all( - Object.values(staticGenerationStore.pendingRevalidates || []) - ) + await Promise.all([ + staticGenerationStore.incrementalCache?.revalidateTag( + staticGenerationStore.revalidatedTags || [] + ), + ...Object.values(staticGenerationStore.pendingRevalidates || {}), + ]) // If a tag was revalidated, the client router needs to invalidate all the // client router cache as they may be stale. And if a path was revalidated, the @@ -481,9 +484,12 @@ export async function handleAction({ if (isFetchAction) { res.statusCode = 500 - await Promise.all( - Object.values(staticGenerationStore.pendingRevalidates || []) - ) + await Promise.all([ + staticGenerationStore.incrementalCache?.revalidateTag( + staticGenerationStore.revalidatedTags || [] + ), + ...Object.values(staticGenerationStore.pendingRevalidates || {}), + ]) const promise = Promise.reject(error) try { @@ -840,9 +846,12 @@ To configure the body size limit for Server Actions, see: https://nextjs.org/doc if (isFetchAction) { res.statusCode = 500 - await Promise.all( - Object.values(staticGenerationStore.pendingRevalidates || []) - ) + await Promise.all([ + staticGenerationStore.incrementalCache?.revalidateTag( + staticGenerationStore.revalidatedTags || [] + ), + ...Object.values(staticGenerationStore.pendingRevalidates || {}), + ]) const promise = Promise.reject(err) try { // we need to await the promise to trigger the rejection early diff --git a/packages/next/src/server/app-render/app-render.tsx b/packages/next/src/server/app-render/app-render.tsx index d192970eec658..c175ab6b75a80 100644 --- a/packages/next/src/server/app-render/app-render.tsx +++ b/packages/next/src/server/app-render/app-render.tsx @@ -1350,9 +1350,12 @@ async function renderToHTMLOrFlightImpl( // If we have pending revalidates, wait until they are all resolved. if (staticGenerationStore.pendingRevalidates) { - options.waitUntil = Promise.all( - Object.values(staticGenerationStore.pendingRevalidates) - ) + options.waitUntil = Promise.all([ + staticGenerationStore.incrementalCache?.revalidateTag( + staticGenerationStore.revalidatedTags || [] + ), + ...Object.values(staticGenerationStore.pendingRevalidates || {}), + ]) } addImplicitTags(staticGenerationStore) diff --git a/packages/next/src/server/future/route-modules/app-route/module.ts b/packages/next/src/server/future/route-modules/app-route/module.ts index eec53d36666f5..69f786e94ddf0 100644 --- a/packages/next/src/server/future/route-modules/app-route/module.ts +++ b/packages/next/src/server/future/route-modules/app-route/module.ts @@ -383,11 +383,14 @@ export class AppRouteRouteModule extends RouteModule< context.renderOpts.fetchMetrics = staticGenerationStore.fetchMetrics - context.renderOpts.waitUntil = Promise.all( - Object.values( - staticGenerationStore.pendingRevalidates || [] - ) - ) + context.renderOpts.waitUntil = Promise.all([ + staticGenerationStore.incrementalCache?.revalidateTag( + staticGenerationStore.revalidatedTags || [] + ), + ...Object.values( + staticGenerationStore.pendingRevalidates || {} + ), + ]) addImplicitTags(staticGenerationStore) ;(context.renderOpts as any).fetchTags = diff --git a/packages/next/src/server/web/spec-extension/revalidate.ts b/packages/next/src/server/web/spec-extension/revalidate.ts index ef10e466fe07f..00996c7d188f2 100644 --- a/packages/next/src/server/web/spec-extension/revalidate.ts +++ b/packages/next/src/server/web/spec-extension/revalidate.ts @@ -68,15 +68,6 @@ function revalidate(tag: string, expression: string) { store.revalidatedTags.push(tag) } - if (!store.pendingRevalidates) { - store.pendingRevalidates = {} - } - store.pendingRevalidates[tag] = store.incrementalCache - .revalidateTag?.(tag) - .catch((err) => { - console.error(`revalidate failed for ${tag}`, err) - }) - // TODO: only revalidate if the path matches store.pathWasRevalidated = true }