Logic Appsで配列を扱いたい

このエントリは2022/08/07現在の情報に基づいています。将来の機能追加や変更に伴い、記載内容との乖離が発生する可能性があります。

問い合わせ

先日、以下のような何とも漠然とした問い合わせが届いた。

Logic Appsで配列を扱うとしたら、どうするのがよいか?For eachを使うべきか?Untilループでくるくる回したほうがよいか?

あと、ループカウンター、というかインデックスの取得方法でよい方法はないか?

ちょっと突っ込んで聞いてみたところ、配列を含むJSONが渡されるとして、その配列要素を処理するにあたり、

  • できるだけ短時間で処理を終えたいのだがどうすればよいか
  • その配列要素の要素番号を取得できるのか、

ということを知りたかったらしい。

方法

配列を扱う場合、以下の方法が考えられる。

方法並列実行インデックスの取得子フローからの応答の取得
1Until loopを使うできないiterationIndexes()で取得可できる
2For eachのコンカレンシー制御を有効化し、同時実行を1にするできない変数でループカウンターを構成する必要ありできる
3For eachでコンカレンシー制御を有効化しない、もしくはコンカレンシー制御を有効化し、同時実行を2以上にするできる可能ではあるが…できる
4親子フローに分割し、子フローのトリガーでSplitOnを使うできるできないできない(永続ストアなどに書き出すなどの仕組みが必要)

1), 2) Until loop、もしくはFor eachのコンカレンシー制御を有効化して同時実行を1に設定する

原始的な方法ではあるが、順次実行していく、というもの。For eachで並列実行させないようにした場合でも同様。この場合はシングルスレッドでの実行であり、変数の競合はない。ただ、順次実行なので、時間がかかってしまう。

インデックス取得

結論から言うと、ループカウンターを明示的に宣言するしかない。

  • Untilの場合、iterationIndexes()関数でインデックスを取得できるが、ループの継続条件として利用できないので、結局ループカウンターを明示的に宣言せざるを得ない。
  • For eachの場合、Untilループとは異なり関数で取得できないため、明示的にループカウンター変数を宣言する必要がある。

3) For eachでコンカレンシー制御を有効化しない、もしくはコンカレンシー制御を有効化し、同時実行を2以上に設定する

この場合、マルチスレッドによる並列実行に変わる。変数を操作する場合は並列実行は推奨されないが、For eachの各スロットに渡した配列の各要素のみを使う場合、For eachの各スロットの最後で配列変数に値を追加するのであれば、変数操作による競合は発生しない。

インデックス取得

ループ回数というよりは、スレッド配列の何要素目で実行しているかを判断するための仕組みになってしまうが、これは理論的には以下の方法で可能。ただし、やり過ぎ感があるのは確か。

For each内で子フローを実行すると、以下のようなHTTP Headerが子フローのトリガー出力時に現れる。以下の例だと、7行目にあるように、test-parentという親フローから呼び出されていることがわかる。

{
    "headers": {
        "Accept-Language": "en-US",
        "User-Agent": "azure-logic-apps/1.0,(workflow ad920c5ccdec422d9b8ab4ed636194ac; version 08585437316453162658)",
        "x-ms-workflow-id": "ad920c5ccdec422d9b8ab4ed636194ac",
        "x-ms-workflow-version": "08585437316453162658",
        "x-ms-workflow-name": "test-parent",
        "x-ms-workflow-system-id": "/scaleunits/prod-00/workflows/ad920c5ccdec422d9b8ab4ed636194ac",
        "x-ms-workflow-run-id": "08585437316398251834604072740CU00",
        "x-ms-workflow-run-tracking-id": "69ad34b7-f7c1-4cc7-930c-7652f291c60d",
        "x-ms-workflow-operation-name": "Invoke_a_workflow_in_this_workflow_app",
        "x-ms-workflow-repeatitem-scope-name": "For_each",
        "x-ms-workflow-repeatitem-index": "7",
        "x-ms-workflow-repeatitem-batch-index": "0",
        "x-ms-tracking-id": "99040e54-988b-4ecc-b24e-49d30ce402ad",
        "x-ms-correlation-id": "99040e54-988b-4ecc-b24e-49d30ce402ad",
        "x-ms-client-request-id": "99040e54-988b-4ecc-b24e-49d30ce402ad",
        "x-ms-client-tracking-id": "08585437316398251834604072740CU00",
        "x-ms-action-tracking-id": "a98f51ca-05b5-4a85-a5ea-47c854ab0b93",
        "x-ms-activity-vector": "IN.06",
        "Content-Type": "application/json; charset=utf-8",
        "Content-Length": "12"
    },
    "body": {
        ...
    }
}

このHeaderを見ると、13行目にx-ms-workflow-repeatitem-indexというプロパティがあるが、これがFor each内の並列実行時のスレッドインデックスを示すもので、ゼロから開始する。今回の場合は7なので、少なくともこのスレッド配列の要素は8個は存在することがわかる。

この仕組みを使って、作成したダミーのフローを呼び出せば、x-ms-workflow-repeatitem-indexから、そのFor eachスレッドに割り当てられた配列の要素番号がわかる場合がある。ここで「わかる場合がある」と書いている理由は以下の通り。

For eachに渡された配列は、並列実行の最大値に到達していないのであれば、各スレッドに割り当てられる配列要素の要素番号と、x-ms-workflow-repeatitem-indexは一致する。ただし、並列実行の最大値以上の場合、For eachの各スレッドの処理が終わったら、未処理の配列要素を順次処理していくため、For eachに渡した配列の要素が、x-ms-workflow-repeatitem-indexと一致しなくなる。

Logic Appsの制約・制限は以下を参照。

Azure Logic Apps の制約と構成の参考文献 / Limits and configuration reference for Azure Logic Apps
https://docs.microsoft.com/azure/logic-apps/logic-apps-limits-and-config

4) トリガーでSplitOnを使う

以下のドキュメントに記載がある通り、トリガーでSplitOnプロパティを使うと、渡された配列をバッチ解除(debatching)して、配列の各要素がトリガーに渡る。

複数の実行をトリガーする / Trigger multiple runs
https://docs.microsoft.com/azure/logic-apps/logic-apps-workflow-actions-triggers#trigger-multiple-runs

この場合、SplitOnを設定したフローは非同期実行でなければならない。例えば親フローからSplitOnを構成した子フローを呼び出した場合、親フローにはHTTP 202が即時返却される。それゆえ、子フローの処理が終了したらその結果をどこかに書き出して、親フローが最後に集計するような、長時間実行時の取り扱いが必要。このあたりは、以下のエントリに記載している。

インデックス取得

配列がdebatchされているので、インデックスは子フローでは把握できない(親フローでもわからない)が、子フローの状態は、x-ms-action-tracking-idを使って追跡することは可能。

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中