【UiPath】リトライスコープ (Retry Scope) の豆知識

UiPath RPA デベロッパー上級資格試験 (UiARD) の勉強がてら、リトライスコープについて色々調べた内容をここに記します。

## 基本的な仕様
公式ドキュメントの説明は次の通り。
>**説明**
>条件が満たされないか例外がスローされる限り、含まれているアクティビティをリトライします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578020/c2e1194a-cb57-2fc5-be51-2080da3bfad4.png)

より細かく言うと、以下のどちらかの条件を満たした時に「アクション」の最初からリトライする。
- 「アクション」内のアクティビティをすべて実行した後、「条件」に指定したアクティビティが False を返す
- 「アクション」内、または「条件」に指定したアクティビティがキャッチされていないエラーを返す

また、独自のオプションとして以下の２つを設定できる。
> **リトライの回数** - シーケンスをリトライする回数です。
> **リトライの間隔** - 各リトライの合間の時間 (秒数) を指定します。

「リトライの回数」の既定は3回、「リトライの間隔」の既定は5秒に設定されている。


## 「条件」に指定できるアクティビティは限られる
「要素の存在を確認」や「テキストの存在を確認」など一部のアクティビティしか使えない。
論理値を返すアクティビティなら使えるのかと思いきや、「ファイルの存在を確認」などは使えない。
「True か確認」は論理値を返さないが（おそらく例外的に）使うことができる。


## 「リトライの回数」はアクションを実行する回数
「リトライの回数を1回に設定する」と聞くと、「エラーが起こったら1回リトライする」とも聞こえるが、
リトライスコープの「リトライの回数」は「アクションを実行する回数」に近い。

- リトライ回数 **1** の場合、アクションを一度実行して終わる。エラーが起こってもリトライしない。
- リトライ回数 **2** の場合、アクションを実行し、エラーが起こったら一度だけリトライする。
- リトライ回数 **0** の場合、アクションを一度も実行せずに終わる。


## 「条件」は何も設定しなくても良い
「条件」にアクティビティを置かなければ常にTrueを返すのと同じ扱いになる。
なので、この場合は単に「アクション」がエラーを返した時だけリトライする形になる。

以下の例だと`C:\Temp\Test.txt`のファイルが存在するかを5秒置きに確認し、3回目でも見つからなければエラーになる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578020/9765e5fb-7bf3-e4a4-abc4-be8486955753.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578020/9f6883e6-6556-1ec4-56ca-fcd470a73af1.png)


## 「アクション」も何も設定しなくて良い
逆に、「アクション」にも何を設定しなくてよい。
この場合は「条件」に指定したアクティビティがTrueを返すまでリトライする形になる。

以下は上の例の「アクション」にあるアクティビティを「条件」に移した例で、これも処理の流れは同じ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578020/a5054148-3500-f583-913a-53867909f70c.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578020/0e5d9f14-b4ae-68c9-f156-160a6e812798.png)


## 「True か確認」を使うなら「アクション」の最後に置いても「条件」に置いても同じ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578020/9765e5fb-7bf3-e4a4-abc4-be8486955753.png)![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578020/a5054148-3500-f583-913a-53867909f70c.png)
どちらでも結果は同じ。
ちなみに昔は「条件」に「True か確認」を置けなかったので、「Is True」アクティビティ（標準パッケージ外）で代用されたりもしていた。


## エラーになるまでの時間を考える時はアクティビティのプロパティも考慮に入れる
各アクティビティのプロパティが既定値として、
以下のワークフローは「要素の存在を確認」が対象ウィンドウを見つけられない時、100秒でエラーになる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578020/a0cc4c66-8c95-82f2-ed4c-b03e8a6eae9e.png)

各プロパティは既定値だと、
リトライスコープの「リトライ回数」が3回で、「リトライの間隔」が5秒、
要素の存在の確認の「タイムアウト」が30秒である。

リトライ回数が3回なので「要素の存在の確認」は3回実行される。
リトライの間隔が5秒なので、リトライする際に5秒の待ち時間が挟まる。
「要素の存在の確認」自体のタイムアウト時間が30秒なので、
30秒 + 5秒 + 30秒 + 5秒 + 30秒 のおよそ100秒（1分40秒）でエラーになる、という内訳。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578020/61b4b611-4203-ceb9-536f-d8842cd34ae0.png)


## 変数のスコープに考慮する
繰り返しアクティビティ等でも同じだが、内側のシーケンスにはリトライの度に都度入り直す形になるので、
スコープを内側のシーケンスに設定した変数はリトライの度に既定値に戻る。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578020/dfebf4b4-43d8-13cd-8c49-d31711031c10.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578020/cf65686b-0762-f9d1-1d9f-101b86c86b17.png)

これを防ぐには単にリトライスコープの外側のシーケンスに変数のスコープを設定すればよい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578020/7c070e34-b8cc-5ac0-378f-135111660382.png)

これを利用してリトライの度に変数を既定値に戻すのも考えられるが、もしスコープを変えられると台無しになるため、
戻したいならスコープに頼らず代入アクティビティなどで明示的に戻すか、別のワークフローとして切り出したほうがよさそう。

## エラーのスロー元はリトライスコープになる
まずリトライスコープ無しでのエラーのログを確認する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578020/c71dd30a-57d7-ec38-b712-2d2ad2bde1c5.png)
上のワークフローを実行すると、「Throw」アクティビティが「BusinessRuleException」を投げました、とログには表示される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578020/173641cb-e040-b91e-ee4b-89a9c6dedc17.png)

次に、リトライスコープが囲った場合のログを確認する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578020/46ed42ee-c8c1-4c9c-bcfe-a7faa339dcca.png)
「リトライスコープ」アクティビティが「BusinessRuleException」を投げたことになっている。
リトライスコープ内のどのアクティビティがエラーになったのかはこのログからは読み取れなくなるので注意。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578020/7fd283fe-7b3d-b3a4-ff37-33c98184dbdc.png)


## リトライスコープ内のエラーもグローバルハンドラーに拾われる
「リトライスコープ」の内部にシーケンスを挟まず直接アクティビティを置いた場合は拾われないが、シーケンスを挟むと拾われる。
（「トライキャッチ」アクティビティの挙動と同じ。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578020/0fbbb9a0-9021-ce9d-aa1d-b046f68b6db5.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578020/0fdce675-8136-b9a8-0a91-cb6ce9a89b37.png)

## 参考

https://docs.uipath.com/activities/lang-ja/docs/retry-scope

## 動作環境
UiPath.System.Activities 22.10.3