-
Notifications
You must be signed in to change notification settings - Fork 69
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
Aiohttp: graceful shutdown doesn't wait for aiojob.asyncio.atomic handler to finish within canceled request. #72
Comments
Looks like found a root of the problem at aiojobs._job.py Job._close:75 (at least after that changes, graceful shutdown waits for tasks to finish) async def _close(self, timeout):
self._closed = True
if self._task is None:
# the task is closed immediately without actual execution
# it prevents a warning like
# RuntimeWarning: coroutine 'coro' was never awaited
self._start()
# changes: comment next 2 lines, and move them to `except asyncio.TimeoutError as exc`
# cause this code will cancel the task immediately, but we need to wait at leat for timeout time
# if not self._task.done():
# self._task.cancel()
# self._scheduler is None after _done_callback()
scheduler = self._scheduler
try:
with async_timeout.timeout(timeout=timeout,
loop=self._loop):
await self._task
except asyncio.CancelledError:
pass
except asyncio.TimeoutError as exc:
# changes: moved 2 lines with task cancelation logic here.
# It seems that task should be canceled only after timeout
if not self._task.done():
self._task.cancel()
if self._explicit:
raise
context = {'message': "Job closing timed out",
'job': self,
'exception': exc}
if self._source_traceback is not None:
context['source_traceback'] = self._source_traceback
scheduler.call_exception_handler(context)
except Exception as exc:
if self._explicit:
raise
self._report_exception(exc) With that modification, if task was started, server will wait for it to finish.
|
I think a fix would either need some explicit logic for @atomic, or maybe a new Personally, I'd be more interested in fixing this from the aiohttp side and having aiohttp give handlers a moment to finish processing before shutting everything down. |
This issue is 5 years already. The only reason for me to use aiojobs is to give a guarantee of preventing cancellation of a task, including a request from disconnected clients. |
And only 1 person cared enough to try and fix it with a PR (but, unfortunately the change was wrong). Feel free to be the one to fix it properly (as mentioned above, a new wait_and_close() method is the one likely to be accepted).
aiojobs provides no gaurantee of preventing cancellation. If you just want to avoid aiohttp's cancellation behaviour on disconnect, it has been removed in the current release, and has a configurable option in the upcoming 3.9 release:
Not sure what you mean by being caught by CancelledError. That line is in the close() method. i.e. The job is being asked to close, which infers that it should cancel the task. |
I'm fixing this more generally in aiohttp (PR to follow soon). Expected behaviour is that when the server is shutting down, new connections will get rejected, but all existing tasks will have a few seconds to continue running, which will allow ongoing handlers to complete. Once the pending tasks are complete, or the timeout is reached, then the application shutdown/cleanup steps are run and finally any remaining tasks cancelled. The |
Have some view decorated with aiojob.asyncio.atomic, name it The Handler.
The Handler writes some important data to database in multiple steps.
Some client makes a request to The Handler and cancels it (e.g. due to poor connection).
The Handler is started.
At the same time, we decide to update code on server, so make a graceful shutdown.
The server had gracefully shutdown, but The Handler was not finished, and we lose some data.
Expected behaviour
The graceful shutdown should wait for The Handler to finish, even if it is within the canceled request.
Actual behaviour
The graceful shutdown doesn't wait for The Handler to finish if it is within the canceled request.
Steps to reproduce
Here is the script which reproduces that behavior (run with arg
test
, likepython3 main.py test
). It runs multiple scenarios:For every scenario:
curl
, make graceful shutdown, print outputs.curl
, cancel request (kill curl), make graceful shutdown, print outputs.After all, it will print the following table:
The most important thing is
started
which indicates was slow_task started or not, andended
which indicated did slow_task finish or not.As you can see, in the cases when the client had closed connection, even with atomic handler job was started, but terminated before finished.
Your environment
OS: macOS Mojave 10.14.2
Python 3.6.5
aiohttp==3.4.4
aiojobs==0.2.2
The text was updated successfully, but these errors were encountered: