Azure Logic Apps 実行履歴の処理時間がズレる原因とパフォーマンス改善の測り方

Azure Logic Apps を使っていると、実行履歴(Run history)に表示される各アクションの所要時間が「足し算で合わない」「親より子の方が短いのに、親の表示が長い」といった違和感に出会います。本記事では、時間表示がズレて見える理由と、実際の処理時間を正しく計測・改善するための具体策を、ワークフロー設計の観点から整理します。

目次

起きていること:実行履歴の「所要時間」が一致しない

典型的には、メインワークフローがサブワークフローや Function App を呼び出し、さらに別のワークフローや外部 API を連鎖させる構成で発生します。例えば次のような流れです。

  • トリガー → 変数初期化 → do-while ループ
  • SQL コネクタで行取得(404 の場合は分岐)
  • 404 の場合にサブワークフローを呼び出して詳細検索
  • 別ワークフローで認証トークン取得(Function App を 2 つ呼び出し)
  • 取得したトークンで HTTP コネクタからサードパーティ API 呼び出し
  • 404 の場合は DB に insert してループ終了

このとき、親フローでは「サブワークフロー呼び出し」アクションが 6 秒と表示される一方、サブフロー側は 4.3 秒と表示されるなど、見た目の時間がかみ合わなくなります。さらにサブフローが呼び出す別フローや Function App でも同様の現象が連鎖し、「全体で 10 秒くらいかかっている。C# のアプリならもっと速いのでは?」と感じやすくなります。

結論:実行履歴の時間は「純粋な処理時間」ではなく「そのアクションが完了するまでのエンドツーエンド時間」

Logic Apps の実行履歴に表示される所要時間は、アクションが開始してから「そのアクションが完了と判定される」までの時間です。ここには、ビジネスロジックの実行時間だけでなく、オーケストレーションや通信などの周辺コストが含まれます。したがって、親と子、あるいは複数の階層で見たときに「数値がズレて見える」こと自体は珍しくありません。

実行履歴の所要時間に含まれやすい要素具体例ズレとして見える典型パターン
オーケストレーションのオーバーヘッドサブワークフロー起動、状態永続化、再開(リハイドレーション)親の「呼び出し」アクションが、子の実行時間より長く表示される
認証・権限チェックコネクタの接続情報検証、Managed Identity のトークン取得同じ API 呼び出しでも時々だけ遅い(初回が特に遅い)
ネットワークレイテンシDNS、TLS ハンドシェイク、経路混雑、リージョン間通信サブフロー内の HTTP は短いのに、親側の待機が伸びる
内部キューイング/スロットリング同時実行制御、コネクタのスロットル、バックエンドの待ち行列一定の負荷を超えた瞬間から、所要時間が階段状に増える
リトライ/ポーリング再試行ポリシー、長時間実行のポーリング(非同期完了待ち)失敗していないのに「1 回だけ極端に長い」実行が混ざる
Function App のコールドスタートConsumption/Premium の起動、依存ライブラリ読み込み子フローの 1 アクションだけが時々数秒伸びる

実行履歴の見方:どの値が「ズレ」を生みやすいか

実行履歴の画面では「Duration(所要時間)」だけが目立ちますが、原因を掘るときは、アクション詳細で表示される開始・終了タイムスタンプも一緒に見ます。特にサブワークフロー呼び出しや HTTP のような外部連携では、Duration は “待ち” を含むことが多いからです。

実行履歴で見る項目意味誤解しやすい点使いどころ
Started timeアクションが開始したとランタイムが判断した時刻「子の処理開始」とは一致しない(呼び出し準備や送信開始の可能性)遅延が発生し始めた地点の特定
Ended timeアクションが完了したと判断した時刻出力の受領や完了通知の待機を含むことがある待機が長いのか、実処理が長いのかの当たりを付ける
DurationStarted~Ended の差分内部キュー・認証・通信・ポーリングなどの合算で「内訳」が見えない運用上の監視(P95 など)には有用
Retry history / Statusリトライやスキップ等の状態成功していても裏で複数回試行されている場合がある「たまに遅い」の説明材料になる

なぜ親フローとサブフローの時間が「足し算で合わない」のか

親フロー上の「サブワークフロー呼び出し」アクションの時間は、ざっくり言うと次の式で考えると理解しやすくなります。

親の所要時間 ≒(子が実行される時間)+(呼び出しと待ち受けの固定費)+(観測のズレ)

イメージしやすい分解例

親で 6.0 秒、子で 4.3 秒と表示されるケースを、あくまで例として分解すると次のようになります。

  • 親:呼び出し要求の組み立て・接続確認(0.4 秒)
  • 親→子:バックエンド受け渡し・スケジューリング待ち(0.6 秒)
  • 子:実処理(4.3 秒)
  • 子→親:完了通知・出力受領・状態更新(0.7 秒)

このように、親の「c アクション」には子の実行以外の時間が含まれます。子側の 4.3 秒が「嘘」というわけではなく、親が見ている計測範囲がより広い(=待ちの固定費を含む)だけ、という理解が近いです。

計測の開始点・終了点がそもそも違う

親のアクションは「子を呼び出す要求を作って送る」瞬間から計測が始まります。一方、子フロー側の計測は「子が実行可能になり、最初のアクションを開始した」タイミングから始まります。両者の間には、バックエンドでの受け渡し・スケジューリングが挟まるため、同じ“仕事”を見ているようで、計測範囲は完全には一致しません。

並列実行や分岐があると、時間の足し算が成立しない

Scope(スコープ)内で並列分岐している、または do-while の中で複数の枝が条件で切り替わる場合、画面上の時間を単純に合計しても「実際の経過時間」と一致しません。並列に動いている枝は合計ではなく最大値に寄るためです。実行履歴は “アクション単体の観測” なので、全体像は「タイムライン」として捉えるのが安全です。

内部キューや状態管理が入る(Logic Apps の特性)

Logic Apps はワークフローを確実に実行・再開できるように、アクションごとの状態を管理し、必要に応じて永続化します。この仕組みは可観測性やリトライ耐性の面では強力ですが、純粋なメモリ内実行よりもオーバーヘッドが出ます。特に、ループや分岐が多い、サブフローを何度も呼び出す、という構成では「小さな固定費」が積み上がり、全体の体感を押し上げます。

コネクタは「外部サービスとの橋渡し」なので時間の内訳が見えにくい

SQL コネクタや HTTP コネクタの所要時間には、実際のクエリ/API 処理時間だけでなく、接続確立、認証、ゲートウェイ、スロットリング待ち、レスポンスの返却までの待ち時間が一体化して表示されます。さらに、サードパーティ API 側の遅延が一定でない場合、Logic Apps 側の実行履歴だけを眺めても原因が特定しにくくなります。

表示は「観測値」であり、丸めや非同期処理の影響を受ける

実行履歴は、あくまで Azure 側が観測したタイムスタンプから算出されます。複数のバックエンド(Logic Apps ランタイム、コネクタ、Function のホストなど)をまたぐため、タイムスタンプの粒度、表示の丸め、非同期完了の判定タイミングにより、数百ミリ秒〜数秒程度の差が積み上がることがあります。

「実際のビジネスロジック時間」を知りたい場合の計測方法

実行履歴は運用上の入口として便利ですが、性能検証では「ワークフロー全体」「外部呼び出し」「Function の中身」を分けて測ることが重要です。おすすめは、相関 ID(Correlation ID)を軸にした分散トレーシングです。

相関 ID を最初に作り、全呼び出しに渡す

トリガー直後に GUID を 1 つ生成し、以降のサブワークフロー呼び出し、Function App 呼び出し、外部 API 呼び出しのヘッダーやパラメータに載せます。これにより、ログを横断して「同じ 1 回の処理」が追えるようになります。

{
  "correlationId": "@{guid()}",
  "startedAt": "@{utcNow()}"
}

Function App では開始・終了を必ずログに残す

Function App 側の「本体処理時間」を知るには、開始直後と終了直前でタイムスタンプを記録し、その差分を Application Insights などに送るのが最短です。ポイントは、単にログを出すのではなく、相関 ID を customDimensions に入れて検索できる状態にすることです。

Logic Apps 側でも「開始」「終了」を明示的に残す

サブワークフローの入口と出口に utcNow() を書き込み、必要なら Compose で差分を計算してログとして出します。これにより、実行履歴の表示だけでは見えない「待ち時間(親から呼ばれて実行開始するまでの時間)」も推定できます。

計測したいものどこで測る記録する値得られる示唆
Function の純粋な処理時間Function のコード内開始/終了時刻、相関 IDビジネスロジックが遅いのか、呼び出しが遅いのかを切り分け
HTTP 呼び出しの実時間Function または API クライアント側送信/受信時刻、ステータス、リトライ回数API 側遅延、ネットワーク、TLS の影響を判定
ワークフロー全体の体感時間Logic Apps(トリガー直後と最後)開始/終了時刻、runId、相関 ID運用上の SLO(例:90〜99 パーセンタイル)を作れる
オーバーヘッド(差分)計測値の突合(実行履歴の時間)-(Function/外部の実測)スロットリング、キュー、状態管理の固定費を見積もれる

ボトルネック切り分けのためのチェックポイント

ズレの説明が付いたとしても、体感が遅いなら改善は必要です。改善の第一歩は「どこが遅いか」を誤判定しないことです。Logic Apps はオーケストレーターなので、遅さの原因は Logic Apps そのものではなく、呼び出し先や設計にあることが多いからです。

SQL コネクタ:取得量とクエリの形を疑う

  • 必要な列だけを取得しているか(SELECT * を避ける)
  • インデックスが効いているか(特に do-while の条件列)
  • 同じ行を何度も取りに行っていないか(ループ内の重複クエリ)
  • 1 件ずつ取りに行っていないか(可能ならバッチやページングにする)

SQL の遅延は「毎回一定に遅い」傾向があり、実行履歴でも比較的素直に反映されます。まずは DB 側の実行計画と待機イベントを確認し、Logic Apps に問題があると思い込まないのがコツです。

認証トークン取得:毎回取りに行く設計は要注意

認証トークン取得のために「別ワークフロー → Function App 1 → Function App 2」というチェーンを毎回回している場合、少しの固定費が積み上がって全体を押し上げます。トークンが数十分〜数時間有効なタイプなら、次のような工夫で体感を大きく改善できることがあります。

  • 1 回の実行(run)内ではトークンを変数に保持し、繰り返し取得しない
  • 複数の API 呼び出しで同じトークンが使えるなら、まとめて取得する
  • サードパーティ API が許すなら、トークンのキャッシュ層(例:Redis)を用意する
  • 可能であれば Managed Identity や接続の統合認証で “毎回の取得処理” を減らす

HTTP コネクタ:遅いのは Logic Apps ではなく相手かもしれない

HTTP 404 のように「結果はすぐ返ってくるはず」と想像していても、実際には相手側で検索やレート制限が発生していることがあります。次の観点で確認すると、原因が早く絞れます。

  • API の応答時間を相手側のログ(またはサポート)で確認できるか
  • API のレート制限(429)や遅延応答がないか
  • 同一リージョンから呼ぶと速いが、別リージョンからは遅いなどの地域差があるか
  • TLS ハンドシェイクが頻発していないか(接続再利用が効いているか)

do-while ループ:回数と待機を設計する

Logic Apps のループは便利ですが、短い周期で回し続けると、オーケストレーションの固定費が効いてきます。「404 の場合は insert して終了」のように条件が明確なら、ループ回数を減らす設計(1 回のクエリで判定できる形、または DB 側で状態を管理する形)に寄せるだけで、全体時間が目に見えて短くなることがあります。

改善の方向性:プランと構成で “効くレバー” が違う

パフォーマンス改善は、闇雲に速いプランにするより「どの遅さを消したいか」を決めて打つのが効果的です。特に、Logic Apps と Function App はそれぞれランタイム特性が異なり、効く対策も変わります。

Logic Apps(Consumption / Standard)の違いを意識する

同じ “Logic Apps” でも、運用形態によって実行の揺れ方が変わります。Standard(シングルテナント)はアプリとして常駐させやすく、ワークフローが温まっている状態を作りやすい一方、Consumption(マルチテナント)はスケールの恩恵を得やすい反面、バックエンドの共有状況でブレが出ることがあります。いずれも万能ではないため、狙うのが「平均の短縮」なのか「ばらつき(P95)の削減」なのかを先に決めると選びやすくなります。

コネクタの種類:Managed と Built-in で経路が違う

特に Standard では、ワークフロー内で “アプリ内で完結するコネクタ(Built-in)” と “サービス経由のコネクタ(Managed)” が混在し得ます。Managed コネクタは外部サービスとの間にコネクタ基盤が入りやすいため、認証・接続・待機の固定費が上乗せされることがあります。遅延の原因がコネクタ経路にありそうなら、同じ目的をより軽い経路で実現できないか(HTTP で直接呼ぶ、Built-in を使う等)を検討する価値があります。

Function App:コールドスタートが疑わしいなら実行環境を見直す

「初回だけ遅い」「一定時間アクセスがないと遅い」「時々だけ数秒伸びる」なら、Function App のコールドスタートが疑われます。一般的には、常時稼働に近い形(Always On 相当、プリウォーム、より安定したプラン)に寄せるとブレが減ります。ただし、これは “Function の起動待ち” を減らす効果であり、Logic Apps のオーケストレーション自体の固定費を消すものではありません。

サブワークフロー:分割の粒度を見直す

再利用性・可読性のためにサブワークフローを分割するのは良い設計です。しかし「呼び出し回数が多い」「1 回の処理が軽い」部分を細かく分けすぎると、呼び出しの固定費が相対的に大きくなります。次の基準で整理すると、過剰分割を避けやすくなります。

  • 1 回の呼び出しで実行する “本体処理” が 100〜200ms 程度しかないなら、統合候補
  • 同じ相手に連続で呼ぶなら、1 回のサブフローにまとめてバッチ化できないか検討
  • トークン取得 → API 呼び出し → 結果整形 など、常にセットなら一体化を検討

並列化:独立な処理は Parallel branch で短縮できる

「Function App を 2 つ呼ぶ」「複数の補助検索を並べて実行できる」など、依存関係がない処理は並列化の余地があります。Logic Apps の並列分岐を使うと、合計処理時間を最大値に近づけられる可能性があります。ただし、外部 API の同時呼び出しはスロットリングやレート制限を招くため、同時実行数の上限(Concurrency)とセットで設計します。

リトライとタイムアウト:速さのために “適切に諦める”

外部 API や SQL の瞬断に備えるリトライは重要ですが、既定のリトライが「体感を悪化させる」こともあります。例えば “404 の場合は別経路へ” のように次の手が決まっているなら、404 は即分岐し、余計なリトライを避けるのが有利です。また、タイムアウトを短くしすぎると逆にリトライが増えるので、API 側の SLA と合わせて設計します。

データ転送量:アクション間で巨大な JSON を渡さない

実行履歴の表示時間が長いとき、意外と効くのがデータ量です。SQL から大きな行を引き、サブワークフローにそのまま渡し、さらに Function に渡す、といった形は、ネットワークだけでなくシリアライズ/デシリアライズや状態保存のコストを押し上げます。必要最小限のフィールドに絞り、重いデータはストレージに置いて参照する、という分離が効くケースがあります。

よくある改善レバー効きやすい症状具体策注意点
コールドスタート対策初回だけ遅い/時々だけ遅いFunction の実行環境を安定化、依存を減らす固定費は残る。費用とのバランスが必要
呼び出し回数削減小さな処理の連鎖で全体が伸びるサブフロー統合、Function 統合、バッチ化再利用性とのトレードオフ
トークン取得の最適化認証だけで毎回数秒run 内キャッシュ、外部キャッシュ、統合認証セキュリティ要件に合わせた管理が必要
外部 API の最適化HTTP の揺れが大きいリージョン近接、リトライ設計、回数削減相手側仕様(レート制限)を優先
データ量削減JSON が肥大化、履歴表示も重い必要列だけ、参照設計、圧縮・ID 化運用時の可読性も考える

「C# のアプリなら速いはず」と感じたときの整理の仕方

結論から言うと、同じ処理を “単一プロセスの C#” で書けば、オーケストレーションや状態永続化の固定費が少ない分、レイテンシは小さくなりやすいです。一方、Logic Apps には「可視化」「運用しやすさ」「再試行」「コネクタ」「監査」「ノーコード運用」という強みがあります。重要なのは、要求性能に対して、どこまでの固定費を許容できるかです。

要求・状況Logic Apps が向くケースC# / Function 主体が向くケース
人や業務プロセスが関わる承認・通知・分岐が多い。失敗時の再実行や監査が重要—
外部サービス連携が中心コネクタで素早く実装し、運用で改善したい—
レイテンシが厳しい—サブ秒やミリ秒単位が必須。高頻度・高スループット
処理が CPU 集約—画像処理、重い変換、複雑なアルゴリズムなど
障害時の補償や再実行を簡単にしたいワークフローで可視化し、補償トランザクションを組みやすいDurable Functions 等で実装する選択肢もある(ただし設計負荷は上がりやすい)

運用の落とし穴:平均値ではなく “ばらつき” を見る

「だいたい 6 秒」と「たまに 20 秒」が混ざると、体感や SLA に大きく影響します。Logic Apps/Function/外部 API はいずれも共有基盤の影響を受けるため、平均値だけでは判断を誤ります。次のように、パーセンタイル(P90/P95/P99)で見ると実情に近づきます。

  • ワークフロー全体の P95 が許容範囲か
  • 遅い実行のとき、どのアクションが伸びているか
  • 伸びているアクションは毎回同じか、ランダムか

遅延がランダムならコールドスタートや外部要因、毎回同じなら設計やクエリが原因、といった仮説が立てやすくなります。

実務で効く “付き合い方” のまとめ

  • 実行履歴の所要時間は「オーケストレーションやネットワークを含むエンドツーエンド」であり、純粋な処理時間ではない
  • 親フローとサブフローの表示時間が合わないのは、計測範囲の差+固定費+観測のズレがあるためで、不具合とは限らない
  • 本当に速くしたいなら、相関 ID でログを貫通させ、Function/外部 API の実測と突合してボトルネックを特定する
  • 改善は「コールドスタート対策」「呼び出し回数削減」「トークン取得の最適化」「データ量削減」「並列化」「リトライ最適化」の順で当たりやすい
  • サブ秒が必須なら C#/Function 主体、数秒〜十数秒が許容される業務連携なら Logic Apps を中心に据える、という棲み分けが現実的

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次