-
-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
on_cleanup / on_shutdown are called after active tasks on the event loop are canceled #3593
Comments
GitMate.io thinks the contributor most likely able to help you is @asvetlov. Possibly related issues are #1207 (Handle all concurrent.futures._base.TimeoutError and throw a aiohttp.errors.TimeoutError instead.), #2168 (server often throw "concurrent.futures._base.CancelledError"), #2374 (cancellederror still exist.), #930 (aiohttp.Timeout causes CancelledError), and #3549 (Concurrent GET requests lead to ClientConnectorError(8, 'nodename nor servname provided, or not known')). |
This is intended change in Now all unfinished tasks are canceled, |
|
I did more research in the code (including on the master branch). The description has been updated. The cancellation does not appear to be the last step. |
My workaround is as follows. Because asyncio signal handlers must be synchronous, there are some challenges. I do not propose altering the behavior of on_shutdown and on_cleanup. I would instead like an additional handler that would be called before canceling all tasks on the event loop. "some_stop_function" could be passed via, say a new method on Application such as on_signal().
|
@asvetlov - Not sure if I'm doing something wrong, but I seem to be running into the same problem where long running tasks are cancelled prior to the import asyncio
from aiohttp import web
my_long_task = None
async def long_task():
print("starting long task")
try:
await asyncio.sleep(3600)
except asyncio.CancelledError:
print("long_task cancelled")
async def shutdown(app):
print("on_shutdown")
print(f"my_long_task.done() = {my_long_task.done()}")
async def cleanup(app):
print("on_cleanup")
async def startup(app):
global my_long_task
loop = asyncio.get_event_loop()
my_long_task = loop.create_task(long_task())
app = web.Application()
app.on_startup.append(startup)
app.on_shutdown.append(shutdown)
app.on_cleanup.append(cleanup)
web.run_app(app) Running this app 10 times - 50/50 split - half the time the task is cancelled first, the other half on_shutdown / on_cleanup are executed first:
I'm running: aiohttp 3.5.4 |
I have written a small code snippet to mimic current (aiohttp 3.5.4) import asyncio
import signal
class GracefulExit(SystemExit):
code = 1
def _raise_graceful_exit():
print('_raise_graceful_exit')
raise GracefulExit()
async def _runner_setup():
loop = asyncio.get_event_loop()
loop.add_signal_handler(signal.SIGINT, _raise_graceful_exit)
loop.add_signal_handler(signal.SIGTERM, _raise_graceful_exit)
async def _run_app():
try:
await _runner_setup()
while True:
print('running....')
await asyncio.sleep(3600)
finally:
print('call runner.cleanup()')
def run_app():
loop = asyncio.get_event_loop()
try:
loop.run_until_complete(_run_app())
except (GracefulExit, KeyboardInterrupt) as ex:
print('GracefulExit?', type(ex))
finally:
print('Cancel all tasks')
run_app() The result shows that pjknkda@anne:~/test/asyncio_signal$ python3.7 main.py
running....
^C_raise_graceful_exit
GracefulExit? <class '__main__.GracefulExit'>
Cancel all tasks This behavior is somewhat unexpected to me and I think this may cause the described issue. |
this worked :) |
Otherwise, some tasks might be cancelled before cleanup hooks run. Fixes aio-libs#3593
Otherwise, some tasks might be cancelled before cleanup hooks run. Fixes aio-libs#3593
I had a similar issue where a cleanup hook would depend on some background task running. The task would get cancelled before the cleanup hook ran, leading to some unexpected behavior. Cancelling the run_app task first makes the cleanup hooks run first, thus hopefully fixing the bug. |
Otherwise, some tasks might be cancelled before cleanup hooks run. Fixes aio-libs#3593
Otherwise, some tasks might be cancelled before cleanup hooks run. Fixes aio-libs#3593
Otherwise, some tasks might be cancelled before cleanup hooks run. Fixes aio-libs#3593
@asvetlov per your comment:
Using python 3.7.2 and aiohttp version 3.6.2, after locally adding a print debug statement to |
Otherwise, some tasks might be cancelled before cleanup hooks run. Fixes #3593
Otherwise, some tasks might be cancelled before cleanup hooks run. Fixes #3593 (cherry picked from commit c32101d) Co-authored-by: multun <[email protected]>
Otherwise, some tasks might be cancelled before cleanup hooks run. Fixes #3593 (cherry picked from commit c32101d) Co-authored-by: multun <[email protected]> Co-authored-by: multun <[email protected]>
Just got bitten by this, too. Could aiohttp 3.7 containing the fix for this bug be released, please? |
Otherwise, some tasks might be cancelled before cleanup hooks run. Fixes #3593
I am running Python 3.7.2 with aiohttp 3.5.4.
web.run_app() is called. Then I press control-c.
This causes my asyncio tasks (started via on_startup) to get cancelled before on_cleanup can gracefully stop them using a method other than .cancel(). This is new behavior from the previous version of aiohttp I was using.
Handling CancelledError is problematic given that it can be thrown anywhere 'await' and similar are used (I guess I could use asyncio.shield in literally hundreds of places).
The text was updated successfully, but these errors were encountered: