-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
test(cloudflare): Reduce flakiness for cloudflare with sub workers #20632
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
81c275a
f96420b
70535eb
952baff
87dbe46
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -116,7 +116,6 @@ export function createRunner(...paths: string[]) { | |
| let envelopeCount = 0; | ||
| const envelopeWaiters: { expected: Expected; resolve: () => void; reject: (e: unknown) => void }[] = []; | ||
| const { resolve: setWorkerPort, promise: workerPortPromise } = deferredPromise<number>(); | ||
| const { resolve: setSubWorkerPort, promise: subWorkerPortPromise, reject: rejectSubWorker } = deferredPromise<number>(); | ||
| let child: ReturnType<typeof spawn> | undefined; | ||
| let childSubWorker: ReturnType<typeof spawn> | undefined; | ||
|
|
||
|
|
@@ -209,22 +208,33 @@ export function createRunner(...paths: string[]) { | |
|
|
||
| if (process.env.DEBUG) log('Starting scenario', testPath); | ||
|
|
||
| const stdio: ('inherit' | 'ipc' | 'ignore')[] = process.env.DEBUG | ||
| ? ['inherit', 'inherit', 'inherit', 'ipc'] | ||
| : ['ignore', 'ignore', 'ignore', 'ipc']; | ||
|
|
||
| const onChildError = (e: Error) => { | ||
| // eslint-disable-next-line no-console | ||
| console.error('Error starting child process:', e); | ||
| reject(e); | ||
| }; | ||
|
|
||
| function onChildMessage(message: string, onReady: (port: number) => void): void { | ||
| const msg = JSON.parse(message) as { event: string; port?: number }; | ||
| if (msg.event === 'DEV_SERVER_READY' && typeof msg.port === 'number') { | ||
| if (process.env.DEBUG) log('worker ready on port', msg.port); | ||
| onReady(msg.port); | ||
| } | ||
| // Inspired by workers-sdk: https://github.com/cloudflare/workers-sdk/blob/main/packages/wrangler/e2e/helpers/wrangler.ts | ||
| function waitForReady(childProcess: ReturnType<typeof spawn>): Promise<number> { | ||
| return new Promise((resolve, reject) => { | ||
| const stdout = childProcess.stdout; | ||
| if (!stdout) { | ||
| reject(new Error('No stdout available')); | ||
| return; | ||
| } | ||
|
|
||
| let output = ''; | ||
| stdout.on('data', (chunk: Buffer) => { | ||
| const text = chunk.toString(); | ||
| if (process.env.DEBUG) process.stdout.write(text); | ||
| output += text; | ||
|
|
||
| const match = output.match(/Ready on (https?:\/\/[^\s]+)/); | ||
| if (match?.[1]) { | ||
| resolve(parseInt(new URL(match[1]).port, 10)); | ||
| } | ||
| }); | ||
| }); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| } | ||
|
|
||
| if (existsSync(join(testPath, 'wrangler-sub-worker.jsonc'))) { | ||
|
|
@@ -243,17 +253,15 @@ export function createRunner(...paths: string[]) { | |
| '--inspector-port', | ||
| '0', | ||
| ], | ||
| { stdio, signal }, | ||
| { stdio: ['ignore', 'pipe', 'inherit'], signal }, | ||
| ); | ||
|
|
||
| childSubWorker.on('message', (msg: string) => onChildMessage(msg, setSubWorkerPort)); | ||
| childSubWorker.on('error', rejectSubWorker); | ||
| childSubWorker.on('error', onChildError); | ||
| childSubWorker.on('exit', code => { | ||
| rejectSubWorker(new Error(`Sub-worker exited with code ${code}`)); | ||
| onChildError(new Error(`Sub-worker exited with code ${code}`)); | ||
| }); | ||
|
|
||
| // Wait for the sub-worker to be ready before starting the main worker | ||
| await subWorkerPortPromise; | ||
| await waitForReady(childSubWorker); | ||
| } | ||
|
|
||
| child = spawn( | ||
|
|
@@ -274,7 +282,7 @@ export function createRunner(...paths: string[]) { | |
| '0', | ||
| ...extraWranglerArgs, | ||
| ], | ||
| { stdio, signal }, | ||
| { stdio: ['ignore', 'pipe', 'inherit'], signal }, | ||
| ); | ||
|
|
||
| CLEANUP_STEPS.add(() => { | ||
|
|
@@ -284,7 +292,7 @@ export function createRunner(...paths: string[]) { | |
|
|
||
| childSubWorker?.on('error', onChildError); | ||
| child.on('error', onChildError); | ||
| child.on('message', (msg: string) => onChildMessage(msg, setWorkerPort)); | ||
| waitForReady(child).then(setWorkerPort).catch(reject); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Duplicate error handler registered on sub-worker processLow Severity The Additional Locations (1)Reviewed by Cursor Bugbot for commit 952baff. Configure here.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Whoops, forgot to change that part of the code |
||
| }) | ||
| .catch(e => reject(e)); | ||
|
|
||
|
|
||


There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: The
waitForReadyfunction can hang indefinitely because it lacks anexitevent handler for the child process. If the process exits before it's ready, tests will time out.Severity: MEDIUM
Suggested Fix
Add an
on('exit', ...)event handler to thechildprocess within thewaitForReadyfunction. This handler should reject the promise if the process exits before the 'Ready on' message is received, ensuring that tests fail fast with a clear error instead of timing out. A similar implementation exists for thechildSubWorkerwhich can be used as a reference.Prompt for AI Agent
Did we get this right? 👍 / 👎 to inform future reviews.