[Python] Redis: Cannot release a lock that's no longer owned

Discussão em 'Python' iniciado por Stack, Dezembro 9, 2024.

  1. Stack

    Stack Membro Participativo

    I'm trying to lock certain key.

    I have httpx.Auth subclass:

    from redis.asyncio import Redis from httpx import AsyncClient, Auth

    def get_redis_client(): return Redis(host=settings.redis_host, port=settings.redis_port)

    class BearerAuth(Auth): esm_url_get_token: str = urljoin(settings.esm_host, settings.esm_path_url_get_token) token_redis_key = "esm:token" token_expires_redis_key = "esm:token:expires"

    @log_esm()
    async def _get_token(self) -> Response:
    redis_client = get_redis_client()
    async with redis_client.lock(self.token_redis_key):
    if expires := await redis_client.get(self.token_expires_redis_key):
    expires = int(expires)
    if time.time() < expires:
    return await redis_client.get(self.token_redis_key)
    timeout = Timeout(settings.esm_timeout, read=None)
    client = AsyncClient(verify=settings.esm_verify, timeout=timeout)
    data = {"login": settings.esm_login, "password": settings.esm_password}
    response = await client.post(url=self.esm_url_get_token, data=data)
    token = response.json()["token"]
    await redis_client.set(self.token_redis_key, token)
    await redis_client.set(self.token_expires_redis_key, self._get_expires())
    await asyncio.sleep(settings.esm_delay_between_get_token_and_request)
    return token

    def _get_expires(self):
    return int(time.time()) + 55 * 60

    async def async_auth_flow(self, request: HTTPXRequest) -> typing.AsyncGenerator[HTTPXRequest, Response]: # NOSONAR
    response = await self._get_token()
    token = response.json()["token"]
    request.headers["Authorization"] = f"Bearer {token}"
    yield request


    The main goal is to get token. If token expires refresh it. With code above I got an error:


    Traceback (most recent call last):\n File "/Users/albertaleksandrov/Library/Caches/pypoetry/virtualenvs/esm-Xqw79VLb-py3.11/lib/python3.11/site-packages/uvicorn/protocols/http/httptools_impl.py", line 435, in run_asgi\n result = await app( # type: ignore[func-returns-value]\n
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File "/Users/albertaleksandrov/Library/Caches/pypoetry/virtualenvs/esm-Xqw79VLb-py3.11/lib/python3.11/site-packages/uvicorn/middleware/proxy_headers.py", line 78, in call\n return await self.app(scope, receive, send)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File "/Users/albertaleksandrov/Library/Caches/pypoetry/virtualenvs/esm-Xqw79VLb-py3.11/lib/python3.11/site-packages/uvicorn/middleware/message_logger.py", line 86, in call\n raise exc from None\n File "/Users/albertaleksandrov/Library/Caches/pypoetry/virtualenvs/esm-Xqw79VLb-py3.11/lib/python3.11/site-packages/uvicorn/middleware/message_logger.py", line 82, in call\n await self.app(scope, inner_receive, inner_send)\n File "/Users/albertaleksandrov/Library/Caches/pypoetry/virtualenvs/esm-Xqw79VLb-py3.11/lib/python3.11/site-packages/fastapi/applications.py", line 289, in call\n await super().call(scope, receive, send)\n File "/Users/albertaleksandrov/Library/Caches/pypoetry/virtualenvs/esm-Xqw79VLb-py3.11/lib/python3.11/site-packages/starlette/applications.py", line 122, in call\n await self.middleware_stack(scope, receive, send)\n File "/Users/albertaleksandrov/Library/Caches/pypoetry/virtualenvs/esm-Xqw79VLb-py3.11/lib/python3.11/site-packages/starlette/middleware/errors.py", line 184, in call\n raise exc\n File "/Users/albertaleksandrov/Library/Caches/pypoetry/virtualenvs/esm-Xqw79VLb-py3.11/lib/python3.11/site-packages/starlette/middleware/errors.py", line 162, in call\n await self.app(scope, receive, _send)\n File "/Users/albertaleksandrov/Library/Caches/pypoetry/virtualenvs/esm-Xqw79VLb-py3.11/lib/python3.11/site-packages/prometheus_fastapi_instrumentator/middleware.py", line 169, in call\n raise exc\n File "/Users/albertaleksandrov/Library/Caches/pypoetry/virtualenvs/esm-Xqw79VLb-py3.11/lib/python3.11/site-packages/prometheus_fastapi_instrumentator/middleware.py", line 167, in call\n await self.app(scope, receive, send_wrapper)\n File "/Users/albertaleksandrov/Library/Caches/pypoetry/virtualenvs/esm-Xqw79VLb-py3.11/lib/python3.11/site-packages/starlette/middleware/base.py", line 108, in call\n response = await self.dispatch_func(request, call_next)\n
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File "/Users/albertaleksandrov/Library/Caches/pypoetry/virtualenvs/esm-Xqw79VLb-py3.11/lib/python3.11/site-packages/partners_logging/middlewares.py", line 24, in logger_middleware\n return await call_next(request)\n
    ^^^^^^^^^^^^^^^^^^^^^^^^\n File "/Users/albertaleksandrov/Library/Caches/pypoetry/virtualenvs/esm-Xqw79VLb-py3.11/lib/python3.11/site-packages/starlette/middleware/base.py", line 84, in call_next\n raise app_exc\n File "/Users/albertaleksandrov/Library/Caches/pypoetry/virtualenvs/esm-Xqw79VLb-py3.11/lib/python3.11/site-packages/starlette/middleware/base.py", line 70, in coro\n await self.app(scope, receive_or_disconnect, send_no_error)\n File "/Users/albertaleksandrov/Library/Caches/pypoetry/virtualenvs/esm-Xqw79VLb-py3.11/lib/python3.11/site-packages/starlette/middleware/exceptions.py", line 79, in call\n raise exc\n File "/Users/albertaleksandrov/Library/Caches/pypoetry/virtualenvs/esm-Xqw79VLb-py3.11/lib/python3.11/site-packages/starlette/middleware/exceptions.py", line 68, in call\n await self.app(scope, receive, sender)\n File "/Users/albertaleksandrov/Library/Caches/pypoetry/virtualenvs/esm-Xqw79VLb-py3.11/lib/python3.11/site-packages/fastapi/middleware/asyncexitstack.py", line 20, in call\n raise e\n File "/Users/albertaleksandrov/Library/Caches/pypoetry/virtualenvs/esm-Xqw79VLb-py3.11/lib/python3.11/site-packages/fastapi/middleware/asyncexitstack.py", line 17, in call\n await self.app(scope, receive, send)\n File "/Users/albertaleksandrov/Library/Caches/pypoetry/virtualenvs/esm-Xqw79VLb-py3.11/lib/python3.11/site-packages/starlette/routing.py", line 718, in call\n await route.handle(scope, receive, send)\n File "/Users/albertaleksandrov/Library/Caches/pypoetry/virtualenvs/esm-Xqw79VLb-py3.11/lib/python3.11/site-packages/starlette/routing.py", line 276, in handle\n await self.app(scope, receive, send)\n File "/Users/albertaleksandrov/Library/Caches/pypoetry/virtualenvs/esm-Xqw79VLb-py3.11/lib/python3.11/site-packages/starlette/routing.py", line 66, in app\n response = await func(request)\n
    ^^^^^^^^^^^^^^^^^^^\n File "/Users/albertaleksandrov/Library/Caches/pypoetry/virtualenvs/esm-Xqw79VLb-py3.11/lib/python3.11/site-packages/fastapi/routing.py", line 273, in app\n raw_response = await run_endpoint_function(\n
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File "/Users/albertaleksandrov/Library/Caches/pypoetry/virtualenvs/esm-Xqw79VLb-py3.11/lib/python3.11/site-packages/fastapi/routing.py", line 190, in run_endpoint_function\n return await dependant.call(**values)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File "/Users/albertaleksandrov/PycharmProjects/kz-esm/app/web/api/test.py", line 47, in check_lock\n await client.create_request(request, user)\n File "/Users/albertaleksandrov/PycharmProjects/kz-esm/app/services/integrations/client.py", line 151, in create_request\n response = await self.raw_request(action="post", url=self.esm_url_post, data=data)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File "/Users/albertaleksandrov/PycharmProjects/kz-esm/app/services/integrations/client.py", line 44, in wrapped\n result: Response = await func(self, *args, **kwargs)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File "/Users/albertaleksandrov/PycharmProjects/kz-esm/app/services/integrations/client.py", line 141, in raw_request\n response = await getattr(client, action)(url=url, json=data)\n
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File "/Users/albertaleksandrov/Library/Caches/pypoetry/virtualenvs/esm-Xqw79VLb-py3.11/lib/python3.11/site-packages/httpx/_client.py", line 1848, in post\n return await self.request(\n
    ^^^^^^^^^^^^^^^^^^^\n File "/Users/albertaleksandrov/Library/Caches/pypoetry/virtualenvs/esm-Xqw79VLb-py3.11/lib/python3.11/site-packages/httpx/_client.py", line 1533, in request\n return await self.send(request, auth=auth, follow_redirects=follow_redirects)\n
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File "/Users/albertaleksandrov/Library/Caches/pypoetry/virtualenvs/esm-Xqw79VLb-py3.11/lib/python3.11/site-packages/httpx/_client.py", line 1620, in send\n response = await self._send_handling_auth(\n
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File "/Users/albertaleksandrov/Library/Caches/pypoetry/virtualenvs/esm-Xqw79VLb-py3.11/lib/python3.11/site-packages/httpx/_client.py", line 1645, in _send_handling_auth\n request = await auth_flow.anext()\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File "/Users/albertaleksandrov/PycharmProjects/kz-esm/app/services/integrations/client.py", line 110, in async_auth_flow\n response = await self._get_token()\n ^^^^^^^^^^^^^^^^^^^^^^^\n File "/Users/albertaleksandrov/PycharmProjects/kz-esm/app/services/integrations/client.py", line 44, in wrapped\n result: Response = await func(self, *args, **kwargs)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File "/Users/albertaleksandrov/PycharmProjects/kz-esm/app/services/integrations/client.py", line 88, in _get_token\n async with redis_client.lock(self.token_redis_key):\n File "/Users/albertaleksandrov/Library/Caches/pypoetry/virtualenvs/esm-Xqw79VLb-py3.11/lib/python3.11/site-packages/redis/asyncio/lock.py", line 165, in aexit\n await self.release()\n File "/Users/albertaleksandrov/Library/Caches/pypoetry/virtualenvs/esm-Xqw79VLb-py3.11/lib/python3.11/site-packages/redis/asyncio/lock.py", line 262, in do_release\n raise LockNotOwnedError("Cannot release a lock that's no longer owned")\nredis.exceptions.LockNotOwnedError: Cannot release a lock that's no longer owned
    ​

    How to fix it?

    Continue reading...

Compartilhe esta Página