Skip to content

Handle reads during ASGI WebSocket shutdown - #1233

Merged
Kludex merged 4 commits into
pydantic:mainfrom
tamird:codex/asgi-websocket-eof
Sep 28, 2026
Merged

Kludex merged 4 commits into
pydantic:mainfrom
tamird:codex/asgi-websocket-eof

Conversation

@tamird

@tamird tamird commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Closing an ASGI WebSocket stream can expose AnyIO's queue exceptions through the network-stream interface. A pending receive raises EndOfStream, and a read begun after local queue closure raises ClosedResourceError. The WebSocket session handles network-layer errors and EOF, so these backend exceptions can escape its task group.

Translate EndOfStream to b"" and ClosedResourceError to httpcore2.ReadError, matching httpcore2's AnyIO adapter. The regressions cover pending and post-close reads on asyncio and Trio, plus explicit session close while another task owns the context.

This addresses the vendored equivalent of the httpx-ws issue 1 using the EOF translation proposed upstream 2.

Prepared with assistance from Codex.

Checklist

  • I understand that this PR may be closed in case there was no previous discussion. (This doesn't apply to typos!)
  • I've added a test for each change that was introduced, and I tried as much as possible to make a single atomic change.
  • I've updated the documentation accordingly.

Closing an ASGI WebSocket session while its context remains open can
wake a pending read with anyio.EndOfStream. The exception escapes the
session task group because its EOF handling expects an empty byte
string from the network stream.

Translate the ASGI queue's EndOfStream to b"" at the stream boundary,
matching httpcore2's AnyIO adapter. Cover the pending-read contract and
cross-task session close on asyncio and Trio.

This addresses the vendored equivalent of httpx-ws issue pydantic#146 [1], with
the same EOF translation proposed upstream [2].

[1]: frankie567/httpx-ws#146
[2]: frankie567/httpx-ws#147
@tamird

tamird commented Sep 25, 2026

Copy link
Copy Markdown
Contributor Author

@Viicos could you please TAL? I suspect your bot might come and close this since there's no ticket :(

@codspeed

codspeed Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 17 untouched benchmarks
⏩ 7 skipped benchmarks1


Comparing tamird:codex/asgi-websocket-eof (1625809) with main (fc32b34)

Open in CodSpeed

Footnotes

  1. 7 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩

@cubic-dev-ai cubic-dev-ai 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.

All reported issues were addressed across 2 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread src/httpx2/httpx2/websockets/_transport.py
An ASGI network-stream read begun after queue closure raises AnyIO's
ClosedResourceError. The WebSocket session only handles network-layer
read errors and EOF, leaving this backend-specific failure unhandled.

Translate local queue closure to httpcore2.ReadError, as the normal
AnyIO network adapter does. Keep EndOfStream mapped to b"" and extend
the stream regression to exercise both pending and post-close reads.

Addresses the missing closure case identified in review [1].

[1]: pydantic#1233 (comment)
@tamird tamird changed the title Return EOF when an ASGI WebSocket stream closes Handle reads during ASGI WebSocket shutdown Sep 25, 2026
@Viicos

Viicos commented Sep 25, 2026

Copy link
Copy Markdown
Member

@Viicos could you please TAL? I suspect your bot might come and close this since there's no ticket :(

The bot is only active on the pydantic repo as we get way too much spam here. I'll defer to @Kludex on this one

@Viicos
Viicos requested a review from Kludex September 25, 2026 18:32
@Kludex
Kludex enabled auto-merge (squash) September 28, 2026 08:12
@Kludex
Kludex merged commit 76d02ee into pydantic:main Sep 28, 2026
14 checks passed
@tamird
tamird deleted the codex/asgi-websocket-eof branch September 28, 2026 08:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants