Closed
Description
Version: 4.2.2
Platform: any
Description:
I had various issues related to task cancellation when using Redis
due to asyncio.CancelledError
disappearing sometimes. Probably related to #2028
The bug is difficult to reproduce as cancel()
needs to be called on a task
exactly when is waiting within an async with async_timeout.timeout(timeout):
block.
I tracked down the issue to async_timeout
used inside redis.asyncio.connection
. This module has this known issue that is not being addressed.
I patched the library externally with this code
import async_timeout
class _Timeout(async_timeout.Timeout):
RANDOM_TOKEN = '0f0dd596-373b-42df-aa0b-682d046c5d24'
def __exit__(self, exc_type, exc_val, exc_tb):
self._do_exit(exc_type, exc_val)
return None
async def __aexit__(self, exc_type, exc_val, exc_tb):
self._do_exit(exc_type, exc_val)
return None
def _do_exit(self, exc_type, exc_val):
if exc_type is asyncio.CancelledError and str(exc_val) == _Timeout.RANDOM_TOKEN \
and self._state == async_timeout._State.TIMEOUT:
self._timeout_handler = None
raise asyncio.TimeoutError
# timeout has not expired
self._state = async_timeout._State.EXIT
self._reject()
def _on_timeout(self, task: "asyncio.Task[None]") -> None:
task.cancel(_Timeout.RANDOM_TOKEN)
self._state = async_timeout._State.TIMEOUT
# drop the reference early
self._timeout_handler = None
async_timeout.Timeout = _Timeout
but connection.py
should be rewritten using asyncio.timeout
as this library may lead to strange behavior as mentioned here.