こんにちは!エンジニアのみっつーです。
今回はDurable Functionsの非同期HTTP APIパターンをテストする形で、Postman Flowsの使い方を見ていきたいと思います。
目次
- Durable Functionsのセットアップ・デバッグ
- Postman Flowsの作成・実行
- Flow実装で躓いた点
- 終わりに
Durable Functionsのセットアップ・デバッグ
まずはテスト対象のDurable Functionsを用意します。
Durable FunctionsはAzure Functionsの拡張機能であり、サーバーレスコンピューティング環境でステートフルなFunctionを記述できるものです。
複数Functionとそれらのオーケストレーションの定義をコーディングで実現します。
今回テストする非同期HTTP APIパターンは↓こんなやつですね。
今回はAzure FunctionsのDurable Functions Orchestrationテンプレートをそのまま使用します。
Visual Studioで作る場合は↓のように選択すればOKです。
(VSが無かったりWindows以外のOSの場合は Azure Functions Core Tools を入れることでCLIから作成できます。)
プロジェクト作成後、そのままデバッグしてみましょう。
テンプレートから特に変更を加えていない場合、正常に起動するとターミナルから http://localhost:xxxx/api/Function1_HttpStart
のようなエンドポイントが実行可能な状態になっていることが確認できます。
まずは通常通りPostmanから単体のエンドポイント呼び出しを行ってみましょう。
GET http://localhost:xxxx/api/Function1_HttpStart
を実行します。
パラメータ設定は不要なのでURLだけ入力してそのままSendでOKです。
レスポンス例は下記のようになります。
{ "id": "123456789012345678901234567890ab", "statusQueryGetUri": "http://localhost:xxxx/runtime/webhooks/durabletask/instances/123456789012345678901234567890ab?taskHub=TestHubName&connection=Storage&code=xxx", "sendEventPostUri": "http://localhost:xxxx/runtime/webhooks/durabletask/instances/123456789012345678901234567890ab/raiseEvent/{eventName}?taskHub=TestHubName&connection=Storage&code=xxx", "terminatePostUri": "http://localhost:xxxx/runtime/webhooks/durabletask/instances/123456789012345678901234567890ab/terminate?reason={text}&taskHub=TestHubName&connection=Storage&code=xxx", "purgeHistoryDeleteUri": "http://localhost:xxxx/runtime/webhooks/durabletask/instances/123456789012345678901234567890ab?taskHub=TestHubName&connection=Storage&code=xxx", "restartPostUri": "http://localhost:xxxx/runtime/webhooks/durabletask/instances/123456789012345678901234567890ab/restart?taskHub=TestHubName&connection=Storage&code=xxx", "suspendPostUri": "http://localhost:xxxx/runtime/webhooks/durabletask/instances/123456789012345678901234567890ab/suspend?reason={text}&taskHub=TestHubName&connection=Storage&code=xxx", "resumePostUri": "http://localhost:xxxx/runtime/webhooks/durabletask/instances/123456789012345678901234567890ab/resume?reason={text}&taskHub=TestHubName&connection=Storage&code=xxx" }
このレスポンスに含まれる statusQueryGetUri
にGETリクエストを行うことで、非同期処理の実行ステータスと結果を取得することができます。
試しにコールしてみると、下記のような結果が得られます。
{ "name": "Function1", "instanceId": "123456789012345678901234567890ab", "runtimeStatus": "Completed", "input": null, "customStatus": null, "output": [ "Hello Tokyo!", "Hello Seattle!", "Hello London!" ], "createdTime": "2024-08-01T00:00:00Z", "lastUpdatedTime": "2024-08-01T00:00:02Z" }
処理が全て完了していると、上記例のように runtimeStatus
がCompletedとなり、 output
に全ての実行結果が含まれます。
まだ非同期処理が実行途中の段階で statusQueryGetUri
をコールした場合は、 runtimeStatus
がRunningとなります。
Durable Functionsの確認はこのくらいにして、本題のPostman Flowsの内容に入っていきたいと思います。
※もし以降のFlowを真似して作られる場合は、上記2リクエスト情報をPostmanのコレクションに登録しておく必要があります。
このとき、 statusQueryGetUri
のリクエストURLは↓に書き換えておいてください(instanceIdが可変なので)。クエリパラメータは不要です。
http://localhost:xxxx/runtime/webhooks/durabletask/instances/{{id}}
Postman Flowsの作成・実行
Postman Flowsは、APIファーストなビジュアルアプリケーション開発インターフェースです。
APIの呼び出しとAPI間のデータ操作、出力データ表示の操作を行うためのGUIが提供されます。
今回は主にテストの用途での使い方を紹介しますが、Flowをデプロイして他のアプリケーションと統合することも可能です。
今回は下記の流れでフローを組みたいと思います。
flowchart TD A([開始]) --> B[初回リクエスト] B --> C[/ループ開始(3回)\] C --> D[statusQueryGetUriリクエスト] D --> E{判定} E -->|Completed| F[出力結果表示] E -->|Completed以外| G[Log出力のみ] F --> H[\ループ終了/] G --> H H --> I([終了])
本当はCompletedとなった時点でループを終了したいところですが、現時点のPostman Flowsにはbreakに相当する機能がありません。
今回はあくまでテスト用途で使用する想定のもと「ループのMAXカウントを明示的に指定する(3回)」という運用でカバーします。
※ループに関しては様々試行錯誤したので最後にまとめて記述します。
まずは今回使用するFlowを見ていきましょう。
先程フロー図で提示した内容をPostman Flowsで実装してみます。
このFlowを作るにあたって主に参考にした情報は下記です。
もし実際にFlowを作る際は、下記ドキュメントの内容を併せてご参考いただけるとよりイメージがつきやすいかと思います。
- Send Requestブロック
- Selectブロック
- Send request | Postman Learning Center
- Use Response Data in a Request | Postman Flows - YouTube
- APIレスポンスデータを以降のブロックで使いたい場合に必要となるものです
- Repeatブロック
- Repeat | Postman Learning Center
- ↑にExampleリンクが付いてるので併せて参考にしましょう
- 他にもループ用途のブロックがありますが、現時点でbreakに値する機能が無いため今回はカウント指定できるRepeatを使用しました
- Ifブロック
- If | Postman Learning Center
- FQLというクエリ言語を使って判定内容を書くので、ドキュメントやサンプルを参考にしましょう
- Outputブロック
- Visualize data in Postman Flows | Postman Learning Center
- 今回はjsonそのまま表示にしか使っていませんが、入力データをビジュアライズできるブロックなのでグラフ化できるデータであればより便利に使えます
Runボタンを押して実際に実行してみると、APIの結果や途中の実行ログを見ることができます。
Flow実装で躓いた点
今回デフォルトのDurable Functions(且つその中の2エンドポイントだけ)をPostman Flowsでテストしてみるという至ってシンプルな内容と思っていましたが想像以上に検証のしがいがありました。
検証残しがいくつかありますが、ステータスチェックのループを組むうえで仕様の把握に苦戦した部分を載せておきます。
- ループに対してbreakできない
- Evaluate使って実現してねというフォーラム回答を見かけましたが、ちょっと用途に合わない気がして導入しませんでした。軽く試しもしましたが上手くいかず。
- How do you break out of a "repeat" block in a Postman Flow? - 🙋 Help - Postman Community
- pause機能について、pause対象ブロックを含むループブロックがある場合、ループブロックが開始するタイミングでもpauseがかかってしまうように見受けられる
- pause機能:プログラミングにおけるブレークポイントのようなものです
- 同症状が報告されているフォーラムやIssueが見当たらなかったので、作り方が悪いだけかもしれません。引き続き検証中。
- ループ関連のブロックを使用せずに再度Send Requestを実行するような繋げ方をすると、2回目以降通るときは1回目の実行結果が流用される
- もしかするとリクエストパラメータに変更がなかったためかもしれない(リクエストパラメータに変更があれば別途実行される可能性を検証中)
- Repeatでのループ時、ループ内処理の完了を待たずに次のループが開始しているように見受けられる
- 1ループ内処理が一定時間過ぎると次のループが開始しているように見受けられました
- 試しにRepeatブロック直後にdelayとLogブロックを置いてログを確認したところ、カウントアップログ(Repeat開始ログ)が先に出力されました
- ステータスリクエストを飛ばすのに間隔を空けたかったのですが、↑の通りであればdelayの設置場所を調整するかRepeatを諦めるかする必要がありそうです
- delayの秒数に変数を割り当てることはできないので、例えばステータスリクエストのリトライ間隔を徐々に広げるといった用途にループカウントを使用することはできない
あと、モニターは大きいほど嬉しいです。
終わりに
Postman Flowsは、複数のAPIを続けて実行するようなパターンでテストを行いたい場合にとても強力なツールになり得るかと思います。
今回は非同期実行のための開始用エンドポイントとステータスチェックエンドポイントを持っているようなパターンで試しました。
Durable Functionsには、処理を中断するためのエンドポイント等も用意されているので、それらを使用するパターンのテスト実施にもPostman Flowsはかなり有効です。
APIを一つコールして、レスポンスJSONをメモしておいて、次のAPIをテストする、といった流れをいちいち実施するのはやはり大変ですよね。
また、 Flow起動のためにWebhookを設けることもできる ので、パイプラインから呼び出してテストとして使うといった方法も検討できるかもしれません。
ともあれまずは複数APIをテストする機会があれば、是非一度Postman Flowsを試してみてください!(無い方は是非Durable Functionsを使ってみてくださいw)
サービス一覧 www.alterbooth.com cloudpointer.tech www.alterbooth.com