I encountered an issue in the acquire decorator where a connection may be returned to the pool in an inconsistent state.
This happens because asyncio.CancelledError inherits from BaseException, not from Exception. As a result, it is not caught by the except Exception block.
Relevant code:
https://github.com/aio-libs/aiomcache/blob/master/aiomcache/client.py#L28
Because of this, when a coroutine is cancelled, conn[0].set_exception(exc) is not called before self._pool.release(conn).
As a result, a broken connection can be returned to the pool and reused later, which may lead to errors like:
ValueError: Separator is not found, and chunk exceed the limit
This can be fixed by explicitly handling asyncio.CancelledError and marking the connection as failed before returning it to the pool.
Example:
def acquire(
func: Callable[Concatenate[_Client, Connection, _P], Awaitable[_T]]
) -> Callable[Concatenate[_Client, _P], Awaitable[_T]]:
@functools.wraps(func)
async def wrapper(self: _Client, *args: _P.args, # type: ignore[misc]
**kwargs: _P.kwargs) -> _T:
conn = await self._pool.acquire()
try:
return await func(self, conn, *args, **kwargs)
except Exception as exc:
conn[0].set_exception(exc)
raise
except asyncio.CancelledError as exc:
# Got CancelledError from client code.
conn[0].set_exception(exc)
raise
finally:
self._pool.release(conn)
return wrapper
I encountered an issue in the
acquiredecorator where a connection may be returned to the pool in an inconsistent state.This happens because
asyncio.CancelledErrorinherits fromBaseException, not fromException. As a result, it is not caught by theexcept Exceptionblock.Relevant code:
https://github.com/aio-libs/aiomcache/blob/master/aiomcache/client.py#L28
Because of this, when a coroutine is cancelled,
conn[0].set_exception(exc)is not called beforeself._pool.release(conn).As a result, a broken connection can be returned to the pool and reused later, which may lead to errors like:
This can be fixed by explicitly handling
asyncio.CancelledErrorand marking the connection as failed before returning it to the pool.Example: