uvicorn waits 30 seconds before terminating with SIGINT #2327
Unanswered
pawel-jaworski
asked this question in
Potential Issue
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
When
uvicorn
is terminated with CTRL^C while there is an open TCP connection with TLS (keep-alive + https), it hangs for 30 seconds before shutting down.To reproduce:
mkcert
:timeout_keep_alive
to 600 seconds:https://localhost:5000
Logs:
Python, uvicorn & OS:
python: 3.12.2
uvicorn: 0.28.1
OS: Ubuntu 20.04
Notes on reproduction:
Debugging details:
https://github.com/encode/uvicorn/blob/0.28.1/uvicorn/server.py#L303
because there's active connection, so
_waiters
is notNone
:https://github.com/python/cpython/blob/v3.12.1/Lib/asyncio/base_events.py#L400
connection.shutdown()
is called:https://github.com/encode/uvicorn/blob/0.28.1/uvicorn/server.py#L263
close()
is called ontransport
instance:https://github.com/encode/uvicorn/blob/0.28.1/uvicorn/protocols/http/h11_impl.py#L339
transport
is an instance of_SSLProtocolTransport
class, so when_start_shutdown
is called:https://github.com/python/cpython/blob/v3.12.1/Lib/asyncio/sslproto.py#L112
inside
close()
method, shutdown is scheduled with 30 seconds delay:https://github.com/python/cpython/blob/v3.12.1/Lib/asyncio/sslproto.py#L620
_detach()
is called:https://github.com/python/cpython/blob/v3.12.1/Lib/asyncio/base_events.py#L297
which calls
_wakeup()
, which in turn sets_waiters
toNone
:https://github.com/python/cpython/blob/v3.12.1/Lib/asyncio/base_events.py#L305
wait_closed
:https://github.com/python/cpython/blob/v3.12.1/Lib/asyncio/base_events.py#L401
transport
is an instance of_SelectorSocketTransport
, so whenclose
is called,_detach()
is called inside_call_connection_lost
:https://github.com/python/cpython/blob/v3.12.1/Lib/asyncio/selector_events.py#L915
_call_connection_lost
is scheduled withcall_soon
instead ofcall_later
, it executes without a delay:https://github.com/python/cpython/blob/v3.12.1/Lib/asyncio/selector_events.py#L871
Expected behaviour:
When server is closed with SIGINT and
force_exit
is set toTrue
, we shouldn't wait for graceful connection shutdown.Proposed solution:
When
force_exit
isTrue
, when shutting down connections, we should calltransport.abort()
instead oftransport.close()
:https://github.com/encode/uvicorn/blob/0.28.1/uvicorn/protocols/http/h11_impl.py#L339
Other solutions:
ssl_shutdown_timeout
to a low value (or 0) whenforce_exit=True
: probably not that straightforwardtimeout_graceful_shutdown
to a low value, but this would affect graceful shutdowns (with SIGTERM) as well, unless depending onforce_exit
Beta Was this translation helpful? Give feedback.
All reactions