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