FastAPI启动时挂载redis(asyncio版)

但使龙城飞将在,不教胡马度阴山。落后就要挨打,挨打要立正,真理只在大炮范围之内。
近代列强的欺侮历历在目,现今无耻之邦公然排海,而强盗政党则列实体清单无休止制裁。
中东乌克炮火不断,我们不是生在和平的年代,而是生在和平的国度。勿忘国耻,吾辈当自强!

代码如下:

import os
from contextlib import AbstractAsyncContextManager, asynccontextmanager
from typing import AsyncGenerator

from fastapi import FastAPI, Request
from pydantic import BaseModel
from redis import asyncio as aioredis


class AsyncRedis(aioredis.Redis, AbstractAsyncContextManager):
    """FastAPI定制版异步redis客户端

    Usage::
        >>> from fastapi import FastAPI, Request
        >>> @asynccontextmanager
        ... async def lifespan(app: FastAPI):
        ...     async with AsyncRedis(app):
        ...         yield
        ...
        >>> @app.get('/keys')
        ... async def show_redis_keys(request: Request) -> list[str]:
        ...     redis: AsyncRedis = AsyncRedis(request)
        ...     return await redis.keys()
        ...
        >>> async def use_outside_fastapi():
        ...     async with AsyncRedis() as redis:
        ...         print(await redis.keys())
        ...
        []
    """

    def __new__(cls, app: FastAPI | Request | None = None, **kw) -> "AsyncRedis":
        if isinstance(request := app, Request):
            return request.app.state.redis
        return super().__new__(cls, **kw)

    async def __aenter__(self) -> "AsyncRedis":
        # Check connection when app startup
        await self.ping()
        return self

    async def __aexit__(self, *args, **kw):
        await self.aclose()  # type:ignore[attr-defined]

    def __init__(self, app=None, **kw) -> None:
        if host := os.getenv("REDIS_HOST"):
            kw.setdefault("host", host)
        super().__init__(**kw)
        if isinstance(app, FastAPI):
            app.state.redis = self


@asynccontextmanager
async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
    async with AsyncRedis(app):
        yield


app = FastAPI(lifespan=lifespan)


@app.get("/keys")
async def get_redis_keys(request: Request) -> list[str]:
    return await AsyncRedis(request).keys()


@app.get("/get")
async def get_redis_value(
    request: Request, key: str
) -> dict[str, str | int | float | None]:
    value = await AsyncRedis(request).get(key)
    if isinstance(value, bytes):
        value = value.decode()
    return {"key": key, "value": value}


class Item(BaseModel):
    key: str
    value: str | float | int
    expire: int | float | None = None


@app.post("/set")
async def set_into_redis(request: Request, item: Item) -> dict[str, str]:
    if item.expire:
        await AsyncRedis(request).set(item.key, item.value, item.expire)
    else:
        await AsyncRedis(request).set(item.key, item.value)
    return {"msg": "OK"}

运行:

python -m venv venv
source venv/*/activate
pip install fastapi redis uvicorn
uvicorn app:app

请求接口:

# pip install httpie
http :8000/keys
http :8000/get key==foo
http :8000/set key=foo1 value=0
http :8000/set 
posted @ 2024-02-25 15:11  waketzheng  阅读(113)  评论(0编辑  收藏  举报