Durable Functionsを使用したサンプル -リクエスト結果をWebHookで返答するサービスへの対応-
今回はDurable Functionsを使用した少しだけ実践的なパターンを想定したサンプル実装を行ってみたいと思います。
前置き
前置き書いていたら長くなったので良い飛ばしてください。
みなさん、サービス間の連携にはどんな仕組みをよく使いますか?
一般的にはWeb APIが多いでしょうか?
今時的だとgPRCを使用したりする事もあるでしょう。
もしかしたら専用イーサネットワーク越しDATABASE LINKなどで RDBを使用して連携しているかも知れません。もしかしたらFTPサーバにcsvファイルをアップロードして連携するなんて事も2018年の今でも現在でも存在しているかも知れません。もしかしたらcsvファイルがshift-jisで書かれていたりeuc-jpで書かれていたり、どこかの企業が拡張した文字コードで書かれていたりするかも知れません。もしかしたらH○LFTなどの連携サービスを使用しているかも知れません。
Web APIでのサービス間連携は同期的であればとてもシンプルです。
1セッション内でリクエストとレスポンスが行われます。
しかし1処理に時間がかかる場合にはWeb APIによる連携は最善とは言えないかも知れません。
リクエストを受ける側は同期的に処理を実行するという制約がかけられる事によって実装難易度が上がってしまったりスケールアウトが難しくなってしまったりするかも知れません。
ロングランニングな処理に対する解決方法としては非同期なAPIを設計する場合があります。
リクエストを受け付けた時に処理IDを発行して返答し、リクエストを行なった側は処理IDを使用して結果取得APIをコールする事で結果を取得する形式です。
Durable FunctionsのOrchestratorは正にその振る舞いをします。
しかしこの形式はリクエストを送る側が結果取得APIをポーリングしなければならないという問題点があります。
そこで最終的に辿り着くパターンとしては処理が終わった時にリクエストを送信した側に何らかの方法で結果を通知する方法です。
良くある方式としてはリクエストを送信する側も結果通知リクエストを受け付けるエンドポイントを用意しておく所謂WebHook的な連携です。
今回は1リクエスト1フックなAPIへのリクエストをDurable Functionsの外部イベントを使用して処理するサンプルを作成してみたいと思います。
成果物
解説
人による操作または他の外部トリガーを処理するときに便利です
と書かれている通り外部トリガーというのが今回でいうWebHookであったりします。
まぁWebHookじゃなくてもFTPサーバに結果CSVをおいて(ry
WebHookOrchestrator
それではリクエストを行う側のOrchestrationを見てみましょう。
まずはHookApiRequestActivity
をコールしてAPIリクエストを行なって処理IDの取得をおこなっています。
処理は単純です。
次にSaveRequestKeyActivity
をコールして取得した処理IDを自身のInstanceIdとセットにしてStorageTableの保存しています。
次にWaitForExternalEvent
を使用して外部から結果を発火されるのを待ちます。
最後にOrchestrateの結果として外部からの結果を返答します。
HookRecieve
次にサービスからWebHookを受け付けるFunctionを見てみます。
WebHookによってリクエストされた情報の中からInstanceIdを取得してStorageTableに問い合わせを行い、リクエストを行なったOrchestratorのInstanceIdを取得。
そのInstanceIdでRaiseEventAsync
をコールします。
RaiseEventAsyncをコールするとWaitForExternalEventで待機していたOrchestratorが動き出してリクエストを行なったOrchestratorの処理が終了します。
終わりに
今回のサンプルであればリクエストを行う部分とWebHookを受ける部分を別々に処理したとしても問題がありません。
しかしAPIリクエストが処理の一部に過ぎず、その結果を使用してさらに複雑に処理を行なっていくようなパターンでは今回のようにDurable FunctionsのOrchestrationで実装していく方が楽になるかとおもいます。
また今回のパターンではWaitForExternalEventで待機した状態でWebHookが行われなかった場合、処理が中途半端になってしまします。
その場合のデザインパターンとしてScheduler Agent Supervisorパターンを用いるのも良いかも知れません。
その辺のサンプルはまた次回に。
それでは👋