1. 程式人生 > 其它 >FastAPI(41)- Background Task 後臺任務

FastAPI(41)- Background Task 後臺任務

後臺任務

  • 顧名思義,可以在返回響應後執行後臺任務
  • 這對於需要在請求後執行特定的操作很有用,且客戶端並不需要在接收響應之前等待該操作完成

常見的栗子

  • 傳送電子郵件通知,由於連線到電子郵件伺服器併發送電子郵件往往會比較“緩慢”(幾秒鐘),因此可以立即返回響應並在後臺傳送電子郵件通知
  • 假設您到一個必須經過緩慢處理的檔案,可以先返回“已接受”(HTTP 202)響應並在後臺處理它

實際栗子

建立後臺任務要用到的函式

  • 建立一個作為後臺任務執行的函式,就是一個普通函式
  • 可以加 async 也可以不加,FastAPI 將會正確處理它
import time

def write_notification(email: str, message: str = ""
): # 1、模擬和郵件伺服器建立連線 time.sleep(3) with open("text.txt", mode="w") as f: # 2、模擬傳送郵件 content = f"message is {message}" f.write(content) print(content)

新增後臺任務

#!usr/bin/env python
# -*- coding:utf-8 _*-
"""
# author: 小菠蘿測試筆記
# blog:  https://www.cnblogs.com/poloyy/
# time: 2021/9/29 7:11 下午
# file: 35_background_task.py
""" import time import uvicorn from fastapi import FastAPI, BackgroundTasks app = FastAPI() def write_notification(email: str, message: str = ""): # 1、模擬和郵件伺服器建立連線 time.sleep(3) with open("text.txt", mode="w") as f: # 2、模擬傳送郵件 content = f"message is {message}" f.write(content)
print(content) @app.post("/email/{email}") async def send_email( email: str, # 指定引數型別為 BackgroundTasks background_task: BackgroundTasks ): # 新增後臺任務 # 第一個引數:可呼叫物件,一般就是函式 # 後面的引數:write_notification 函式所需要的引數 background_task.add_task(write_notification, email, message="test_message") return {"message": "Notification sent in the background"} if __name__ == '__main__': uvicorn.run(app="35_background_task:app", reload=True, host="127.0.0.1", port=8080)

後臺任務結合依賴項

#!usr/bin/env python
# -*- coding:utf-8 _*-
"""
# author: 小菠蘿測試筆記
# blog:  https://www.cnblogs.com/poloyy/
# time: 2021/9/29 7:11 下午
# file: 35_background_task.py
"""
import time
from typing import Optional

import uvicorn
from fastapi import FastAPI, BackgroundTasks, Depends

app = FastAPI()


# 後臺任務函式
def write_log(message: str):
    with open("log.txt", mode="a") as log:
        log.write(message)


# 依賴項函式
async def get_query(
        background_task: BackgroundTasks,
        q: Optional[str] = None,
):
    # 如果 q 有值才執行後臺任務
    if q:
        message = f"found query: {q}\n"
        background_task.add_task(write_log, message)


@app.post("/email_depends/{email}")
async def send_email(
        email: str,
        background_task: BackgroundTasks,
        q: str = Depends(get_query)
):
    # 執行一次後臺任務
    message = f"message to {email}\n"
    background_task.add_task(write_log, message)
    return {"message": "Message sent"}


if __name__ == '__main__':
    uvicorn.run(app="35_background_task:app", reload=True, host="127.0.0.1", port=8080)
  • 後臺任務可以在任意地方使用,比如路徑操作、依賴項、子依賴項...
  • FastAPI 會將所有後臺任務合併在一起,然後在後臺會按 add_task 的順序執行

檢視BackgroundTasks 原始碼

  • BackgroundTasks 是繼承BackgroundTask,而 BackgroundTask 是直接來自starlette.background
  • add_task() 第一個引數 func 型別是 Callable,可呼叫物件,一般傳函式就好啦
  • 內部會宣告一個BackgroundTask 物件,自動呼叫它的 __call__ 方法
  • 可以看到,最終會執行 func()
  • func() 函式引數就是 add_task() 函式除第一個引數以外的引數

BackgroundTasks 注意事項

  • 如果需要執行繁重的後臺計算,且可能需要多個程序執行(例如,不需要共享記憶體、變數等),使用其他更大的工具,如:Celery,效果可能會更好
  • 它們往往需要更復雜的配置、訊息/作業佇列管理器,如 RabbitMQ 或 Redis,它們允許在多個程序中執行後臺任務,尤其是在多個伺服器中
  • 但是,如果需要從同一個 FastAPI 應用程式訪問變數和物件,或者需要執行小型後臺任務(例如傳送電子郵件通知),只需使用 BackgroundTasks