Skip to content

Commit d735d31

Browse files
authored
fix static worker restart behavior (#56728)
In [55841](#55841), this file was reworked to improve type safety and readability, but it changed the behavior of how we were invoking methods on the worker. Specifically, when a restart occurred, this timeout wrapping function was referencing an already ended worker, resulting in a "Farm is ended, no more calls can be done to it" build error. This PR ensures that we're fetching the method from the current `this._worker` at the time of invocation, not at the time of method creation. [Slack x-ref](https://vercel.slack.com/archives/C04KC8A53T7/p1697064752635179?thread_ts=1696952142.759769&cid=C04KC8A53T7)
1 parent f0dd49e commit d735d31

File tree

6 files changed

+50
-6
lines changed

6 files changed

+50
-6
lines changed

packages/next/src/lib/worker.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -133,9 +133,7 @@ export class Worker<T extends object = object, Args extends any[] = any[]> {
133133
}
134134

135135
const wrapMethodWithTimeout =
136-
<M extends (...args: unknown[]) => Promise<unknown> | unknown>(
137-
method: M
138-
) =>
136+
(methodName: keyof T) =>
139137
async (...args: Args) => {
140138
activeTasks++
141139

@@ -149,7 +147,8 @@ export class Worker<T extends object = object, Args extends any[] = any[]> {
149147
const result = await Promise.race([
150148
// Either we'll get the result from the worker, or we'll get the
151149
// restart promise to fire.
152-
method(...args),
150+
// @ts-expect-error - we're grabbing a dynamic method on the worker
151+
this._worker[methodName](...args),
153152
restartPromise,
154153
])
155154

@@ -160,7 +159,7 @@ export class Worker<T extends object = object, Args extends any[] = any[]> {
160159
}
161160

162161
// Otherwise, we'll need to restart the worker, and try again.
163-
if (onRestart) onRestart(method.name, args, ++attempts)
162+
if (onRestart) onRestart(methodName.toString(), args, ++attempts)
164163
}
165164
} finally {
166165
activeTasks--
@@ -174,7 +173,7 @@ export class Worker<T extends object = object, Args extends any[] = any[]> {
174173
// @ts-expect-error - we're grabbing a dynamic method on the worker
175174
let method = this._worker[name].bind(this._worker)
176175
if (timeout) {
177-
method = wrapMethodWithTimeout(method)
176+
method = wrapMethodWithTimeout(name)
178177
}
179178

180179
// @ts-expect-error - we're dynamically creating methods
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
export async function generateMetadata() {
2+
await new Promise((resolve) => setTimeout(resolve, 11000))
3+
4+
return {
5+
title: 'Test',
6+
}
7+
}
8+
9+
export default function Page() {
10+
return <div>Hello World</div>
11+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export default function Layout({ children }) {
2+
return (
3+
<html>
4+
<body>{children}</body>
5+
</html>
6+
)
7+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default function Page() {
2+
return <div>Root Page</div>
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports = {
2+
staticPageGenerationTimeout: 10,
3+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { nextBuild } from 'next-test-utils'
2+
3+
describe('worker-restart', () => {
4+
it('should properly exhaust all restart attempts and not fail with any worker errors', async () => {
5+
const { stdout, stderr } = await nextBuild(__dirname, [], {
6+
stdout: true,
7+
stderr: true,
8+
})
9+
10+
const output = stdout + stderr
11+
expect(output).toContain(
12+
'Restarted static page generation for /bad-page because it took more than 10 seconds'
13+
)
14+
expect(output).toContain(
15+
'Static page generation for /bad-page is still timing out after 3 attempts'
16+
)
17+
expect(output).not.toContain(
18+
'Error: Farm is ended, no more calls can be done to it'
19+
)
20+
})
21+
})

0 commit comments

Comments
 (0)