-
-
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
Change web handlers cancellation policy #2492
Comments
Yes, this should be configurable at (1) global and (2) handler level. |
Personally, I like the current policy. Typically, inside a view only a small portion of the view code needs to be protected from cancellation. For that, you can wrap it inside |
PR #4080 replaces task cancellation with We can close the issue. |
How does this handle the case?
With the old behaviour, the query would be automatically cancelled. With the new PR, it doesn't get cancelled, and so the database is doing a lot of useless work. |
I think the original proposal was reasonable, making cancellation opt-in, and per route, but #4080 just removes cancellation completely. I think #4080 removes an important functionality from aiohttp. How can we even detect client disconnection? There's only two points where we can: (1) at the beginning, (2) at the end. If the client disconnects 5 seconds into a query that takes 20 seconds, we will not be notified. The handler only finds out at the end of the query, when it's about to write the response. |
The previous approach required protecting user code from cancellation. In the case mentioned by you (20 sec DB request has client disconnection after 5 sec of running) the normal behavior takes 20 secs. You don't rely on early connection dropping but think that all requests are handled without user interruption normally. It overloads the server, very long DB queries should be refactored most likely to make the system more responsible. Early cancellation doesn't help at all. In the case of response streaming the server sends data by chunks. It gets an exception about client disconnection on the next send. I deemed a lot about the cancellation. Now I'm pretty sure that the user should do nothing with it. aiohttp can implement support for early client disconnection notification but I very doubt if any people will use it; while we should care about the maintenance burden (code, documentation, tests). |
Fine, I kind of understand you reasoning. But I still wish aiohttp made it possible, even if not so simple, for application code to be notified of client disconnections in real time. As it is now, only when you try to return the response does aiohttp itself get the notification. Application code only gets notification in case of streaming response which, in case of a long DB query, is going to be near the end of query completion. Maybe we could at least have a simple Looking through the sources, it seems that I could potentially get |
What should be |
Well, to get real time notification of disconnections, something like Request.poll() would do nothing, and simply hang until the client disconnects. Maybe it needs a better name: class Request:
async def wait_for_disconnection(self): ..
"""Does nothing and returns when the socket that sent this request disconnects""" Then you could have a handler like: async def handler(request):
wait = asyncio.create_task(request.wait_for_disconnection())
bgtask = asyncio.create_task(my_bg_code())
asyncio.wait([wait, bgtask], return_when=asyncio.FIRST_COMPLETED)
if bgtask.done():
wait.cancel()
return web.Response(bgtask.result())
bgtask.cancel()
raise web.HTTPGatewayTimeout() It's not pretty, but at least it's possible. |
There's probably a few awaits missing in the above, but I can always make a utility function in my app, that simplifies it: async def cancel_on_disconnect(request, coro):
...
def handler(request):
result = await cancel_on_disconnect(request, my_bg_task()) The |
Ok, we need Regarding What do you think? |
Yes, I prefer I am not sure about |
Suppose you have a streaming or web-socket response. We can left |
We are discussing long enough to keep the issue open |
WebSocketResponse already has a close() method. For other types of responses you can simply send a response with empty or error message body, and then aiohttp can close the transport itself if it's in shutdown mode. In any case, this does feel like a separate issue. I don't have strong opinion either way, but, if you want |
I'm being stupid, WebSocketResponse is a response, you said request.disconnect(). Anyway, an entirely different issue. Would you like me to prepare a PR for |
The idea for
Please do |
as means of allowing request handlers to be notified of premature client disconnections.
I agree with the second paragraph. About first - there is a asyncio way to wrap handler into asyncio.shield: from functools import wraps
def atomic(coro):
@wraps(coro)
async def wrapper(*args, **kwargs):
return await asyncio.shield(coro(*args, **kwargs))
return wrapper
@atomic
async def handler(request):
. . . |
I've caught by this unexpected cancellation yesterday. I don't actually care about whether it is the default, but can you print out such cancellation at a higher logging level than debug (+ debug=True) ? My coroutine just disappeared, without a trace. Even without an access log entry. FYI, my use case is different than most common ones: the request is not requesting data or modifying state; it's a signal that some event has happened. It's the endpoint of a GitHub webhook, so it's expected to continue running even the requestor has gone. (I've solved this by spawning a free future after discovering aiohttp cancelled my coroutine.) |
Done by aiohttp 3.7 |
Cancelling a web handler task on client disconnection is the most unexpected and annoying feature of aiohttp web server.
People from classic WSGI world don't expect it.
Moreover tornado doesn't support a cancellation (I hope it will in 5.0 release).
The proposal is:
False
by default.Opinions?
The text was updated successfully, but these errors were encountered: