grpc: Graceful shutdown is not working for async server
What version of gRPC and what language are you using?
1.37
What operating system (Linux, Windows,…) and version?
macOS Cataline 10.15.7
What runtime / compiler are you using (e.g. python version or version of gcc)
Python 3.9.0
What did you do?
I am running the following code
import logging
import asyncio
import grpc
async def serve() -> None:
server = grpc.aio.server()
listen_addr = "[::]:50051"
server.add_insecure_port(listen_addr)
logging.info("Starting server on %s", listen_addr)
await server.start()
try:
await server.wait_for_termination()
except KeyboardInterrupt:
# Shuts down the server with 0 seconds of grace period. During the
# grace period, the server won't accept new connections and allow
# existing RPCs to continue within the grace period.
await server.stop(0)
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO)
asyncio.run(serve())
What did you expect to see?
A graceful shutdown
What did you see instead?
/Users/ilian/.virtualenvs/usersettings-service/bin/python /Users/ilian/workspace/lifesum/usersettings-service/tmp.py
INFO:root:Starting server on [::]:50051
Traceback (most recent call last):
File "/Users/ilian/workspace/lifesum/usersettings-service/tmp.py", line 38, in <module>
asyncio.run(serve())
File "/Users/ilian/.pyenv/versions/3.9.0/lib/python3.9/asyncio/runners.py", line 44, in run
return loop.run_until_complete(main)
File "/Users/ilian/.pyenv/versions/3.9.0/lib/python3.9/asyncio/base_events.py", line 629, in run_until_complete
self.run_forever()
File "/Users/ilian/.pyenv/versions/3.9.0/lib/python3.9/asyncio/base_events.py", line 596, in run_forever
self._run_once()
File "/Users/ilian/.pyenv/versions/3.9.0/lib/python3.9/asyncio/base_events.py", line 1854, in _run_once
event_list = self._selector.select(timeout)
File "/Users/ilian/.pyenv/versions/3.9.0/lib/python3.9/selectors.py", line 562, in select
kev_list = self._selector.control(None, max_ev, timeout)
KeyboardInterrupt
Exception ignored in: <function Server.__del__ at 0x10b05c5e0>
Traceback (most recent call last):
File "/Users/ilian/.virtualenvs/usersettings-service/lib/python3.9/site-packages/grpc/aio/_server.py", line 169, in __del__
File "src/python/grpcio/grpc/_cython/_cygrpc/aio/common.pyx.pxi", line 116, in grpc._cython.cygrpc.schedule_coro_threadsafe
File "src/python/grpcio/grpc/_cython/_cygrpc/aio/common.pyx.pxi", line 108, in grpc._cython.cygrpc.schedule_coro_threadsafe
File "/Users/ilian/.pyenv/versions/3.9.0/lib/python3.9/asyncio/base_events.py", line 431, in create_task
File "/Users/ilian/.pyenv/versions/3.9.0/lib/python3.9/asyncio/base_events.py", line 510, in _check_closed
RuntimeError: Event loop is closed
sys:1: RuntimeWarning: coroutine 'AioServer.shutdown' was never awaited
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Reactions: 11
- Comments: 18 (8 by maintainers)
I created PR https://github.com/grpc/grpc/pull/26622 to add a proper graceful shutdown example. @IlianIliev Please let me know if it works or not.
@damarvin The 2 CTRL+C problem is different than the graceful shutdown described in this issue. The graceful shutdown issue is about where can
KeyInterrupt
be propagated to. Can you share your reproduce snippet?I have opened a ticket there -> https://bugs.python.org/msg398400 Let’s see if they can help in any way. And thank you for your help to look at this issue )
Good point. I reproduced your result with a busy loop in the server handler. In normal Python,
KeyboardInterrupt
will be populated to the main thread, so it’s deterministic. But with asyncio, the main thread might be occupied by the request handler or the event loop, hence theKeyboardInterrupt
problem exists.This sounds like a design problem for
asyncio
. I don’t have an answer. Maybe we should open an issue to CPython? https://bugs.python.org/I tried your change. If we use
time.sleep
theKeyboardInterrupt
exception will be populated to thetime.sleep
, hence it will not be caught by our new try-catch clause at all.I see exactly the output as the case is about, with the 1st CTRL+C already. I assume @IlianIliev needs a 2nd too, to get back on the console, so I’d wait for #26123 is fixed.