Durable Functions トラブルシューティング ガイド

Durable Functions は、通常のコードを使用してサーバーレス オーケストレーションを構築できる Azure Functions の拡張機能です。 Durable Functions の詳細については、Durable Functions の概要に関する記事をご覧ください。

この記事では、Durable Functions アプリで一般的なシナリオのトラブルシューティングを行うためのガイドを提供します。

注意

Microsoft サポート エンジニアがアプリケーションに関する問題の診断をお手伝いします。 このガイドを使用して問題を診断できない場合は、Azure portal の関数アプリ ページの [サポートとトラブルシューティング] セクションの [新しいサポート リクエスト] ブレードにアクセスして、サポート チケットを提出できます。

Screenshot of support request page in Azure Portal.

ヒント

問題のデバッグと診断を行う場合は、アプリで Durable Functions 拡張機能の最新バージョンが使用されていることを確認することから始めるようお勧めします。 ほとんどの場合、最新バージョンを使用すると、他のユーザーによって既に報告されている既知の問題が軽減されます。 拡張機能のバージョンをアップグレードする方法については、「Durable Functions 拡張機能のバージョンをアップグレードする」の記事を参照してください。

Azure portalの [問題の診断と解決] タブは、アプリケーション関連の考えられる問題を監視および診断するのに役立つリソースです。 また、診断に基づいて、問題への考えられる解決策も提供します。 詳細については、「Azure Functions アプリ診断」を参照してください。

上記のリソースで問題が解決しない場合は、以降のセクションで特定のアプリケーションの症状に関するアドバイスを提供します。

オーケストレーションが Pending 状態でスタックしている

オーケストレーションを開始すると、Durable 拡張機能によって管理されている内部キューに "開始" メッセージが書き込まれ、オーケストレーションの状態が "Pending" に設定されます。 オーケストレーション メッセージが取得され、使用可能なアプリ インスタンスによって正常に処理されると、状態は "Running" (または "Pending" 以外の他の状態) に遷移します。

"Pending" 状態で無期限にスタックしたままのオーケストレーション インスタンスをトラブルシューティングするには、次の手順を使用します。

  • Durable Task Framework トレースで、影響を受けたオーケストレーション インスタンス ID の警告またはエラーを確認します。 サンプル クエリについては、「エラーまたは警告をトレースする」セクションを参照してください。

  • スタックしているオーケストレーターに割り当てられている Azure Storage コントロール キューを調べて、その "開始メッセージ" がまだ存在するかどうかを確認します。コントロール キューの詳細については、Azure Storage プロバイダーのコントロール キューのドキュメントを参照してください。

  • アプリのプラットフォーム構成のバージョンを "64 ビット" に変更します。 アプリがメモリ不足のため、オーケストレーションが開始されない場合があります。 64 ビット プロセスに切り替えると、より多くの合計メモリをアプリに割り当てることができます。 これは、App Service の Basic、Standard、Premium、Elastic Premium プランにのみ適用されます。 Free プランまたは従量課金プランでは、64 ビット プロセスはサポートされていません

長い遅延後にオーケストレーションが開始される

通常、オーケストレーションはスケジュールされてから数秒以内に開始されます。 ただし、特定のケースでは、オーケストレーションの開始に時間がかかることがあります。 オーケストレーションの実行を開始するのに数秒以上かかる場合にトラブルシューティングを行うには、次の手順を使用します。

オーケストレーションが完了しないか、Running 状態でスタックしている

オーケストレーションが長時間 "Running" 状態のままである場合、通常は、スケジュール設定されている実行時間の長いタスクが完了するまで待機していることを意味します。 たとえば、持続的タイマー タスク、アクティビティ タスク、または外部イベント タスクが完了するのを待機している場合があります。 ただし、スケジュールされたタスクが正常に完了したのにオーケストレーションがまだ進行していない場合は、オーケストレーションが次のタスクに進むのを妨げている問題がある可能性があります。 多くの場合、この状態のオーケストレーションは "スタック オーケストレーション" と呼ばれます。

スタック オーケストレーションのトラブルシューティングを行うには、次の手順に従います。

  • 関数アプリを再起動してみます。 この手順は、アプリまたは拡張機能コードの一時的なバグまたはデッドロックが原因でオーケストレーションがスタックしている場合に役立ちます。

  • Azure Storage アカウントのコントロール キューを確認して、キューが継続的に増加していないか確認します。 こちらの Azure Storage メッセージング KQL クエリを使用すると、オーケストレーション メッセージのデキューに関する問題を特定するのに役立ちます。 問題が 1 つのコントロール キューにのみ影響する場合は、特定のアプリ インスタンスにのみ存在する問題を示している可能性があります。その場合、スケールアップまたはスケールダウンして異常な VM インスタンスから離れると有効な場合があります。

  • 「Azure Storage メッセージング」セクションの Application Insights クエリを使用して、そのキュー名をパーティション ID としてフィルター処理し、そのコントロール キュー パーティションに関連する問題がないか探します。

  • Durable Functions のベスト プラクティスと診断ツール」のガイダンスを確認してください。 一部の問題は、既知の Durable Functions アンチパターンによって引き起こされる可能性があります。

  • Durable Functions でのバージョン管理に関するドキュメントを確認してください。 一部の問題は、実行中のオーケストレーション インスタンスへの破壊的変更によって発生する可能性があります。

オーケストレーションの実行速度が遅い

大量のデータ処理、内部エラー、コンピューティング リソースの不足が原因で、オーケストレーションの実行が通常よりも遅くなる場合があります。 次の手順を使用して、予想以上に実行に時間がかかっているオーケストレーションのトラブルシューティングを行います。

  • Durable Task Framework トレースで、影響を受けたオーケストレーション インスタンス ID の警告またはエラーを確認します。 サンプル クエリについては、「エラーまたは警告をトレースする」セクションを参照してください。

  • アプリで .NET インプロセス モデルを利用している場合は、延長セッションを有効にすることを検討してください。 延長セッションでは、処理速度の低下を招く場合がある履歴の読み込みを最小限に抑えられます。

  • パフォーマンスとスケーラビリティのボトルネックを確認します。 アプリケーションのパフォーマンスは多くの要因によって決まります。 たとえば、CPU 使用率が高い場合やメモリ消費量が多い場合は、遅延が発生することがあります。 詳細なガイダンスについては、「Durable Functions のパフォーマンスとスケーリング」を参照してください。

サンプル クエリ

このセクションでは、Azure Functions アプリ用に構成された Azure Application Insights インスタンスでカスタム KQL クエリを作成して、問題のトラブルシューティングを行う方法について説明します。

Azure Storage メッセージング

既定の Azure Storage プロバイダーを使用する場合、すべての Durable Functions の動作は Azure Storage キュー メッセージによって決定され、オーケストレーションに関連するすべての状態はテーブル ストレージと BLOB ストレージに格納されます。 Durable Task Framework トレースが有効になっている場合、すべての Azure Storage 操作が Application Insights に記録されます。このデータは、実行とパフォーマンスの問題をデバッグするうえで非常に重要です。

Durable Functions 拡張機能の v2.3.0 以降では、host.json ファイルのログ構成を更新して、これらの Durable Task Framework ログを Application Insights インスタンスに発行できます。 これを行う方法の詳細と手順については、Durable Task Framework のログに関する記事を参照してください。

次のクエリは、特定のオーケストレーション インスタンスに対するエンド ツー エンドの Azure Storage の相互作用を調べるためのクエリです。 startorchestrationInstanceID を編集して、時間の範囲とインスタンス ID でフィルター処理します。

let start = datetime(XXXX-XX-XXTXX:XX:XX); // edit this 
let orchestrationInstanceID = "XXXXXXX"; //edit this
traces  
| where timestamp > start and timestamp < start + 1h 
| where customDimensions.Category == "DurableTask.AzureStorage" 
| extend taskName = customDimensions["EventName"]
| extend eventType = customDimensions["prop__EventType"] 
| extend extendedSession = customDimensions["prop__IsExtendedSession"]
| extend account = customDimensions["prop__Account"] 
| extend details = customDimensions["prop__Details"] 
| extend instanceId = customDimensions["prop__InstanceId"] 
| extend messageId = customDimensions["prop__MessageId"] 
| extend executionId = customDimensions["prop__ExecutionId"] 
| extend age = customDimensions["prop__Age"] 
| extend latencyMs = customDimensions["prop__LatencyMs"] 
| extend dequeueCount = customDimensions["prop__DequeueCount"] 
| extend partitionId = customDimensions["prop__PartitionId"] 
| extend eventCount = customDimensions["prop__TotalEventCount"] 
| extend taskHub = customDimensions["prop__TaskHub"] 
| extend pid = customDimensions["ProcessId"]
| extend appName = cloud_RoleName
| extend newEvents = customDimensions["prop__NewEvents"]
| where instanceId == orchestrationInstanceID
| sort by timestamp asc
| project timestamp, appName, severityLevel, pid, taskName, eventType, message, details, messageId, partitionId, instanceId, executionId, age, latencyMs, dequeueCount, eventCount, newEvents, taskHub, account, extendedSession, sdkVersion

エラーまたは警告をトレースする

次のクエリでは、特定のオーケストレーション インスタンスのエラーと警告を検索します。 orchestrationInstanceID の値を指定する必要があります。

let orchestrationInstanceID = "XXXXXX"; // edit this
let start = datetime(XXXX-XX-XXTXX:XX:XX); 
traces  
| where timestamp > start and timestamp < start + 1h
| extend instanceId = iif(isnull(customDimensions["prop__InstanceId"] ) , customDimensions["prop__instanceId"], customDimensions["prop__InstanceId"] ) 
| extend logLevel = customDimensions["LogLevel"]
| extend functionName = customDimensions["prop__functionName"]
| extend status = customDimensions["prop__status"]
| extend details = customDimensions["prop__Details"] 
| extend reason = customDimensions["prop__reason"]
| where severityLevel > 1 // to see all logs of  severity level "Information" or greater.
| where instanceId == orchestrationInstanceID
| sort by timestamp asc 

コントロール キューまたはパーティション ID のログ

次のクエリでは、instanceId のコントロール キューに関連付けられているすべてのアクティビティを検索します。 orchestrationInstanceID に instanceID の値を指定し、start にクエリの開始時刻を指定する必要があります。

let orchestrationInstanceID = "XXXXXX"; // edit this
let start = datetime(XXXX-XX-XXTXX:XX:XX); // edit this
traces  // determine control queue for this orchestrator
| where timestamp > start and timestamp < start + 1h 
| extend instanceId = customDimensions["prop__TargetInstanceId"] 
| extend partitionId = tostring(customDimensions["prop__PartitionId"])
| where partitionId contains "control" 
| where instanceId == orchestrationInstanceID
| join kind = rightsemi(
traces  
| where timestamp > start and timestamp < start + 1h 
| where customDimensions.Category == "DurableTask.AzureStorage" 
| extend taskName = customDimensions["EventName"]
| extend eventType = customDimensions["prop__EventType"] 
| extend extendedSession = customDimensions["prop__IsExtendedSession"]
| extend account = customDimensions["prop__Account"] 
| extend details = customDimensions["prop__Details"] 
| extend instanceId = customDimensions["prop__InstanceId"] 
| extend messageId = customDimensions["prop__MessageId"] 
| extend executionId = customDimensions["prop__ExecutionId"] 
| extend age = customDimensions["prop__Age"] 
| extend latencyMs = customDimensions["prop__LatencyMs"] 
| extend dequeueCount = customDimensions["prop__DequeueCount"] 
| extend partitionId = tostring(customDimensions["prop__PartitionId"])
| extend eventCount = customDimensions["prop__TotalEventCount"] 
| extend taskHub = customDimensions["prop__TaskHub"] 
| extend pid = customDimensions["ProcessId"]
| extend appName = cloud_RoleName
| extend newEvents = customDimensions["prop__NewEvents"]
) on partitionId
| sort by timestamp asc
| project timestamp, appName, severityLevel, pid, taskName, eventType, message, details, messageId, partitionId, instanceId, executionId, age, latencyMs, dequeueCount, eventCount, newEvents, taskHub, account, extendedSession, sdkVersion

Application Insights 列のリファレンス

上記のクエリによって射影された列とそれぞれの説明の一覧を次に示します。

説明
pid 関数アプリ インスタンスのプロセス ID。 これは、オーケストレーションの実行中にプロセスがリサイクルされたかどうかを判断するのに役立ちます。
taskName ログ記録されるイベントの名前。
eventType メッセージの種類。これは通常、オーケストレーターによって実行される作業を表します。 使用可能な値とその説明の全一覧については、こちらを参照してください。
extendedSession 延長セッションが有効かどうかを示すブール値。
account アプリによって使用されるストレージ アカウント。
details 特定のイベントに関する追加情報 (ある場合)。
instanceId 特定のオーケストレーションまたはエンティティ インスタンスの ID。
messageId 特定のキュー メッセージの一意の Azure Storage ID。 この値がよく表示されるのは、ReceivedMessage、ProcessingMessage、DeletingMessage トレース イベントです。 メッセージ ID はメッセージを送信した "後"に Azure Storage によって生成されるため、SendMessage イベントには表示されないことに注意してください。
executionId オーケストレーター実行の ID。continue-as-new が呼び出されるたびに変わります。
age メッセージがエンキューされてからのミリ秒数。 大きい数値はパフォーマンスの問題を示している場合が多いです。 例外は TimerFired メッセージの種類で、タイマーの期間に応じて Age 値が大きくなる可能性があります。
latencyMs ストレージ操作にかかるミリ秒数。
dequeueCount メッセージがデキューされた回数。 通常の状況では、この値は常に 1 です。 1 より大きい場合は、問題が発生している可能性があります。
partitionId このログに関連付けられているキューの名前。
totalEventCount 現在のアクションに関係する履歴イベントの数。
taskHub タスク ハブの名前。
newEvents ストレージ内の履歴テーブルに書き込まれる履歴イベントのコンマ区切りのリスト。