Power Automate クラウドフローの簡単エラーハンドル・メッセージ通知の実装サンプル

はじめに

結構前にPower AppsとPower Automateの連携の記事でシンプルなエラーハンドルの実装サンプルをお見せしたのですが、自分もよく使うフローのエラーハンドルとメッセージ通知(フロー作成者宛)の実装サンプルを今更ながら記事にしようかと思います。テンプレートとしてコピーして微調整すれば使えると思いますので活用ください。

この記事は、Microsoft Power Automate Advent Calendar 2024 12月1日担当分の記事です。

スコープを使ったエラーハンドル(Try・Catch)

何もしない場合は、定期的なタイミングでPower Automateからエラー通知が来ますが、すぐのタイミングではないのでシンプルでも入れておいた方がオススメです。

フローのアクションで「スコープ」があります。こちらで全体を囲ってあげて、※一部アクション除く
その中で何らかのエラーが発生したらエラー処理用のスコープでメール通知などのアクションを行う。というものです。
詳細はともかくエラーが発生したら実行者や管理者へ通知があると、対応するリカバーがとれるので必須に近い機能かと思います。
フロー内で複雑な業務ロジックやループ処理を行っている場合に、細かくエラーハンドルするのは大変ですが(出来はします)、とりあえずなんか起きたら通知して詳細はフローを見て対応するというケースで活用出来ます。

本サンプルではスケジュールフローを動作して処理内でエラーがあったら、フロー作成者へメールを送信します。また、エラー概要もresult()式で取得して、フローURLリンクなども通知に含めたサンプルです。

フローサンプル

以下よく作るエラーハンドル簡易版のサンプルです。
メイン処理の全体をスコープで囲み、その下にエラー時用のスコープを用意。
エラー時用スコープではエラー概要取得、エラー通知をフロー作成者(や指定ユーザー)に送る内容です。
トリガーはサンプルはスケジュールですが、手動やApps、自動トリガーなどでも同様です。

スコープ TRY:メイン処理部分 サンプル実装

以下では対象リストからステータス申請中のレコードを取得し、その分にリマインドメールを送るサンプルです。
この部分はあくまでサンプルであり、中身は実際のフローの処理に置き換えるイメージです。

スコープ CATCH:エラー処理部分 エラー時に処理を行う

この部分が共通して使える実装となっています。
概要としては、フローの情報から作成者のアドレス・名前を取得、スコープ内のエラー情報からアクション名、エラー概要を取得しています。
それらをメール送信して、最後はエラー終了としている感じです。

スコープの実行条件の構成を調整する

エラー処理スコープ(CATCH)はメイン処理がエラーとなった場合に実行したいので、
「実行条件の構成」をエラー発生時、またはタイムアウト時に調整します。
デフォルトのままでは前の処理が成功した場合に実行されるようになっています。

こうすることで前の処理(スコープ TRY)でエラーまたはタイムアウトが発生した場合に動作し、正常終了の場合は動作しない制御が出来ます。

トリガー、変数の初期化アクションはスコープに含めれない

上記サンプルのように、トリガーはもちろん、変数の初期化アクションは最上位のレイヤーにいないといけないためスコープには含めることはできません。そのため、初期化アクションがある場合は上部のメイン処理のスコープより手前に定義する必要があります。
※一度しか使わない(変動しない)、作成アクションで事足りるようであれば変数アクションを使用しない手もあります

エラー情報の取得(Result)

式でresult()があります。これをスコープ(またはApply each)に対して使うと結果が取得出来ます。

公式リファレンスは以下
Reference guide for expression functions – Azure Logic Apps | Microsoft Learn

TIPSこのサンプルではエラー情報を取得してますが、実際エラー情報を通知に含めるかは必要に応じてでよいと思います。
エラー通知が来たらいずれにせよフローを確認して対処となると思いますので、通知するのみであれば、固定で「フローでエラーが発生しました。」レベルでもいいかなとも思います。
エラー内容によりその後の処理が変わる(通知ではなく別の処理にしたり)や別にエラーログを残す必要があるなどの場合は情報取得の部分は必要かなと思います。

 resultからエラー情報を取得する

上記でスコープ内の結果が取れますが、そこからステータスがFailedに等しいものでフィルターして、エラー時の情報(エラーアクションやエラーメッセージなど)を取得します。
以下でスコープ内でエラーがあったアクションが取れます。

NOTEスコープの名称がサンプルの「スコープ TRY」の場合になってます。メイン処理のスコープ名が異なる場合はこの部分をスコープ名に調整してください

Code差出人: @result(‘スコープ_TRY’) ※メイン処理を囲ったスコープを指定
@item()?[‘status’]:次の値に等しい:Failed ※ステータスがFailedに等しいでフィルタ

発生個所の階層によりエラー情報の構造が異なる

上記で取得したエラーアクションの結果ですが、直下のアクションがエラーとなった場合と配下のループ処理がエラーとなっている場合で取得される構造が異なります。

NOTEエラー対象が通常のアクションの場合とApply each配下のエラーの場合で形式が異なります。

以下、それぞれエラーが発生した場合のスコープのresultの結果ですが、データの構造が異なっています。
特にループがない場合は気にしなくてもいいですが、大体そういった処理は入っていると思いますので
今回のサンプルではどちらの場合も取れるように調整します。
※アクションの場合はCodeにBadRequestなどが入っているが、ループ内で配下のエラーではCodeには”ActionFailed”となっている※配下の詳細エラーまでは取れてない

直下の場合はOutPuts>Body>にStatusとmessageがある。ループの場合はerrorにcodeとmessageがある

両方のパターンでエラー情報を取れるように実装する

上記のとおり、エラー発生個所によってresult()で取れる結果の構造が異なるため、どちらの場合でも取れるように作成アクションで調整します。また、複数ある場合も最初のエラーを取得するようにしています。
以下のようにそれぞれの結果を並べて定義します。
最初のエラーのアクション名を取得、次の行で通常パターンのエラーメッセージ、続けてループ配下パターンのエラーメッセージを指定。無い場合は空欄となるためどちらかが取得できます。

Code@{body(‘アレイのフィルター処理_エラーアクション’)?[0]?[‘name’]}<br>
@{body(‘アレイのフィルター処理_エラーアクション’)?[0]?[‘outputs/body/message’]}@{body(‘アレイのフィルター処理_エラーアクション’)?[0]?[‘error/message’]}

workflow() 式を使ってフロー情報・作成者情報を取得し通知する

次にworkflow()を使ってクラウドフローの各種情報や作成者の情報を取得します。
この情報を使ってフロー編集画面へのリンクや作成者へのメール通知を行う事が出来ます。

workflow()の公式解説は以下
式関数のリファレンス ガイド – Azure Logic Apps | Microsoft Learn

以下ではO365 Userコネクタでフロー作成者IDを指定して表示名とメールアドレスを取得しています。

TIPS送付先が固定されている場合は必須ではありません。ただこうしておくと、フローをコピーして使ってもらう場合もそのフローの作成者宛に送信されるので便利です。

Code@{workflow()[‘tags’][‘createdBy’]}
→上記でフローの作成者のアドレスや表示名を取得している

メール通知をHTML形式で実装

以下のように、Workflow()式で取れた情報と通知先、表示名などを指定してメールでエラー通知します。
以下はサンプルで実装している内容です。適宜調整ください。

本文のエラー内容は上記で取得した最初のエラーアクション名とメッセージが入ります。
フローリンクは公式でもサンプルとして記載のある書き方で、このまま書けばフローの詳細画面へのリンクになってくれます。

宛先: @{outputs(‘ユーザープロフィールの取得(V2)’)?[‘body/mail’]}

件名:【フローエラー】 @{workflow()[‘tags’][‘flowDisplayName’]}でエラーが発生しました

本文:@{outputs(‘ユーザープロフィールの取得(V2)’)?[‘body/displayName’]}さん<br>
@{workflow()[‘tags’][‘flowDisplayName’]}でエラーが発生しました。<br>
<br>
エラー内容:@{outputs(‘作成_最初のエラーアクションメッセージ’)}<br>
<br>
詳細はフロー履歴より確認ください。<br>
<a href=https://flow.microsoft.com/manage/environments/@{workflow()[‘tags’][‘environmentName’]}/flows/@{workflow()[‘name’]}/details>フローを開く @{workflow()[‘tags’][‘flowDisplayName’]}

最後にエラー終了のアクションを追加

CATCH(エラー処理)スコープの最後に終了アクション>状態:失敗を追加します。
何もしないとエラー処理が正常終了したということでフロー履歴も正常終了となりパッと見わかりません。こうしておくと最終的に失敗したかがフローの履歴から分かります。

エラー通知メールサンプル

上記の場合、以下のようにフロー作成者へエラー通知が届きます。
最初の方はSPOリストの列名が存在しないというエラーですね。
次のエラーはループ処理内のアクションでのエラーという内容です(スコープ直下のエラー情報でないと正確には取れないので概要という感じですね)
2つのケースはエラーメッセージの持ち方が異なるのですがどちらも取得出来ています。


ループ内のエラーハンドルもそれぞれエラーチェックしてエラーがあったら配列に対象を追加、メール本文に追記するなども可能です。(その分の工数はかかりますが必要であれば)
サンプルではエラー発生の有無と概要までとして、詳細はフローを開いて解析・対応する前提の実装です。

エラーテンプレートの定義

最後に上記のテンプレートをコピペできるように以下に貼っておきます。展開してコピーしてください。
※トリガー、編集の初期化は省略しTRYスコープ、CATCHスコープのみです。

TIPSTRY部分はサンプルなので実際の実装に置き換えていただき、CATCHはそのまま使えるはずです。
TRYのスコープは「スコープ TRY」の前提となっているので、メイン処理のスコープ名が異なる場合は調整してください。

TRYスコープ定義
{"id":"07be104a-9031-40cc-8131-de8eef5ca236","brandColor":"#8C3900","connectionReferences":{"shared_sharepointonline":{"connection":{"id":"/providers/Microsoft.PowerApps/apis/shared_sharepointonline/connections/shared-sharepointonl-b07ef8c2-4976-4a38-b020-2aba40ca6c20"}},"shared_office365":{"connection":{"id":"/providers/Microsoft.PowerApps/apis/shared_office365/connections/shared-office365-5a7219fb-d4a1-4c13-a1bb-0a7ed0a70cc0"}},"shared_office365users":{"connection":{"id":"/providers/Microsoft.PowerApps/apis/shared_office365users/connections/6b555765586742a48553790860241542"}}},"connectorDisplayName":"制御","icon":"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzIiIGhlaWdodD0iMzIiIHZlcnNpb249IjEuMSIgdmlld0JveD0iMCAwIDMyIDMyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPg0KIDxwYXRoIGQ9Im0wIDBoMzJ2MzJoLTMyeiIgZmlsbD0iIzhDMzkwMCIvPg0KIDxwYXRoIGQ9Im04IDEwaDE2djEyaC0xNnptMTUgMTF2LTEwaC0xNHYxMHptLTItOHY2aC0xMHYtNnptLTEgNXYtNGgtOHY0eiIgZmlsbD0iI2ZmZiIvPg0KPC9zdmc+DQo=","isTrigger":false,"operationName":"スコープ_TRY","operationDefinition":{"type":"Scope","actions":{"複数の項目の取得_対象SPOリスト":{"type":"OpenApiConnection","inputs":{"host":{"connectionName":"shared_sharepointonline","operationId":"GetItems","apiId":"/providers/Microsoft.PowerApps/apis/shared_sharepointonline"},"parameters":{"dataset":"https://kurumeya.sharepoint.com/sites/NY","table":"7999837a-5930-4738-afe1-2a7381d92258","$filter":"status eq '申請中'"},"authentication":"@parameters('$authentication')"},"runAfter":{},"metadata":{"operationMetadataId":"eec58758-4526-4fed-af5f-d63138aa9bae"}},"Apply_to_each_承認リマインド":{"type":"Foreach","foreach":"@outputs('複数の項目の取得_対象SPOリスト')?['body/value']","actions":{"メールの送信_(V2)_承認処理リマインド通知":{"type":"OpenApiConnection","inputs":{"host":{"connectionName":"shared_office365","operationId":"SendEmailV2","apiId":"/providers/Microsoft.PowerApps/apis/shared_office365"},"parameters":{"emailMessage/To":"@items('Apply_to_each_承認リマインド')?['approver/Email']","emailMessage/Subject":"@{items('Apply_to_each_承認リマインド')?['Title']}の承認をしてください","emailMessage/Body":"<p><br>\nタイトル:@{items('Apply_to_each_承認リマインド')?['Title']}<br>\n申請者:@{items('Apply_to_each_承認リマインド')?['Author/DisplayName']}<br>\n申請日:@{convertFromUtc(items('Apply_to_each_承認リマインド')?['OData__x7533__x8acb__x65e5_'], 'Tokyo Standard Time', 'yyyy/MM/dd')}<br>\n</p>","emailMessage/Cc":"@items('Apply_to_each_承認リマインド')?['Author/Email']","emailMessage/Importance":"Normal"},"authentication":"@parameters('$authentication')"},"runAfter":{},"metadata":{"operationMetadataId":"0e532f12-6d0c-4bc1-bf72-d89cee30135d"}}},"runAfter":{"複数の項目の取得_対象SPOリスト":["Succeeded"]},"metadata":{"operationMetadataId":"14aa61c7-3196-484d-b691-a939a2af8ab8"}}},"runAfter":{"変数を初期化する_管理者メールアドレス":["Succeeded"]},"metadata":{"operationMetadataId":"8527ea0b-da4b-4a7c-9481-0013426ad982"}}}

CATCHスコープ定義
{"id":"531d299e-7de5-4e5d-9fd8-c19f03663966","brandColor":"#8C3900","connectionReferences":{"shared_sharepointonline":{"connection":{"id":"/providers/Microsoft.PowerApps/apis/shared_sharepointonline/connections/shared-sharepointonl-b07ef8c2-4976-4a38-b020-2aba40ca6c20"}},"shared_office365":{"connection":{"id":"/providers/Microsoft.PowerApps/apis/shared_office365/connections/shared-office365-5a7219fb-d4a1-4c13-a1bb-0a7ed0a70cc0"}},"shared_office365users":{"connection":{"id":"/providers/Microsoft.PowerApps/apis/shared_office365users/connections/6b555765586742a48553790860241542"}}},"connectorDisplayName":"制御","icon":"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzIiIGhlaWdodD0iMzIiIHZlcnNpb249IjEuMSIgdmlld0JveD0iMCAwIDMyIDMyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPg0KIDxwYXRoIGQ9Im0wIDBoMzJ2MzJoLTMyeiIgZmlsbD0iIzhDMzkwMCIvPg0KIDxwYXRoIGQ9Im04IDEwaDE2djEyaC0xNnptMTUgMTF2LTEwaC0xNHYxMHptLTItOHY2aC0xMHYtNnptLTEgNXYtNGgtOHY0eiIgZmlsbD0iI2ZmZiIvPg0KPC9zdmc+DQo=","isTrigger":false,"operationName":"スコープ_CATCH","operationDefinition":{"type":"Scope","actions":{"ユーザー_プロフィールの取得_(V2)":{"type":"OpenApiConnection","inputs":{"host":{"connectionName":"shared_office365users","operationId":"UserProfile_V2","apiId":"/providers/Microsoft.PowerApps/apis/shared_office365users"},"parameters":{"id":"@workflow()['tags']['createdBy']","$select":"mail,displayName"},"authentication":"@parameters('$authentication')"},"runAfter":{},"description":"フロー作成者のプロフィール取得","metadata":{"operationMetadataId":"20fb5531-7a00-4ba7-b54c-c9009f1169e0"}},"メールの送信_(V2)_エラーメール":{"type":"OpenApiConnection","inputs":{"host":{"connectionName":"shared_office365","operationId":"SendEmailV2","apiId":"/providers/Microsoft.PowerApps/apis/shared_office365"},"parameters":{"emailMessage/To":"@outputs('ユーザー_プロフィールの取得_(V2)')?['body/mail']","emailMessage/Subject":"【フローエラー】 @{workflow()['tags']['flowDisplayName']}でエラーが発生しました","emailMessage/Body":"@{outputs('ユーザー_プロフィールの取得_(V2)')?['body/displayName']}さん<br>\n@{workflow()['tags']['flowDisplayName']}でエラーが発生しました。<br>\n<br>\nエラー内容:@{outputs('作成_最初のエラーアクションメッセージ')}<br>\n<br>\n詳細はフロー履歴より確認ください。<br>\n<a href=https://flow.microsoft.com/manage/environments/@{workflow()['tags']['environmentName']}/flows/@{workflow()['name']}/details>フローを開く @{workflow()['tags']['flowDisplayName']}</a>","emailMessage/Cc":"@variables('管理者メールアドレス')","emailMessage/Importance":"High"},"authentication":"@parameters('$authentication')"},"runAfter":{"作成_最初のエラーアクションメッセージ":["Succeeded"]},"description":"フロー作成者へエラー通知 フローの詳細画面へのリンク","metadata":{"operationMetadataId":"30ebd89f-c057-4add-9f5c-f4f3a635cc71"}},"終了_エラー終了":{"metadata":{"operationMetadataId":"92d91ce7-869e-432b-b6d5-39a7ad93ef4b"},"type":"Terminate","inputs":{"runStatus":"Failed"},"runAfter":{"メールの送信_(V2)_エラーメール":["Succeeded"]}},"アレイのフィルター処理_エラーアクション":{"type":"Query","inputs":{"from":"@result('スコープ_TRY')","where":"@equals(item()?['status'], 'Failed')"},"runAfter":{"ユーザー_プロフィールの取得_(V2)":["Succeeded"]},"metadata":{"operationMetadataId":"5a7a6fea-7f5f-43d4-99a3-cc2d4a13d11b"}},"作成_最初のエラーアクションメッセージ":{"type":"Compose","inputs":"@{body('アレイのフィルター処理_エラーアクション')?[0]?['name']}<br>\n@{body('アレイのフィルター処理_エラーアクション')?[0]?['outputs/body/message']}\n@{body('アレイのフィルター処理_エラーアクション')?[0]?['error/message']}","runAfter":{"アレイのフィルター処理_エラーアクション":["Succeeded"]},"metadata":{"operationMetadataId":"2c89f9ce-2d25-43a1-9bd9-5dde8a37c853"}}},"runAfter":{"スコープ_TRY":["Failed","TimedOut"]},"metadata":{"operationMetadataId":"8768fe30-f5c2-490d-803a-fe2386bac8bf"}}}

フローへの貼り付け(現時点クラシック限定だと思います)

上記の定義内容をコピーしてフローを開き、「自分のクリップボード」を選択して
Ctrl+Vで張り付ければそれぞれスコープアクションが追加できるはずです。
貼り付け後は接続設定やTRYスコープの部分は調整し、CATCHは基本そのまま使えるはずです。

ちらっと試したところ、モダンデザイナーの方だとモダンデザイナー内で他のアクションをコピーしての貼り付けは出来ましたが、テキスト定義をコピーしたものからのコピーは出来ませんでした。(やり方が悪いのかもですが)
ひとまずクラシック限定の方法として記載しておきます。

自分のクリップボード>Ctrl+Vで張り付けて選択。スコープCATCHも同様

おわりに

今回はよく使うスコープを使ったTRY・CATCHの実装サンプルをご紹介しました。
TRY部分は実装によりさまざまですが、CATCHの部分は本サンプルそのままでも使えると思います。

そもそもしっかり作っていてもクラウドサービスなのでエラーが出るときは出ます。そういうものであるというご理解は作る側、利用側ともに重要です。
細かいエラーハンドルは実装やテストに工数がかかりますが、最低限これくらいを入れておけばエラー時に気付け早急なリカバリー対応が可能です。

正直エラーハンドルは重要ではありますが、そこに時間をかけたくないよーというのは開発時代から思っててw
ただ全くないのは運用面で困るケースあるので、このテンプレートを使ってもらったり参考にしてもらって、最低限通知する仕組みを入れつつ、メインでやりたい部分に注力いただければと思います。

またアクション(とくにスコープを使った)クリップボードコピーは大変便利なのでこの点だけ別で記事にしました。こちらも併せてご参考ください。それでは!

関連記事




この記事は役に立ちましたか?

もし参考になりましたら、下記のボタンで教えてください。

ヨウセイ

ヨウセイ

一般職からSharePoint、C#、.NET系技術者へ、そこからPower App、Power Automate技術者へと転身。 ワンランク上のおっさんはPower Appsでシステム開発が出来る〜! qiitaや自社HPでも技術ブログを書いていました。

関連記事

コメント

この記事へのコメントはありません。

CONTENTS