Python3 FastAPI Redis 使用方法,FastAPI 已经很快了,但是更快的方案依然是结合 Redis 充当缓存
Python3 FastAPI 使用 Redis
本文介绍 Python3 FastAPI
结合 Redis
使用方法,FastAPI
已经很快了,但是 更快的方案依然是继续结合 Redis
来当数据缓存
本文提供3种 使用Redis + FastAPI
的方法
分别见这里:
- 第1种方案:使用依赖注入来实现
- 第2种方案:使用
Lifespan Events
生命周期事件来实现 - 第3种方案:使用
startup、shutdown
事件来实现(不推荐)
环境:
Windows 10
Python 3.10.11 X64
fastapi==0.108.0
aioredis==2.0.1
方案1:使用依赖注入来实现
使用依赖注入来实现
实现步骤
1. 安装库
aioredis>=2.0.1
dependency-injector>=4.41.0
结构:
--- Test
|-- redis.py
|-- test_router.py
|-- test_aioredis.py
2. 初始化Redis连接和关闭
"""
@ File : redis.py
@ Author : yqbao
@ Version : V1.0.0
@ Description : redis
"""
from typing import AsyncIterator
from aioredis import from_url, Redis
async def init_redis_pool(host: str, password: str, db: int = 0, port: int = 6379) -> AsyncIterator[Redis]:
session = await from_url(
url=f"redis://{host}", port=port, password=password, db=db, encoding="utf-8", decode_responses=True)
yield session
await session.close()
3. 添加 server类,实现Redis 动作,Server 依赖于 Redis
"""
@ File : redis.py
@ Author : yqbao
@ Version : V1.0.0
@ Description : redis
"""
from typing import Awaitable
from aioredis import Redis
class Service(object):
def __init__(self, redis: Redis) -> None:
self._redis = redis
async def set(self, key: str, value: str) -> Awaitable:
return await self._redis.set(key, value)
async def get(self, key: str) -> str:
return await self._redis.get(key)
4. 创建一个 Container 容器,用于连接Redis并存放连接池
"""
@ File : redis.py
@ Author : yqbao
@ Version : V1.0.0
@ Description : redis
"""
from dependency_injector import containers, providers
class Container(containers.DeclarativeContainer):
config = providers.Configuration()
redis_pool = providers.Resource(
init_redis_pool,
host=config.redis_host,
port=config.redis_port,
db=config.redis_db,
password=config.redis_password, )
service = providers.Factory(Service, redis=redis_pool)
5. 配置路由,实现依赖注入
"""
@ File : test_router.py
@ Author : yqbao
@ Version : V1.0.0
@ Description : test_router
"""
from fastapi import Depends, APIRouter
from dependency_injector.wiring import inject, Provide
from lib.redis import Service, Container
router = APIRouter(responses={404: {"message": "Not Found"}})
# 在需要使用Redis的位置,用 inject 装饰,并依赖注入 service: Service = Depends(Provide[Container.service])
@router.get("/router-test")
@inject
async def index(service: Service = Depends(Provide[Container.service])):
value = await service.set('name', 'value')
return {"result": value}
6. 应用程序 APP
"""
@ File : test_aioredis.py
@ Author : yqbao
@ Version : V1.0.0
@ Description : test_aioredis
"""
from fastapi import FastAPI, Depends
from dependency_injector.wiring import inject, Provide
from redis import Service, Container
import test_router
app = FastAPI()
app.include_router(router=test_router.router)
# 在需要使用缓存的位置,用 inject 装饰,并依赖注入 service: Service = Depends(Provide[Container.service])
@app.get("/test")
@inject
async def index(service: Service = Depends(Provide[Container.service])):
value = await service.set('name', 'value')
return {"result": value}
# 创建容器
container = Container()
container.config.redis_host.from_value("localhost")
container.config.redis_password.from_env("REDIS_PASSWORD", "<YOU PASSWORD>") # 若环境变量不存在,则使用 <YOU PASSWORD>
container.config.redis_db.from_value(0)
container.config.redis_port.from_value(6379)
# 创建容器时,要将需要依赖注入的模块加载到容器中,否则将无法调用依赖项,报属性错误
container.wire(modules=[__name__, test_router.__name__])
if __name__ == '__main__':
import uvicorn
uvicorn.run(app='test_aioredis:app', host="127.0.0.1", port=8000, reload=True)
方案2:使用Lifespan Events生命周期事件来实现
使用Lifespan Events生命周期事件来实现
实现步骤
1. 安装库
aioredis>=2.0.1
2. 初始化Redis连接和关闭
结构:
--- Test
|-- test_router2.py
|-- test_aioredis2.py
"""
@ File : test_aioredis2.py
@ Author : yqbao
@ Version : V1.0.0
@ Description : test_aioredis2
"""
from typing import AsyncIterator
from aioredis import from_url, Redis
async def init_redis_pool(host: str, password: str, db: int = 0, port: int = 6379) -> AsyncIterator[Redis]:
session = await from_url(
url=f"redis://{host}", port=port, password=password, db=db, encoding="utf-8", decode_responses=True)
return session
3. 创建异步上下文管理器
"""
@ File : test_aioredis2.py
@ Author : yqbao
@ Version : V1.0.0
@ Description : test_aioredis2
"""
from contextlib import asynccontextmanager
from fastapi import FastAPI
# 关于生命周期事件详见:https://fastapi.tiangolo.com/advanced/events/#lifespan
@asynccontextmanager
async def lifespan(apps: FastAPI):
session = await init_redis_pool(host="127.0.0.1", password="<YOU PASSWORD>", db=0, port=6379) # 你的密码<YOU PASSWORD>
# 将Redis连接添加到app全局实例,详见:https://www.starlette.io/applications/
# Storing state on the app instance
app.state.redis = session
yield
await session.close()
4. 在路由中使用APP全局实例,调用Redis
"""
@ File : test_router2.py
@ Author : yqbao
@ Version : V1.0.0
@ Description : test_router2
"""
from fastapi import APIRouter, Request
router = APIRouter(responses={404: {"message": "Not Found"}})
# 利用 request 访问全局实例,若 request 可用,则request.app可用
@router.get("/router-test")
async def index(request: Request):
value = await request.app.state.redis.set('name', 'value')
return {"result": value}
5. 将上文创建的 异步上下文管理器,添加到应用 APP
"""
@ File : test_aioredis2.py
@ Author : yqbao
@ Version : V1.0.0
@ Description : test_aioredis2
"""
from fastapi import Request
import test_router2
app = FastAPI(lifespan=lifespan) # 添加生命周期为函数 lifespan
app.include_router(router=test_router2.router)
# 利用 request 访问全局实例,若 request 可用,则request.app可用
@app.get("/test")
async def index(request: Request):
value = await request.app.state.redis.set('name', 'value')
return {"result": value}
if __name__ == '__main__':
import uvicorn
uvicorn.run(app='test_aioredis2:app', host="127.0.0.1", port=8000, reload=True)
方案3:使用startup、shutdown事件来实现(不推荐)
使用startup、shutdown
事件来实现(不推荐,因为被Lifespan Events
生命周期事件所取代)
实现步骤
1. 安装库
aioredis>=2.0.1
2. 初始化Redis连接和关闭
结构:
--- Test
|-- test_router3.py
|-- test_aioredis3.py
"""
@ File : test_aioredis3.py
@ Author : yqbao
@ Version : V1.0.0
@ Description : test_aioredis3
"""
from typing import AsyncIterator
from aioredis import from_url, Redis
async def init_redis_pool(host: str, password: str, db: int = 0, port: int = 6379) -> AsyncIterator[Redis]:
session = await from_url(
url=f"redis://{host}", port=port, password=password, db=db, encoding="utf-8", decode_responses=True)
return session
3. 创建 startup、shutdown事件
"""
@ File : test_aioredis3.py
@ Author : yqbao
@ Version : V1.0.0
@ Description : test_aioredis3
"""
from fastapi import FastAPI
@app.on_event("startup")
async def startup_event():
# 将Redis连接添加到app全局实例,详见:https://www.starlette.io/applications/
# Storing state on the app instance
# 你的密码<YOU PASSWORD>
app.state.redis = await init_redis_pool(host="127.0.0.1", password="<YOU PASSWORD>", db=0, port=6379)
@app.on_event("shutdown")
async def shutdown_event():
await app.state.redis.close()
4. 在路由中使用APP全局实例,调用Redis
"""
@ File : test_router3.py
@ Author : yqbao
@ Version : V1.0.0
@ Description : test_router3
"""
from fastapi import APIRouter, Request
router = APIRouter(responses={404: {"message": "Not Found"}})
# 利用 request 访问全局实例,若 request 可用,则request.app可用
@router.get("/router-test")
async def index(request: Request):
value = await request.app.state.redis.set('name', 'value')
return {"result": value}
5. 应用 APP,直接使用request 访问全局实例
"""
@ File : test_aioredis3.py
@ Author : yqbao
@ Version : V1.0.0
@ Description : test_aioredis3
"""
from fastapi import Request
import test_router3
app = FastAPI()
app.include_router(router=test_router3.router)
# 利用 request 访问全局实例,若 request 可用,则request.app可用
@app.get("/test")
async def index(request: Request):
value = await request.app.state.redis.set('name', 'value')
return {"result": value}
if __name__ == '__main__':
import uvicorn
uvicorn.run(app='test_aioredis3:app', host="127.0.0.1", port=8000, reload=True)
本文来自博客园作者:星尘的博客,转载请注明出处:https://www.cnblogs.com/yqbaowo/p/17958727