持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第30,点击查看活动详情
- 有时,用户的一个请求行为服务端处理可能需要一段时间,此时如果等服务端处理完毕再给用户响应,那用户的体验可能不太好。
- 比如,用户注册接口,注册完毕后会收到邮件提醒,在邮件中激活账号。我们知道,发邮件其实是一个相对来说比较耗时的操作。
- 那此时,我们没有必要等邮件发出去后再给用户响应,而是可以直接给用户结束的响应,然后把发邮件的操作放在后台执行。
- 执行可能可以使用python的第三方库celery(重量级),可以使使用fastapi自带的background task(轻量级)
from fastapi import BackgroundTasks, FastAPI
import asyncio
app = FastAPI()
def email_notification(email: str, message=""):
await asyncio.sleep(2)
pass
@app.post("/send-notification/{email}")
async def send_notification(email: str, background_tasks: BackgroundTasks):
background_tasks.add_task(email_notification, email, message="some notification")
return {"message": "Notification sent in the background"}
- 在fastapi中使用后台任务非常简单,一共需要四步
- 第一步:编写一个执行后台任务的函数获取其他可以调调用的对象,同步调用或异步调用都可以。
- 第二步:从fastapi导入一个BackgroundTasks
- 第三步:在路径操作函数中,定义一个BackgroundTasks的变量,比如叫background_tasks
- 第四步:background_tasks调用add_task函数,可以注册该请求结束后需要执行的后台任务,在add_task传入被执的后台任务及其需要的参数即可。
- 并且后台任务可以和依赖注入结合使用,比如下面的例子中,在依赖注入使用后台任务。
from typing import Union
from fastapi import BackgroundTasks, Depends, FastAPI
app = FastAPI()
def write_log(message: str):
with open("log.txt", mode="a") as log:
log.write(message)
def get_query(background_tasks: BackgroundTasks, q: Union[str, None] = None):
if q:
message = f"found query: {q}\n"
background_tasks.add_task(write_log, message)
return q
@app.post("/send-notification/{email}")
async def send_notification(
email: str, background_tasks: BackgroundTasks, q: str = Depends(get_query)
):
message = f"message to {email}\n"
background_tasks.add_task(write_log, message)
return {"message": "Message sent"}
技术细节:
- 本质上 fastapi的后台后台任务不是他自创的,而是使用了starlette的后台任务,在起基础上稍微封装了使用方式。