Skip to content

[vite-plugin] Fix flaky WebSocket upgrade test and harden upgrade handler - #14862

Merged
petebacondarwin merged 2 commits into
mainfrom
fix/vite-plugin-websocket-upgrade-flake
Jul 27, 2026
Merged

[vite-plugin] Fix flaky WebSocket upgrade test and harden upgrade handler#14862
petebacondarwin merged 2 commits into
mainfrom
fix/vite-plugin-websocket-upgrade-flake

Conversation

@petebacondarwin

@petebacondarwin petebacondarwin commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Deflakes the @cloudflare/vite-plugin WebSocket upgrade test on Windows CI, and fixes a latent unhandled-rejection bug it exposed.

Observed flake: Tests (Windows, packages-and-tools)handleWebSocket > does not forward framing headers from the Worker response:

  • AssertionError: expected '' to contain 'HTTP/1.1 101'
  • Error: Hook timed out in 10000ms (afterEach)
  • MiniflareCoreError [ERR_DISPOSED] unhandled rejection

Root cause: listen() never awaited miniflare.ready, so a cold workerd boot was charged against vi.waitFor's 1s default timeout instead of the 50s test timeout. On the contended Windows runner the boot exceeded 1s, so no bytes arrived. The test then threw before its socket.destroy(), so httpServer.close() hung on the live socket — and because this package's vitest config didn't extend the shared one, hookTimeout fell back to the 10s default (and there was no retry safety net). Finally, afterEach's dispose() rejected the still-pending dispatchFetch, and the async upgrade handler had no try/catch, surfacing the ERR_DISPOSED unhandled rejection.

Changes:

  • src/websockets.ts (real fix): wrap the upgrade handler in try/catch and destroy the socket on failure. Without this, a rejected dispatchFetch during dev-server shutdown/restart escapes the async listener as an unhandled rejection (can terminate the process) and leaks the client socket. This path is reachable in real vite dev/vite preview, not just tests.
  • src/__tests__/websockets.spec.ts: listen() awaits miniflare.ready (deterministic fix); Miniflare created per-test via a helper (no throwaway spawn); afterEach tears down tracked sockets and calls closeAllConnections() before closing the server so a failed assertion can't cascade into a hook timeout; explicit { timeout: 10_000 } on the two real round-trip waits; added a regression test asserting no unhandled rejection when dispatchFetch fails.
  • vitest.config.ts: extend vitest.shared.ts to inherit retry: 1, hookTimeout/teardownTimeout, etc.

Verification: websockets.spec.ts 9/9 pass; full package suite 179/179 across 18 files (confirms restoreMocks: true from the shared config regresses nothing); type-check, lint, and format clean. Removing the try/catch makes the new regression test hang the process, confirming it catches the bug.


  • Tests
    • Tests included/updated
    • Automated tests not possible - manual testing has been completed as follows:
    • Additional testing not necessary because:
  • Public documentation
    • Cloudflare docs PR(s):
    • Documentation not necessary because: internal test/robustness fix with no user-facing API or behavior change.

Note

This is a contribution from an AI agent: OpenCode, anthropic/claude-opus-4-8.


Open in Devin Review

@petebacondarwin petebacondarwin added the ci-flake Applied to PRs addressing CI flakiness label Jul 26, 2026
@changeset-bot

changeset-bot Bot commented Jul 26, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: b7b386c

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@cloudflare/vite-plugin Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-project-automation github-project-automation Bot moved this to Untriaged in workers-sdk Jul 26, 2026
@workers-devprod
workers-devprod requested review from a team and dario-piotrowicz and removed request for a team July 26, 2026 08:45
@workers-devprod

workers-devprod commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Codeowners approval required for this PR:

  • ✅ @cloudflare/wrangler
Show detailed file reviewers

@github-actions

github-actions Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

✅ All changesets look good

ask-bonk[bot]

This comment was marked as resolved.

@ask-bonk

ask-bonk Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Review submitted successfully to PR #14862.

Summary of my review:

  • Production fix (websockets.ts): Correct. Wrapping the async upgrade handler in try/catch, destroying the socket, and cleaning up the WeakMap entry properly addresses the unhandled-rejection-on-shutdown bug.
  • Config/test refactor: Sound — extending vitest.shared.ts, awaiting mf.ready, and tracked-socket teardown in afterEach are all reasonable deflaking measures.
  • One actionable issue (low severity): Posted an inline suggestion recommending onTestFinished to guarantee cleanup of the global unhandledRejection listener, since the current process.off only runs on the success path and would leak on a hang/timeout (compounded by retry: 1).

github run

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Open in Devin Review

@pkg-pr-new

pkg-pr-new Bot commented Jul 26, 2026

Copy link
Copy Markdown
@cloudflare/autoconfig

npm i https://pkg.pr.new/@cloudflare/autoconfig@14862

@cloudflare/config

npm i https://pkg.pr.new/@cloudflare/config@14862

create-cloudflare

npm i https://pkg.pr.new/create-cloudflare@14862

@cloudflare/deploy-helpers

npm i https://pkg.pr.new/@cloudflare/deploy-helpers@14862

@cloudflare/kv-asset-handler

npm i https://pkg.pr.new/@cloudflare/kv-asset-handler@14862

miniflare

npm i https://pkg.pr.new/miniflare@14862

@cloudflare/pages-shared

npm i https://pkg.pr.new/@cloudflare/pages-shared@14862

@cloudflare/unenv-preset

npm i https://pkg.pr.new/@cloudflare/unenv-preset@14862

@cloudflare/vite-plugin

npm i https://pkg.pr.new/@cloudflare/vite-plugin@14862

@cloudflare/vitest-pool-workers

npm i https://pkg.pr.new/@cloudflare/vitest-pool-workers@14862

@cloudflare/workers-auth

npm i https://pkg.pr.new/@cloudflare/workers-auth@14862

@cloudflare/workers-editor-shared

npm i https://pkg.pr.new/@cloudflare/workers-editor-shared@14862

@cloudflare/workers-utils

npm i https://pkg.pr.new/@cloudflare/workers-utils@14862

wrangler

npm i https://pkg.pr.new/wrangler@14862

commit: b7b386c

devin-ai-integration[bot]

This comment was marked as resolved.

petebacondarwin and others added 2 commits July 27, 2026 10:57
…dler

The `handleWebSocket` upgrade listener is `async` but did not guard
`miniflare.dispatchFetch`. When Miniflare is disposed mid-upgrade (dev
server shutdown/restart) the rejection escaped as an unhandled rejection,
which can terminate the process and leaks the client socket. Wrap the
handler body in try/catch and destroy the socket on failure.

Also deflake `websockets.spec.ts` on Windows CI: `listen()` now awaits
`miniflare.ready` so `workerd` cold start is charged to `testTimeout`
rather than the 1s `vi.waitFor` budget; Miniflare is created per-test via
a helper (no throwaway spawn); and `afterEach` tears down tracked sockets
before closing the server so a failed assertion can't cascade into a hook
timeout. Extend the shared vitest config to pick up `retry`/`hookTimeout`.
Co-authored-by: ask-bonk[bot] <249159057+ask-bonk[bot]@users.noreply.github.com>
@petebacondarwin
petebacondarwin force-pushed the fix/vite-plugin-websocket-upgrade-flake branch from e14c534 to b7b386c Compare July 27, 2026 09:57

@workers-devprod workers-devprod left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codeowners reviews satisfied

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci-flake Applied to PRs addressing CI flakiness

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants