こんにちは!
seiです!
今回は業務でfastAPIの機能backgroundTaskをariadneで使用するときに、少しはまったので備忘録です!
要件
フロント側がレスポンスを待ちたくない重い処理がありました。(email送信やバッチ処理等)
①よ~し、「重い処理の部分だけ後でやって先にレスポンス返そう!」
②「重い処理終わったらpub/subで通知や!」
なAPIを作るのにBackGroundTaskが最適でした。
①の部分で使います。
まずはfastAPIのドキュメント見てみます。
ふむふむ、operation_pathのところでbackground_taskつかえばいいんやな!
ariadneではリゾルバ関数の中で使ったらよいかな?
main.py
from fastapi import BackGroundTasks
// contextの中にbackgroundtask入れる
GraphQLApp = Graphql(schema,context_value={"back_ground_task":BackGroundTasks()})
app = FastAPI()
app.add_route("/graphql", GraphQLApp)
resolver.py
def heavy_process(arg1):
# 何らかの重い処理
return
@query.field("heavy")
def resolve_heavy(_, info,some_arg):
background_task = info.context["back_ground_task"]
background_task.add_task(heavy_process,arg1)
return "Hello, world!"
これだと動きませんでした(´;ω;`)
fastAPIとariadneでBackgroundTasksを使う方法
middleware層でbackgroundTaskを追加すればよいです。
middlewareのレスポンスにbackgroundの項目があるので、そこに追加します。
back_ground_middleware.py
class BackgroundTaskMiddleware(BaseHTTPMiddleware):
async def dispatch(
self, request: Request, call_next: RequestResponseEndpoint
) -> Response:
request.state.background = None
response = await call_next(request)
if request.state.background:
response.background = request.state.background
return response
resolver.py
def heavy_process(arg1):
# 何らかの重い処理
return
@query.field("heavy")
def resolve_heavy(_, info,some_arg):
task = BackgroundTasks()
task .add_task(heavy_process,arg1)
#middlewareにstateで渡す
request = info.context["request"]
request.state.background = task
return "Hello, world!"
main.py
from fastapi import BackGroundTasks
// contextの中にbackgroundtask入れる
GraphQLApp = Graphql(schema,context_value={"back_ground_task":BackGroundTasks()})
app = FastAPI()
#middlewareを追加する
app.add_middleware(BackgroundTaskMiddleware)
app.add_route("/graphql", GraphQLApp)
なぜこれでできるのか?
なぜこれで動くのか分からなかったので、調べました。
何で動くのか分からないプログラムはなるべく避けたいです。
もう一度FastAPIドキュメントに戻ります。
BackgroundTaskはfastAPIに入ってるstarletteを使用しているようです。
starletteのドキュメント見てみます。
BackGroundTaskに追加しているだけで、ここでは実際の処理は行っていませんね。
JSONResponseをインスタンス化した後に何か起こってるみたいです。
さらにgithubのソースコードを見てみます。
ありました!
def __init__() で親クラスResponseのコンストラクタを呼んでますね!
コンストラクタでBackgroundTaskがプロパティに設定されています。
ariadneはstarletteが組み込まれていないので、リゾルバ内でbackgroundtaskを使うことはできないポイですね。
middlewareを挟んであげて、starlette側で頑張る必要がありました!
ドキュメントを読む力がついてきたので、これからも続けていこうと思います!
実はメンタを始めてみました~
プログラミング学習で困っている方がいれば、ご連絡ください!
のんびりやっています~
フルスタックエンジニアとして働いています。フロントエンド、バックエンド、クラウドについての知識を教えることができます。 …