-
Type:
Sub-task
-
Resolution: Fixed
-
Priority:
Major - P3
-
Affects Version/s: None
-
Component/s: None
-
None
-
DevProd Correctness
-
Fully Compatible
-
Correctness 2026-01-26, Correctness 2026-02-09
-
None
-
None
-
None
-
None
-
None
-
None
-
None
Error:
Test proxy_protocol_connect.js times out waiting for proxy server to terminate.
Signal handler fires but server never exits.
Description:
Python 3.13's asyncio made breaking changes to server shutdown behavior that exposed issues in the proxy-protocol library.
Root Causes:
1. Python 3.13 added Server.close_clients(): In Python 3.13+, calling server.close() alone only stops accepting new connections but leaves existing connections open indefinitely. The new Server.close_clients() method (gh-113538) is required to forcibly disconnect active connections during shutdown.
2. Python 3.12+ fixed wait_closed() bug: Python 3.10/3.11 had a bug where wait_closed() returned immediately even with active connections. Python 3.12+ fixed this to correctly wait. The proxy-protocol library's original code relied on this bug - it only called close() and assumed wait_closed() would return quickly. With the bug fixed, wait_closed() now hangs indefinitely waiting for connections that were never closed.
Why It Worked in Python 3.10/3.11:
The wait_closed() bug masked the missing close_clients() call. Even though active connections weren't closed, wait_closed() returned immediately, allowing the server to exit.
Why It Fails in Python 3.12+:
With the wait_closed() bug fixed, the server correctly waits for connections to close. Since close_clients() was never called, connections remain open and wait_closed() hangs forever.
Fix:
Monkey-patched the proxy-protocol library's run() function to:
1. Call server.close_clients() before forever.cancel() in the signal handler
2. Use loop.add_signal_handler() instead of signal.signal() to ensure signal handling runs on the event loop thread
3. Added production logging for shutdown signal and completion