10秒以内に返事をしないと拗ねてしまう妹を量産する Power Automate フロー

# はじめに
今回は*Do until*アクションを使っていろいろ遊んでみます。
[**アダプティブ カードを投稿して応答を待機する**]のアクションで、応答がなかったことを条件にループを終了させます。
後半では*Apply to each*でコンカレンシー制御をONにして、処理を並列に進める際のループの抜け方を説明します。

https://twitter.com/ksgiksg/status/1641980794003652609

# 1人の妹に愛されるフロー
## フローの概要
このフローでは、妹から送られてくるメッセージに10秒以内で返事をし続ける限り、メッセージが送り続けられるというものです。
逆に言うと、10秒で返事ができなかったときにループを終了させるものです。

フローの全体像はこのようになっています。
![make.powerautomate.com_environments_c282a6c7-dd13-e3fe-99b5-0460a4ecac01_flows_1598f7f4-b2b4-41a4-a6a5-5dbbda5053cc(PowerAutomate).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2572227/576727df-0212-ec06-eade-b78ad346c54c.png)

## フローの解説
### カードの情報
このスコープではアダプティブカードの情報をまとめて指定しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2572227/bde3fe07-222f-1299-7774-4ec66710bb85.png)

変数定義的なアクションはスコープにまとめて一か所で管理しておくと、メンテナンスや変更が楽になるのでオススメです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2572227/b880335a-3a9e-1108-2c17-7704de6493ac.png)

### ループの脱出フラグ
無限ループを抜けるかどうかの判定に使う変数です。
この`flg=true`になったときにループを終了させます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2572227/fd8ed10b-0c73-69b4-256a-ff359c945a61.png)

*Do until*アクションは、条件を満たした場合にループを終了させますが、初めから条件を満たしている場合も１度だけ処理を実行します。
Power Automate の画面上は条件を上の部分に書きますが、フローチャートでいうと以下のように条件式が下に来るような感じですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2572227/fe4ab132-9886-a8e5-816b-c9ca3f9c8c36.png)

flg変数の変更は**条件**アクションを使ってもいいのですが、今回は前のアクションがタイムアウトしたかどうかで判定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2572227/13a799c6-6ab4-a9ca-5d36-f1fa395f0d1f.png)

一見して何も条件判定を行っていないように見えますが、[実行条件の構成]から、[変数の設定]アクションが実行されるのが、前のアクション[アダプティブ カードを投稿しました]がタイムアウトした時だけになるように設定しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2572227/bb3cea16-35e0-c439-93db-58ffcdbea668.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2572227/b284d7f9-cef7-9cd1-67d2-586af037de39.png)

### 待機アクションのタイムアウト
ユーザーの応答を待機する系のアクションは、応答がないとずっと待ち続けてしまうことになるので、10秒以内に返事がなかったときに妹が拗ねるように変更します。

:::note info
正確にはずっと待ち続けるわけではなく、既定では30日でタイムアウトします。
:::

30日待たせるのもかわいそうなので、アクションの設定からタイムアウトの期間を10秒(**PT10S**)に設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2572227/c438c7f6-8283-b6e0-c79b-e486104e85bf.png)
期間はISO 8601形式で記述します。

https://ja.wikipedia.org/wiki/ISO_8601#%E7%B6%99%E7%B6%9A%E6%99%82%E9%96%93

### 少しだけ我慢する
返事があったのにすぐにまた聞き返すようでは、せっかちだと思われて嫌われてしまいます。
淑女たるもの我慢も必要ということで、5秒待つアクションを追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2572227/0ebefa09-c0b6-ff4f-5c53-f3428d58c3f5.png)

このアクションも実行条件の構成に注意が必要です。
[変数の設定]がスキップされた場合＝[アダプティブ カードを投稿しました]で返事があった場合に、ちゃんと待てるように設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2572227/bece9700-d649-323b-50ce-c45a47935d9c.png)


### 返事がなかった場合に拗ねる
これでフローは完成です。
返事がなくてループを終了してしまった後に、捨て台詞を言い残してフローを終わりにします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2572227/c836fbb2-4433-de99-e4f8-d9039a021be9.png)



# たくさんの妹に愛されるフロー
## フローの概要
1人では愛され度が足りないので、妹を量産します。
1人のときの妹の定義はフロー内で行っていましたが、管理ができるようにSharePointリストで情報をまとめます。

列の定義は、1人のときの[カードの情報]スコープと同じです。
[1行テキスト]列を使用していますが、URLが長い場合は[複数行テキスト]にしてもOKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2572227/d3e228ef-ee77-1ad1-641c-c48d8572224d.png)

基本的な構造は1人のときと同じで、そのアクションが*Apply to each*の中に入っています。
![make.powerautomate.com_environments_c282a6c7-dd13-e3fe-99b5-0460a4ecac01_flows_248654bf-7024-46d8-a886-f0dd71d9bc2b(PowerAutomate).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2572227/8854ecef-91e4-42a4-8786-821aaac18f0d.png)


ただし、脱出条件に使っている変数をそのまま使うと、**1人に返事ができなかったときに全ての妹に愛想をつかされてしまいます。**
なので、複数の処理を並列して動かす場合にはループを終了させる条件を考えないといけません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2572227/d4e396f3-5b64-2ae4-ab26-12a1dbd5c1f5.png)


## フローの解説
### 複数の妹の並列起動
SharePointリストの[複数の項目を取得]で定義した妹群を*Apply to each*で使用します。
そのままだと順次処理、1人ずつ妹を起動することになるので、並列処理ができるように設定を変更します。

*Apply to each*の設定からコンカレンシー制御をオンにしておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2572227/d1101d08-430b-41ae-94f2-1490bdaf10de.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2572227/c6ce8e86-5f2d-e28c-e969-cb4e2aed5c1f.png)

### ループの脱出フラグ
今回は変数を使いません。
変数を使おうと思った場合は、妹がいくつ生成されるかわからないため、動的に妹の数に合わせた変数を用意する必要があるからです。


[選択]アクションで配列変数を生成したり、JSON DictionaryとsetPropaty関数を使ったりする方法もありますが、難しくなるので今回は使用しません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2572227/86bd156f-6b3f-0f37-7eb5-f44f75f3a6a3.png)

https://wataruf.hatenablog.com/entry/2022/06/08/000000

### ループの終了条件
代わりに使うのがこちらの条件式です。
```Power fx:Do until
empty(body('アダプティブ_カードを投稿して応答を待機する'))
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2572227/904aa0e6-b346-8703-a21b-9bbc27cb0a52.png)

これは[アダプティブ カードを投稿して応答を待機する]アクションが**空**かどうかを判定する式になっています。

返事ができた場合は下のように、`body`にいろいろな情報が帰ってきているのがわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2572227/bd67bdfe-0838-7b5c-f9af-0e756c35d581.png)

逆に返事ができなかった場合＝タイムアウトした場合は、出力として返されるものがないので、`empty(body('アダプティブ_カードを投稿して応答を待機する'))`は`true`を返します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2572227/36ad87ea-2ab6-e822-bf03-6f36589a227e.png)

よって、条件部分は以下のように設定すればOKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2572227/f852ec88-54a8-0349-c183-52cbcb1d8a72.png)


なんとなく条件式をループの上側に記載する関係で、1つ前のループの結果を取得して判定しているように見えますが、フローチャートで図示した通り、実際に条件判定を行うのは処理の後の下の部分です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2572227/65b3bfd2-2596-f143-4d11-61d8c842448e.png)



# おわりに
午前中には間に合いませんでしたが、エイプリルフールということでネタっぽいフローの解説をしてみました。
*Apply to each*や*Do until*は、繰り返し処理としてワークフローの基本要素ですので、細かい設定や仕様を把握しておくと、できることの幅が広がると思います。

今回は以上です。