Skip to content

Commit c6a8699

Browse files
committed
fix: track revalidate / cdn purge to ensure it finishes execution and is not suspended mid-execution
1 parent 063027c commit c6a8699

File tree

3 files changed

+33
-9
lines changed

3 files changed

+33
-9
lines changed

src/run/handlers/cache.cts

+21-7
Original file line numberDiff line numberDiff line change
@@ -244,19 +244,33 @@ export class NetlifyCacheHandler implements CacheHandler {
244244
if (requestContext?.didPagesRouterOnDemandRevalidate) {
245245
const tag = `_N_T_${key === '/index' ? '/' : key}`
246246
getLogger().debug(`Purging CDN cache for: [${tag}]`)
247-
purgeCache({ tags: [tag] }).catch((error) => {
248-
// TODO: add reporting here
249-
getLogger()
250-
.withError(error)
251-
.error(`[NetlifyCacheHandler]: Purging the cache for tag ${tag} failed`)
252-
})
247+
requestContext.trackBackgroundWork(
248+
purgeCache({ tags: [tag] }).catch((error) => {
249+
// TODO: add reporting here
250+
getLogger()
251+
.withError(error)
252+
.error(`[NetlifyCacheHandler]: Purging the cache for tag ${tag} failed`)
253+
}),
254+
)
253255
}
254256
}
255257
})
256258
}
257259

258260
// eslint-disable-next-line @typescript-eslint/no-explicit-any
259261
async revalidateTag(tagOrTags: string | string[], ...args: any) {
262+
const revalidateTagPromise = this.doRevalidateTag(tagOrTags, ...args)
263+
264+
const requestContext = getRequestContext()
265+
if (requestContext) {
266+
requestContext.trackBackgroundWork(revalidateTagPromise)
267+
}
268+
269+
return revalidateTagPromise
270+
}
271+
272+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
273+
private async doRevalidateTag(tagOrTags: string | string[], ...args: any) {
260274
getLogger().withFields({ tagOrTags, args }).debug('NetlifyCacheHandler.revalidateTag')
261275

262276
const tags = Array.isArray(tagOrTags) ? tagOrTags : [tagOrTags]
@@ -275,7 +289,7 @@ export class NetlifyCacheHandler implements CacheHandler {
275289
}),
276290
)
277291

278-
purgeCache({ tags }).catch((error) => {
292+
await purgeCache({ tags }).catch((error) => {
279293
// TODO: add reporting here
280294
getLogger()
281295
.withError(error)

src/run/revalidate.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { ServerResponse } from 'node:http'
2+
import { isPromise } from 'node:util/types'
23

34
import type { RequestContext } from './handlers/request-context.cjs'
45

@@ -12,7 +13,13 @@ export const nextResponseProxy = (res: ServerResponse, requestContext: RequestCo
1213
// eslint-disable-next-line @typescript-eslint/no-explicit-any
1314
return async function newRevalidate(...args: any[]) {
1415
requestContext.didPagesRouterOnDemandRevalidate = true
15-
return originalValue?.apply(target, args)
16+
17+
const result = originalValue?.apply(target, args)
18+
if (result && isPromise(result)) {
19+
requestContext.trackBackgroundWork(result)
20+
}
21+
22+
return result
1623
}
1724
}
1825
return originalValue

tests/fixtures/page-router/pages/api/revalidate.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
export default async function handler(req, res) {
22
try {
3-
await res.revalidate('/static/revalidate-manual')
3+
// res.revalidate returns a promise that can be awaited to wait for the revalidation to complete
4+
// if user doesn't await it, we still want to ensure the revalidation is completed, so we internally track
5+
// this as "background work" to ensure it completes before function suspends execution
6+
res.revalidate('/static/revalidate-manual')
47
return res.json({ code: 200, message: 'success' })
58
} catch (err) {
69
return res.status(500).send({ code: 500, message: err.message })

0 commit comments

Comments
 (0)