FastAPI×ariadneでBackgroundTasksを使う方法

こんにちは!
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)

 

参考URL:https://stackoverflow.com/questions/62031695/how-to-use-background-tasks-with-starlette-when-theres-no-background-object

なぜこれでできるのか?

なぜこれで動くのか分からなかったので、調べました。
何で動くのか分からないプログラムはなるべく避けたいです。

 

もう一度FastAPIドキュメントに戻ります。
BackgroundTaskはfastAPIに入ってるstarletteを使用しているようです。

 

starletteのドキュメント見てみます。

BackGroundTaskに追加しているだけで、ここでは実際の処理は行っていませんね。
JSONResponseをインスタンス化した後に何か起こってるみたいです。

さらにgithubのソースコードを見てみます。

ありました!
def __init__() で親クラスResponseのコンストラクタを呼んでますね!

 

コンストラクタでBackgroundTaskがプロパティに設定されています。

 

ariadneはstarletteが組み込まれていないので、リゾルバ内でbackgroundtaskを使うことはできないポイですね。
middlewareを挟んであげて、starlette側で頑張る必要がありました!

ドキュメントを読む力がついてきたので、これからも続けていこうと思います!

 

実はメンタを始めてみました~
プログラミング学習で困っている方がいれば、ご連絡ください!

のんびりやっています~

フルスタックエンジニアとして働いています。フロントエンド、バックエンド、クラウドについての知識を教えることができます。 …

 

カラフルな幾何学模様
プログラミング学習方法を発信してます!