-
Notifications
You must be signed in to change notification settings - Fork 2.6k
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 = _Timeoutbut connection.py should be rewritten using asyncio.timeout as this library may lead to strange behavior as mentioned here.