Skip to content

Commit

Permalink
Update revalidateTag to batch tags in one request (#65296)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
ijjk committed Sep 12, 2024
1 parent 937651f commit 9954a21
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 26 deletions.
27 changes: 18 additions & 9 deletions packages/next/src/server/app-render/action-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down
9 changes: 6 additions & 3 deletions packages/next/src/server/app-render/app-render.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down
9 changes: 0 additions & 9 deletions packages/next/src/server/web/spec-extension/revalidate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

0 comments on commit 9954a21

Please sign in to comment.