Задать вопрос
@albertalexandrov

Как залочить ключ Redis на доступ?

Не разберусь, как заблокировать на доступ конкретный ключ в Redis.

У меня такой код:

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"

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


Можно видеть, что я пытаюсь заблокировать ключ "esm:token". Нужно блокировать доступ к ключу настолько, насколько длится код в блоке контекстного менеджера. Но этот код валится на ошибке:

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


Как правильно залочить ключ Redis?
  • Вопрос задан
  • 88 просмотров
Подписаться 1 Простой Комментировать
Пригласить эксперта
Ответы на вопрос 1
@Everything_is_bad
А зачем ты этот лок ключ token_redis_key дальше трогаешь? Не надо так делать. Лок ключ не должен пресекаться с ключами в который ты хранишь данные.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы
11 дек. 2024, в 22:15
10000 руб./за проект
11 дек. 2024, в 22:10
3000 руб./за проект
11 дек. 2024, в 21:35
13000 руб./за проект