Dynamics 365 のワークフロー プロセスはコーディングなしでもデータの更新や作成・削除から割り当て、メール送信など多くのことを実行できる便利な機能です。既定のワークフロー プロセスだけでなく、Workflow Heroes にあるようなサードパーティー製のワークフローソリューションをインポートすれば、レコードの共有設定や日付・10進数の四則演算など、ユーザーの多くの要望をワークフロー プロセスで実現できるようになります。
ただ、こんな便利なワークフロー プロセスにおいても制限事項があります。特に運用で一番インパクトがあったのが無限ループを回避するための制限でした。
下記の技術情報にあるように、特定のレコードに対してプロセスが一定回数実行されると、無限ループとして検出されて「失敗」してしまいます。
無限ループの回避
・・・作成するワークフローには、無限ループを検出して停止するためのロジックが含まれます。 ワークフロー プロセスが、短時間に特定のレコードに対して一定の回数を超えて実行されると、次のエラーでそのプロセスは失敗します。このワークフロー ジョブは、それを開始したワークフローに無限ループが含まれるので取り消されます。ワークフロー ロジックを修正して、もう一度やり直してください。 回数の上限値は 16 です。
この制限事項には結構手を焼きまして、いろいろ試行錯誤して、どのタイミングで「失敗」してしまうのかがわかってきたので、その対策を含めてご紹介します。
どういったときにループを使うのか?
まずワークフロー プロセスをどういったときに使うか。私はよく上位下位関係のあるエンティティのレコードを上位から下位に対して一括更新する時や、前後関係のあるレコードの一部を削除した際、後続するレコードを更新する時などに使います。
例えば、下図のように営業案件に複数の活動が関連しており、これらの活動を開始の日付が古い順に番号を振りたいとします。
ここで、営業活動側でロールアップフィールドを作成して、活動で開始が一番古い(MIN)の日付を持ってきて、
その日付と一致した活動は一番古いだと判別できます。
上位から下位に対して日付が一致しているかどうかと番号を付与するプロセス、Ultimate Workflow Toolkit の 「Distribute Workflow」 を使って処理して行いました。
この営業案件のフィールドを更新する処理を活動数分繰り返すのですが、営業案件にぶら下がる活動数が多い場合、簡単に16回の制限を超えてしまうので、プロセスが無限ループとして検出され「失敗」します。
実行できるループの回数
1プロセス内の1ステップでレコードの更新を行い、その後に「子ワークフローの実行」で同プロセスを再度呼んでループを繰り返す検証を行ったところ、実際は15回目で「失敗」となりました。
そして、レコードの更新が行われたのは、14回でした。(15回目の更新時に、無限ループ検出されている)
そのため公式ドキュメントで記載されている16回よりも実際は少ないようです。(なぜかは不明)
次に、1 プロセスのステップで、レコードを複数回更新した場合、16 回以上のレコード更新を行うことができるかの検証しました。
1 プロセスに 4 ステップを追加して、営業案件レコードを更新後、同プロセスをループするようにしました。
この場合でも、15 回目で「失敗」となりました。
ただ、1 プロセス内でレコードを4回更新しているので、14 回 (成功したプロセス実行数) x 4 ステップ = 48回 レコードが更新されたことになります。最初の検証とは大きな違いです。1 プロセスのステップ数を増やせば、より多く更新することができるはずです。
これらの検証より、制限ギリギリまでループを実行したい場合は、1プロセス内でステップを多く活用して、同プロセスをループする方法が最適だとわかりました。
どのように対策をしたらいいか?
ただ、どんなに工夫をしてもループ回数制限にはひっかかります。どのようにループ回数制限とうまく付き合えばいいか。試行錯誤した結果、この方法であればうまくいくことがわかりました。
(あくまで個人的なアイディアです。もし他にいい方法があればコメントください)
上限を確認
ループさせたいプロセスが最大何回実行できるかを把握します。今回の場合は、15回目で失敗するので、14回がMAXかと思います。
14回実行されたらプロセスを停止するような条件文を追加しておけば、「失敗」が記録されることはないでしょう。
Batch Process を仕込む
以前の記事 Dynamics 365 バッチでプロセスを起動させる で触れた「Change Tracking Solution」の Batch Process を使って、15回目以降の処理は、バッチで時間を空けて処理します。
上記で設定した条件文のところで、「もし14回目になったら、バッチプロセスを作成するプロセスを実行する」のようなステップにしておきます。下図のように、「レコードの作成」で「Batch Process」を作成するエンティティとして設定します。
「プロパティの設定」を開いて、下図のようにBatch Process を作成してみます。呼び出すプロセスはループを実行するプロセスで、Next Activation はレコードが更新された5分後に設定しました。
「Taget Records」では Fetch XML を使えるので、「トピック(name)」が xxxxx である営業案件をターゲットに実行します。この xxxxx の箇所は動的な値にしたいので、右パネルの「検索」から、{トピック(営業案件)} という黄色塗りつぶしの動的な営業案件名を value 箇所に設定しています。
これで、14 回目までのループ処理は、初回のプロセスで実行され、15 回目以降は 5 分後にバッチで実行される同プロセスで処理されることになりました。
バッチ作成結果は下図の通りです。プロセスに Batch Process が作成されています。
内容を見てみると、意図したとおりに作成されていました。
かなり力技ですが、これでうまくワークフロープロセスをループする処理が実行できました。
今回は、少し曖昧な箇所(制限が16回と書いてありつつ、実際は15回目で失敗するところ)もある記事でしたが、
ワークフロープロセスでどうしてもループを実行したい際のアイディアとして参考いただければと思います。
今回はここまで。