Closed bitrut closed 6 years ago
FYI, raising GracefulExit
did the job. I just had some issues with concurrency and I've been raising this exception too early in my testing code.
Thanks anyway.
FYI GracefulExit
is a private API, use it on your own risk.
I'm running an aiohttp server in its own thread for a test. I'd like to end the test cleanly so called
await app.shutdown()
await app.cleanup()
but the server kept going. :-( My new plan is to use https://docs.python.org/3/library/multiprocessing.html so I can use terminate or close to stop the server. It looks like the cleanest option of the choices nicely listed at https://www.geeksforgeeks.org/python-different-ways-to-kill-a-thread/
@TomGoBravo FYI you may experience intermittent problems when running asyncio loop in non-main threads.
@TomGoBravo
Same issue here, the application keeps running after i called app.shutdown()
and app.cleanup()
Here is the code
import asyncio
from aiohttp import web
app = web.Application()
routes = web.RouteTableDef()
@routes.get("/hello")
async def hello(request):
return web.Response(text="Hello World")
async def bootup(this_app):
asyncio.create_task(background())
async def background():
await asyncio.sleep(5)
print("Start shutting down")
await app.shutdown()
print("Start cleaning up")
await app.cleanup()
if __name__ == "__main__":
app.add_routes(routes)
app.on_startup.append(bootup)
web.run_app(app, host="0.0.0.0", port=80)
print("Finished")
output
======== Running on http://0.0.0.0:80 ========
(Press CTRL+C to quit)
Start shutting down
Start cleaning up
This seems to be without a solution. I find related issues #5386, #4617, #3638, ...
I think the new API to solve it is in #2746. But the PR is stalled. I did not go studying further.
I solved this by using the web.AppRunner
and having the main task just wait on a future until the other tasks have decided they have shut down. The runner.cleanup should perform the shutdown. Something along the lines of:
async def process():
app = web.Application()
runner = web.AppRunner(app)
loop = asyncio.get_running_loop()
running = loop.create_future()
async def stop(e):
await runner.cleanup()
running.set_exception(e)
... # app setup
await runner.setup()
site = web.TCPSite(runner, *address)
await site.start()
await running
def main(config=None):
asyncio.run(process())
Would be nice to have a web.serve_app
you could just await or cancel with as simple interface as that of web.run_app
along the lines of asyncio.Server.serve_forever
.
I kindly ask for this to be reopened.
It is very frustrating that there only seem to be two ways of causing a graceful shutdown of an aiohttp application as discussed in this issue:
GracefulExit
, having to use a private APIweb.run_app
, probably by also using private APIsEven then, it seems questionable just how graceful a shutdown by throwing a SystemExit
to the loop really is (see https://github.com/aio-libs/aiohttp/issues/3638#issuecomment-621256659). So some documentation would really be appreciated.
In my case the easiest way to do this in most cases is to send a signal like os.kill(os.getpid(), 15)
. You could modify the signal handler if necessary for more specific behavior.
This did the trick for me and also exits gracefully.
import signal
def shutdown():
signal.raise_signal(signal.SIGTERM)
Call shutdown()
where you'd like to perform the interception.
Long story short
I have a aiohtto-based service which has the main purpose to just perform a task running in the background. The http is here just to respond with health status of the background task. I don't see any way to programatically stop aiohttp server in case of exception raised by the task. The whole service should stop, because it doesn't make sense without healthy task. I tried something like this (the example is based on the aiohttp docs):
Expected behaviour
I'd expect aiohttp to run all the
on_cleanup
hooks. Or some documentation on how to programatically shutdown the service.Actual behaviour
on_cleanup
hooks are not called.Steps to reproduce
Your environment