Krukov / cashews

Cache with async power
MIT License
371 stars 22 forks source link

Cannot close Redis connection - AttributeError: 'Redis' object has no attribute '_client' #209

Closed rkrell closed 2 months ago

rkrell commented 4 months ago

cashews==7.0.2

Example code:

async def main():

    cache.setup('mem://')
    cache.setup(
        f'redis://{cfg.redis.host}:{cfg.redis.port}/{cfg.redis.db}',
        password=None,
        retry_on_timeout=True,
        prefix=REDIS_NAMESPACE,
        protocol=3
    )

    try:
        # some code
    finally:
        await cache.close()

results in a stacktrace:

Traceback (most recent call last):
  File "/home/rk/demo/application.py", line 120, in <module>
    asyncio.run(main())
  File "/home/rk/.pyenv/versions/3.11.5/lib/python3.11/asyncio/runners.py", line 190, in run
    return runner.run(main)
           ^^^^^^^^^^^^^^^^
  File "/home/rk/.pyenv/versions/3.11.5/lib/python3.11/asyncio/runners.py", line 118, in run
    return self._loop.run_until_complete(task)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/rk/.pyenv/versions/3.11.5/lib/python3.11/asyncio/base_events.py", line 653, in run_until_complete
    return future.result()
           ^^^^^^^^^^^^^^^
  File "/home/rk/demo/application.py", line 110, in main
    await cache.close()
  File "/home/rk/.pyenv/versions/demo-3.11/lib/python3.11/site-packages/cashews/wrapper/wrapper.py", line 97, in close
    await backend.close()
  File "/home/rk/.pyenv/versions/demo-3.11/lib/python3.11/site-packages/cashews/backends/redis/backend.py", line 313, in close
    await self._client.close()
          ^^^^^^^^^^^^
AttributeError: 'Redis' object has no attribute '_client'

Shouldn't this be handled differently?

rkrell commented 4 months ago

Just for comparison, the following code works instead:

import asyncio

from cashews import cache

async def main():
    cache.setup('mem://')
    redis_backend = cache.setup(
        f'redis://127.0.0.1:6379/0',
        password=None,
        retry_on_timeout=True,
        prefix='redis',
        protocol=3
    )

    try:
        async with cache.lock('redis:shower', expire=10):
            print(
                f"shower is "
                f"{'occupied' if await cache.is_locked('redis:shower') else 'available'}")
        print(
            f"shower is "
            f"{'occupied' if await cache.is_locked('redis:shower') else 'available'}")
    finally:
        await redis_backend.close()

if __name__ == '__main__':
    try:
        asyncio.run(main(), debug=True)
    except KeyboardInterrupt:
        print('Cancelled by user')

I got to call close() on single Backend instances.

As soon as I call just await cache.close() the problem appears.

Krukov commented 4 months ago

@rkrell Thanks for reporting. I will take a look at this (probably a bug) at weekends

Krukov commented 2 months ago

Sorry for a delay , the fix in the main branch. Gonna to release it soon

Krukov commented 2 months ago

Fixed with 7.1.0 version. Please reopen the issue if it still exist