Repository navigation
wait_for raises CancelledError #114496
Copy link
Copy link
Closed as not planned
Labels
pendingThe issue will be closed if no feedback is providedThe issue will be closed if no feedback is providedtopic-asynciotype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
Description
Bug report
Bug description:
Problem is, wait_for sometimes raises CancelledError instead of TimeoutError.
Had a look on recent changes and updated Lib/asyncio/timeouts.py with #113819 by @serhiy-storchaka which seemed similar.
I failed to do to reproduce with sleep only/without httpx.
As the exception raised is either TimeoutError or CancelledError, I consider this an cpython issue.
import pytest
import httpx
import asyncio
import asyncio.timeouts
import random
import logging
@pytest.mark.asyncio
async def test_wait_for():
async def step() -> bool:
"""
:return True if finished. False if not stalled
"""
while True:
try:
c = httpx.AsyncClient()
if False: # works
async with asyncio.timeout(6):
await asyncio.sleep(random.randrange(1, 5))
async with c.stream("get", "https://git.kernel.org/torvalds/t/linux-6.8-rc1.tar.gz") as r:
async for i in r.aiter_bytes(100):
await asyncio.sleep(random.randrange(1, 5))
except Exception as e:
logging.exception(e)
async def install() -> None:
while True:
try:
await asyncio.wait_for(step(), timeout=random.randrange(1,4))
except (asyncio.TimeoutError, TimeoutError):
pass
except asyncio.CancelledError as x:
logging.exception(x)
# assert False, "Cancellation"
raise
await install()Traceback (most recent call last):
File "/tmp/the_test.py", line 576, in install
await asyncio.wait_for(step(), timeout=random.randrange(1,4))
File "/usr/lib/python3.12/asyncio/tasks.py", line 520, in wait_for
return await fut
^^^^^^^^^
File "/tmp/the_test.py", line 569, in step
await asyncio.sleep(random.randrange(1, 5))
File "/usr/lib/python3.12/asyncio/tasks.py", line 665, in sleep
return await future
^^^^^^^^^^^^
asyncio.exceptions.CancelledError
CPython versions tested on:
3.12
Operating systems tested on:
Linux
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
pendingThe issue will be closed if no feedback is providedThe issue will be closed if no feedback is providedtopic-asynciotype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
Projects
- StatusShow more project fieldsDone
Activity
gvanrossum commentedon Jan 23, 2024
Can someone (doesn't have to be the OP) please supply an example that doesn't depend on an external library?
From the traceback it looks like
wait_for()usesCancelledErrorto trigger the timeout and somehow the code that normally turns that into aTimeoutErrordoesn't run. But in order to track down the issue it would be nice to have a simpler repro.commonism commentedon Jan 24, 2024
Using asyncio.timeout directly:
I think the conversion to TimeoutError is not done due to
self._task.uncancel() <= self._cancellingbeing unmet here (self._task.cancelling() = 2, self._canceling = 0)cpython/Lib/asyncio/timeouts.py
Lines 109 to 115 in 1e4f00e
Not using the c-module for asyncio to see who cancels gets me to
anyio canceling via tg.cancel_scope.cancel()
https://github.com/agronholm/anyio/blob/3f14df89fe4c6d5edebae345a95d04c30334bba2/src/anyio/_core/_sockets.py#L167-L181
I may be wrong wrt. to cpython causing this.
@gvanrossum Given the opportunity. We've had an argument about tulip/asyncio ~10 years ago. I disagreed, lack of experience/vision. You were right.
aditchawdhary commentedon Jan 24, 2024
I tried to look at this,
This downloads the tar file as a data stream and stores in the tar format. This example uses
urllib.request.urlopeninstead ofasyncio.While looking at the documentation for
asyncio.wait_forhere, it specifically mentions that to avoid task cancellation, wrap withshield()and when I tried to do this, I did not see any Cancellation errors.I am not too aware of the inner working of asyncio, thanks @commonism for explaining that.
commonism commentedon Jan 24, 2024
The problem we have is the
CancelledErroris not converted to aTimeoutError.As shown before, I currently suspect anyio CancelScope modifies the tasks cancellation count.
According to @agronholm agronholm/anyio#374 co-existence of anyio and asyncio should not cause any problems for anyio >= 4.x.
I use 4.2.0.
agronholm commentedon Jan 24, 2024
AnyIO does uncancel the task when exiting cancelled cancel scopes (as of v4), so it shouldn't pose a problem. Could someone create a minimal reproducing example of the problem? I don't have a lot of bandwidth to dedicate to this.
gvanrossum commentedon Jan 24, 2024
I still don't see a simple repro that doesn't use a 3rd party module. (Also, the code snippets presented as "repro" are incomplete, they lack the needed imports and the
asyncio.run()call that starts things.)I may just close this issue for lack of information if the situation doesn't improve within a week.
PS. @commonism I don't know who you are (or who you were 10 years ago) so I cannot comment on the disagreement we had then -- I have no idea what it was about. :-)
sunmy2019 commentedon Jan 31, 2024
Looks like the behavior is expected.
CancelledErrortoTimeoutErrordue to that extra cancel.Seems no bug here.
commonism commentedon Jan 31, 2024
I agree with anyIO causing this.
asyncio.wait_for sometimes raises CancelledError