Commit 2afd2bd
committed
fix(server): guard GET SSE response with CancelScope to prevent Windows deadlock
On Windows + ProactorEventLoop, sse-starlette's EventSourceResponse can
leave orphan child tasks parked in anyio.sleep() or Event.wait() after
client disconnect. These orphans prevent TaskGroup.__aexit__ from
completing, causing _handle_get_request to hang forever. Each hung GET
response accumulates resources until the uvicorn worker deadlocks.
The companion issue PrefectHQ/fastmcp#4192 has a full investigation,
cross-control matrix, and deterministic reproduction confirming the
bug is in the FastMCP wrapper layer's interaction with sse-starlette,
not the SDK's core transport.
Fix: wrap the EventSourceResponse await in _handle_get_request with
an anyio.CancelScope stored on the transport. terminate() cancels this
scope before closing streams, breaking the TaskGroup deadlock and
allowing the session to clean up properly.
Fixes #26531 parent 0e3a604 commit 2afd2bd
1 file changed
Lines changed: 19 additions & 5 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
188 | 188 | | |
189 | 189 | | |
190 | 190 | | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
191 | 194 | | |
192 | 195 | | |
193 | 196 | | |
| |||
743 | 746 | | |
744 | 747 | | |
745 | 748 | | |
746 | | - | |
747 | | - | |
748 | | - | |
| 749 | + | |
| 750 | + | |
| 751 | + | |
| 752 | + | |
| 753 | + | |
| 754 | + | |
| 755 | + | |
| 756 | + | |
749 | 757 | | |
| 758 | + | |
| 759 | + | |
| 760 | + | |
750 | 761 | | |
751 | 762 | | |
752 | | - | |
753 | | - | |
754 | 763 | | |
755 | 764 | | |
756 | 765 | | |
| |||
787 | 796 | | |
788 | 797 | | |
789 | 798 | | |
| 799 | + | |
| 800 | + | |
| 801 | + | |
| 802 | + | |
| 803 | + | |
790 | 804 | | |
791 | 805 | | |
792 | 806 | | |
| |||
0 commit comments