FastAPIで極める非同期処理:バックグラウンドタスクとWebSocket活用ガイド
📋 記事のポイント(サマリー)
- 誰向け?
- 同期処理のAPIは書けるが、非同期やリアルタイム通信に挑戦したい中級者〜上級者
- 学べること
async def
/await
を用いた非同期関数の基本- FastAPIのバックグラウンドタスク機能で非同期バッチ処理を実装
- WebSocketエンドポイントの立ち上げとクライアント連携
- フロントエンドとの双方向リアルタイム通信サンプル
- 実運用時の注意点(接続数制限・例外処理など)
- 得られる効果
- 高負荷/長時間処理をAPIレスポンスと切り分け、ユーザー体験向上
- チャットや通知などリアルタイム機能を簡単に組み込める
🎯 対象読者
- 開発者Dさん(27歳・社会人)
すでにREST APIは同期版で書けるが、画像処理やメール送信を非同期に回したい方 - エンジニアEさん(30代)
チャット機能を学習中で、FastAPIでWebSocketを動かしてみたい方 - サイドプロジェクトFさん(24歳・学生)
サーバー負荷を抑えつつリアルタイムゲームのプロトタイプを作りたい方
♿ アクセシビリティレベル
- 読みやすさ:短めの文と箇条書きで視線移動を減らし、重要語はルビで補足
- 構造化:見出し・サブ見出しを階層化し、スクリーンリーダーで論理的に把握可能
- コード例:固定幅フォントで改行やインデントを揃え、コメントを充実
- 要約:各章末にポイントをまとめ、後から見返しやすい
1. 非同期処理の基本:async/await
とは?
Python 3.5以降で導入された 非同期関数 は、async def
/await
構文で記述します。
- 同期処理:関数が終わるまで他の処理を待つ
- 非同期処理:重たい処理中も別タスクを並行実行できる
import asyncio
async def say_after(delay: int, message: str):
await asyncio.sleep(delay)
print(message)
async def main():
# 並行実行(ここではタスクをまとめて実行)
await asyncio.gather(
say_after(1, "こんにちは"),
say_after(2, "FastAPI!"),
)
# 実行
asyncio.run(main())
要点まとめ
async def
で非同期関数を定義await
で他の非同期処理が終わるのを待機asyncio.gather
で複数タスクを同時実行
2. バックグラウンドタスクで長時間処理を切り分け
2.1 FastAPIの BackgroundTasks
FastAPI標準の BackgroundTasks
を使うと、レスポンス返却後に別処理を実行できます。
from fastapi import FastAPI, BackgroundTasks
import time
app = FastAPI()
def write_log(message: str):
time.sleep(5) # 重たい処理(例:ファイルI/O)
with open("log.txt", "a") as f:
f.write(message + "\n")
@app.post("/process/")
async def process_data(data: dict, background_tasks: BackgroundTasks):
# レスポンスを返した後にバックグラウンドで write_log が動く
background_tasks.add_task(write_log, f"Processed: {data}")
return {"status": "accepted"}
- リクエスト→即レスポンス→裏で長時間処理
- ユーザーは待たずに画面を更新可能
要点まとめ
- エンドポイント引数に
BackgroundTasks
を追加add_task
で同期/非同期関数両方を処理後にキューイング
2.2 複数タスク・例外処理
async def notify_user(user_id: int, message: str):
# 非同期関数もキューイング可
await asyncio.sleep(2)
# ここでメール送信やSNS通知を実装
@app.post("/notify/{user_id}")
async def notify(user_id: int, background_tasks: BackgroundTasks):
background_tasks.add_task(notify_user, user_id, "お知らせです")
return {"detail": "通知中"}
notify_user
はasync def
なので非同期で並行実行- タスク内で例外が起きてもAPI本体には影響なし
3. WebSocketでリアルタイム通信を実装
3.1 WebSocketの基本エンドポイント
FastAPIでは websockets
標準を利用し、簡単にWebSocketを立ち上げられます。
from fastapi import FastAPI, WebSocket
app = FastAPI()
@app.websocket("/ws")
async def websocket_endpoint(ws: WebSocket):
await ws.accept()
while True:
data = await ws.receive_text()
# 受信内容をそのまま返信
await ws.send_text(f"あなた: {data}")
- クライアントから送られたテキストを即座に返す エコーサーバ
while True
で接続維持しつつ、双方向通信
要点まとめ
@app.websocket
でエンドポイント定義accept()
→receive_XXX()
→send_XXX()
3.2 フロントエンドから接続する例
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>FastAPI WS</title></head>
<body>
<input id="msg" placeholder="メッセージ入力">
<button onclick="send()">送信</button>
<pre id="log"></pre>
<script>
const ws = new WebSocket("ws://127.0.0.1:8000/ws");
ws.onmessage = e => {
document.getElementById("log").textContent += e.data + "\n";
};
function send() {
const input = document.getElementById("msg");
ws.send(input.value);
input.value = "";
}
</script>
</body>
</html>
- ブラウザで開くだけでリアルタイムチャット体験
- CORS設定不要で同一オリジンならそのまま動作
4. 実運用での注意点
- 接続数制限
- WebSocketは常に接続維持 → サーバリソースを圧迫します
- Nginx/uvicornの
--ws
オプションで同時接続数を制御
- 例外/切断処理
- クライアントが突然切断すると例外が発生 →
try/except WebSocketDisconnect
でハンドリング
- クライアントが突然切断すると例外が発生 →
- バックグラウンドタスクの監視
- 大量タスク時は Celery などの専用キューを導入検討
- セキュリティ
- WebSocket経由の認証はトークンをクエリやヘッダで渡す方法を採用
要点まとめ
- 負荷対策と例外制御を組み込んで安定稼働を目指す
- 必要に応じて専用キュー/メッセージブローカーを活用
5. まとめと次のステップ
本記事では、FastAPIを使った非同期処理の2大機能、バックグラウンドタスク と WebSocket を中心に解説しました。
async/await
の基礎BackgroundTasks
でレスポンス即返却+長時間処理@app.websocket
でリアルタイム通信- フロント連携サンプルHTML
- 実運用での制限・例外・セキュリティ注意点
次は、以下を試してみましょう:
- メッセージブローカー連携:RedisやRabbitMQを使ったPub/Subモデル
- フロントフレームワーク統合:React/Vueでさらに洗練されたチャットUI
- 分散タスクキュー:CeleryやFastAPI-Backgroundタスクでスケーラブルに
FastAPIの非同期機能は拡張性が高く、用途に合わせて多彩な実装が可能です。ぜひ実践しながら、自分だけのリアルタイムAPIを作り込んでみてくださいね♡