【Power Automate】例外処理の実装方法

## はじめに
Power Automate の例外処理はテンプレートで公開されています。
<img width="400" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241051/99214c48-5e43-a896-6bde-5e713091de74.png">
しかし、これでは少し物足りないため、解説しつつ改良した例外処理をご紹介します。

## 基本的なフローの流れ
先ずは「Try」「Catch」「Finally」と３つの【スコープ】を用意して順に並べます。
Try の中にはメインの処理を記述し、Finally には毎回必ず処理したい内容を記述します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241051/b657e462-6560-c1f3-db56-79abf369c8ac.png)

## 実行条件の構成
Automate で例外処理を実現する上で重要な設定が **「実行条件の構成」** です。
スコープの三点リーダを押して、上記をメニューから選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241051/e03569d3-9620-9904-aa2e-0d4d3173e4f5.png)
通常は「に成功しました」にデフォルトでチェックが入っていますが、そのチェックを外して、「に失敗しました」（必要に応じて「がタイムアウトしました」）のチェックを入れて「完了」を押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241051/0bad60f8-91cd-2584-5d57-d617f8f2e523.png)
上記を設定すると、Try と Catch のスコープを繋ぐ矢印が赤色に変わります。
これにより、Try 内でエラー／タイムアウトが発生すると Catch に処理が流れるようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241051/44469c9a-7583-f297-7542-1bfbb3b93f89.png)
Finally も同様の手順で **４つ全て** のチェックを入れます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241051/c2861017-4b80-a39f-0102-071c8d95f44f.png)

## Catch スコープ内の実装
下記の流れのそれぞれの要素について説明します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241051/b08418c3-678a-36c1-eb3b-2c9aa2e06034.png)

### URLの生成
例外が発生したフローの「詳細画面」と「実行履歴詳細」画面に遷移するURLを生成します。

**[詳細画面イメージ]**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241051/dddacb87-4737-c1a6-6323-1596b51a9a96.png)

**[実行履歴詳細画面イメージ]**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241051/d43a4b4c-e273-065a-b109-26a20536710d.png)
「組み込み -> データ操作 -> 作成」アクションを２つ追加して、それぞれ以下の内容を入力することで、上記画面に遷移するURLを生成できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241051/b2f719c0-716c-e4cc-f5cf-a02a2ec1a6ec.png)

```powershell:フローの詳細画面の URL
https://make.powerautomate.com/manage/environments/@{workflow()['tags']['environmentName']}/flows/@{workflow()['name']}/details
```

```powershell:フローの実行履歴詳細の URL
https://make.powerautomate.com/manage/environments/@{workflow()['tags']['environmentName']}/flows/@{workflow()['name']}/runs/@{workflow()['run/name']}
```

### エラー内容の解析
「組み込み -> コントロール -> Apply to each」アクションを追加して、「以前の手順から出力を選択」の箇所に```result('Try')```を指定します。これにより、Try スコープで発生した複数のエラー情報に対して処理できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241051/7600d1dd-0c16-a9c8-ca99-f302b18a7402.png)
また、その中に「組み込み -> データ操作 -> JSON の解析」アクションを追加します。
「コンテンツ」には動的なコンテンツから```現在のアイテム```を選択してください。
そして「スキーマ」には下記の内容を入力します。
```json:スキーマ
{
    "type": "object",
    "properties": {
        "name": {
            "type": "string"
        },
        "inputs": {
            "type": "object",
            "properties": {
                "host": {
                    "type": "object",
                    "properties": {
                        "apiId": {
                            "type": "string"
                        },
                        "connectionReferenceName": {
                            "type": "string"
                        },
                        "operationId": {
                            "type": "string"
                        }
                    }
                },
                "parameters": {
                    "type": "object",
                    "properties": {
                        "dataset": {
                            "type": "string"
                        },
                        "table": {
                            "type": "string"
                        },
                        "id": {
                            "type": "integer"
                        }
                    }
                }
            }
        },
        "outputs": {
            "type": "object",
            "properties": {
                "statusCode": {
                    "type": "integer"
                },
                "headers": {
                    "type": "object",
                    "properties": {
                        "Vary": {
                            "type": "string"
                        },
                        "X-SharePointHealthScore": {
                            "type": "string"
                        },
                        "X-MS-SPConnector": {
                            "type": "string"
                        },
                        "X-SP-SERVERSTATE": {
                            "type": "string"
                        },
                        "DATASERVICEVERSION": {
                            "type": "string"
                        },
                        "SPClientServiceRequestDuration": {
                            "type": "string"
                        },
                        "X-DataBoundary": {
                            "type": "string"
                        },
                        "X-1DSCollectorUrl": {
                            "type": "string"
                        },
                        "X-AriaCollectorURL": {
                            "type": "string"
                        },
                        "SPRequestGuid": {
                            "type": "string"
                        },
                        "request-id": {
                            "type": "string"
                        },
                        "MS-CV": {
                            "type": "string"
                        },
                        "Strict-Transport-Security": {
                            "type": "string"
                        },
                        "X-FRAME-OPTIONS": {
                            "type": "string"
                        },
                        "Content-Security-Policy": {
                            "type": "string"
                        },
                        "MicrosoftSharePointTeamServices": {
                            "type": "string"
                        },
                        "X-Content-Type-Options": {
                            "type": "string"
                        },
                        "X-MS-InvokeApp": {
                            "type": "string"
                        },
                        "Timing-Allow-Origin": {
                            "type": "string"
                        },
                        "x-ms-apihub-cached-response": {
                            "type": "string"
                        },
                        "x-ms-apihub-obo": {
                            "type": "string"
                        },
                        "Cache-Control": {
                            "type": "string"
                        },
                        "Date": {
                            "type": "string"
                        },
                        "P3P": {
                            "type": "string"
                        },
                        "X-AspNet-Version": {
                            "type": "string"
                        },
                        "X-Powered-By": {
                            "type": "string"
                        },
                        "Content-Length": {
                            "type": "string"
                        },
                        "Content-Type": {
                            "type": "string"
                        },
                        "Expires": {
                            "type": "string"
                        },
                        "Last-Modified": {
                            "type": "string"
                        }
                    }
                },
                "body": {
                    "type": "object",
                    "properties": {
                        "status": {
                            "type": "integer"
                        },
                        "message": {
                            "type": "string"
                        }
                    }
                }
            }
        },
        "startTime": {
            "type": "string"
        },
        "endTime": {
            "type": "string"
        },
        "trackingId": {
            "type": "string"
        },
        "clientTrackingId": {
            "type": "string"
        },
        "clientKeywords": {
            "type": "array",
            "items": {
                "type": "string"
            }
        },
        "code": {
            "type": "string"
        },
        "status": {
            "type": "string"
        },
        "error": {
            "type": "object",
            "properties": {
                "code": {
                    "type": "string"
                },
                "message": {
                    "type": "string"
                }
            }
        }
    }
}
```
ちなみにこのスキーマの内容については、エラー発生時の「コンテンツ」の内容をコピーしておき、「JSON の解析」アクションの【サンプルから作成】に貼り付けることで生成できます。

**[エラー発生時のコンテンツ内容例]**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241051/d4d3a6cb-dd53-29f9-8175-98236d8cb9d5.png)
**[サンプルから作成するときの入力例]**
※ 上記コンテンツの内容を貼り付けて「完了」を押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241051/0c361f47-8924-6ee2-f2c2-b323630176a1.png)
ただし、エラーの内容によって JSON の内容も変わるので、上記で記載したスキーマはある程度のエラー内容ならカバーできるように盛り盛りにしてあります。

### 失敗判定
エラー内容を解析できたところで次は、その内容から処理に失敗しているかどうかを判定します。（ループ処理の名前を分かりやすく「Error Results Loop」としたものの、よく考えたらエラーで無いものも含まれるため、もう少し実態に合った名前にした方がいいかも・・・）

「組み込み -> コントロール -> 条件」アクションを追加して、左辺には「動的なコンテンツ」から```status```を選択してください。（status は２種類ありますが、下記イメージのように```body('JSON_の解析')?['status']```の方を選択してください）
そして右辺には```Failed```を入力してください。（文字列ですが、ダブルやシングルクオートの括りは不要）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241051/f0917be1-7839-2978-fe87-0b02f7f144fb.png)

### エラー通知（メール送信の例）
失敗判定が「はい」の方にエラーを通知する処理を追加します。
例では「メールの送信」としていますが、Teams への通知といった処理でもいいと思いますので、ご自由に処理を追加してください。

今回は「標準 -> Office 365 Outlook -> メールの送信 (V2)」アクションを追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241051/b6f51015-db77-8b70-8df5-76036a616749.png)
【本文】の内容をコピーしたものを下記に貼り付けておきます。
```:本文
フロー名　　： @{workflow()?['tags']?['flowDisplayName']}
アクション名： @{body('JSON_の解析')?['name']}
ステータス　： @{body('JSON_の解析')?['status']}
エラー内容　： @{body('JSON_の解析')?['code']}
@{body('JSON_の解析')?['outputs']?['body']?['message']}
@{body('JSON_の解析')?['error']?['message']}

【フローの詳細画面の URL】：
@{outputs('フローの詳細画面の_URL')}

【フローの実行履歴詳細の URL】：
@{outputs('フローの実行履歴詳細の_URL')}
```
**[存在しないリストを更新したときの通知内容例]**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241051/7402ad27-dc39-3b9c-e131-61d7d029bd98.png)

### 終了処理
最後に「組み込み -> コントロール -> 終了」アクションを追加します。
自分は特に何もしていませんが、必要に応じてカスタマイズしてみてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241051/589d320e-60f0-d167-7444-f3daad1e4bf7.png)
この後は Finally のスコープに処理が移りますが、自分は特に何も処理していないので、こちらも必要に応じて処理を追加してください。不要なら Finally スコープ自体消してしまってもいいと思います。

## 参考サイト
https://rksoftware.hatenablog.com/entry/2022/09/03/120000

## さいごに
いまのところ作成したフローには全て上記の例外処理を入れてありますが、共通化する方法がないか、もしくは今後のアップデートで出来るようになるといいなぁと思います。

また、ユニフェイスでは新しいことにチャレンジしたい人材を募集しておりますので、気になる方はぜひご応募お願いします😊
[技術ブログ](https://hub.uni-face.co.jp/)も公開していますのでこちらもチェックしてみてください！

https://uni-face.co.jp/