在 Azure 中診斷 Durable Functions

診斷長期函式的問題有數個選項。 其中一些選項與一般函式相同,某些則是長期函式特有的。

Application Insights

Application Insights 是在 Azure Functions 中診斷和監視的建議方式。 一樣適用於長期函式。 如需如何在您的函式應用程式中利用 Application Insights 的概觀,請參閱監視 Azure Functions

Azure Functions 長期延伸模組也會發出「追蹤事件」,可讓您追蹤協調流程的端對端執行。 您可以使用 Azure 入口網站中的 Application Insights Analytics 工具尋找及查詢這些追蹤事件。

追蹤資料

協調流程執行個體的每個生命週期事件會讓追蹤事件寫入到 Application Insights 中的追蹤集合。 這個事件包含具有數個欄位的 customDimensions 裝載。 欄位名稱前面都會加上 prop__

  • hubName:您的協調流程執行所在之工作中樞的名稱。
  • appName︰函式應用程式的名稱。 當您有多個函數應用程式共用相同的 Application Insights 執行個體時,此欄位會很有用。
  • slotName部署位置,目前的函式應用程式在其中執行。 當您使用部署位置來設定協調流程版本時,此欄位會很有用。
  • functionName:協調器或活動函式的名稱。
  • functionType:函式的類型,例如協調器活動
  • instanceId:協調流程執行個體的唯一識別碼。
  • state:執行個體的生命週期執行狀態。 有效值包括:
    • 已排程:函式已排程執行,但是尚未開始執行。
    • 已啟動:函式已開始執行,但是尚未等候或已完成。
    • 等候:協調器已排程一些工作,並且正在等候完成。
    • 接聽:協調器正在接聽外部事件通知。
    • 已完成:函式已順利完成。
    • 失敗:函式失敗,發生錯誤。
  • 原因:與追蹤事件相關聯的其他資料。 例如,如果執行個體正在等候外部事件通知,這個欄位會指出它正在等候之事件的名稱。 如果函式失敗,此欄位會包含錯誤詳細資料。
  • isReplay:布林值,指出追蹤事件是否要重新執行。
  • extensionVersion:長期工作延伸模組的版本。 版本資訊是報告延伸模組中可能 Bug 時特別重要的資料。 如果在長時間執行執行個體執行時發生更新,它可能會報告多個版本。
  • sequenceNumber:事件的執行序號。 與時間戳記結合,有助於依執行時間排序事件。 請注意,如果主機會在執行個體執行中重新啟動,這個數字將重設為零,所以務必一律先依 timestamp,然後依 sequenceNumber 進行排序。

您可以在 host.json 檔案的 logger (Functions 1.x) 或 logging (Functions 2.0) 區段中,設定發出至 Application Insights 之追蹤資料的詳細程度。

Functions 1.0

{
    "logger": {
        "categoryFilter": {
            "categoryLevels": {
                "Host.Triggers.DurableTask": "Information"
            }
        }
    }
}

Functions 2.0

{
    "logging": {
        "logLevel": {
            "Host.Triggers.DurableTask": "Information",
        },
    }
}

根據預設,會發出所有「非重新執行」的追蹤事件。 藉由將 Host.Triggers.DurableTask 設定為 "Warning""Error" 可以降低資料量,在此情況下,追蹤事件只會針對例外情況發出。 若要允許發出詳細的協調流程重新執行事件,請在 host.json 設定檔中將 logReplayEvents 設定為 true

注意

根據預設,Application Insights 遙測是由 Azure Functions 執行階段取樣,以避免過於頻繁發出資料。 這會在短期內發生太多生命週期事件時,造成追蹤資訊遺失。 Azure Functions 監視文章會說明如何設定這個行為。

預設不會記錄協調器、活動和實體函式的輸入和輸出。 建議使用這個預設行為,因為記錄輸入和輸出可能會增加 Application Insights 成本。 函式輸入和輸出承載也可能包含敏感性資訊。 因此,預設會改為記錄函式輸入和輸出的位元組數目,而不是實際承載。 如果您想要透過 Durable Functions 延伸模組記錄完整的輸入和輸出承載,請在 host.json 設定檔中將 traceInputsAndOutputs 屬性設定為 true

單一執行個體查詢

下列查詢顯示 Hello Sequence 函式協調流程之單一執行個體的歷史追蹤資料。 它是使用 Kusto 查詢語言撰寫的。 它會篩選重新執行,以便僅顯示「邏輯」執行路徑。 您可以藉由排序 timestampsequenceNumber 來排序事件,如下列查詢中所示:

let targetInstanceId = "ddd1aaa685034059b545eb004b15d4eb";
let start = datetime(2018-03-25T09:20:00);
traces
| where timestamp > start and timestamp < start + 30m
| where customDimensions.Category == "Host.Triggers.DurableTask"
| extend functionName = customDimensions["prop__functionName"]
| extend instanceId = customDimensions["prop__instanceId"]
| extend state = customDimensions["prop__state"]
| extend isReplay = tobool(tolower(customDimensions["prop__isReplay"]))
| extend sequenceNumber = tolong(customDimensions["prop__sequenceNumber"])
| where isReplay != true
| where instanceId == targetInstanceId
| sort by timestamp asc, sequenceNumber asc
| project timestamp, functionName, state, instanceId, sequenceNumber, appName = cloud_RoleName

結果是一份追蹤事件的清單,顯示協調流程的執行路徑,包括依執行時間以遞增順序排序任何活動函式。

Application Insights 單一實例已排序查詢

執行個體摘要查詢

下列查詢會顯示在指定時間範圍內執行之所有協調流程執行個體的狀態。

let start = datetime(2017-09-30T04:30:00);
traces
| where timestamp > start and timestamp < start + 1h
| where customDimensions.Category == "Host.Triggers.DurableTask"
| extend functionName = tostring(customDimensions["prop__functionName"])
| extend instanceId = tostring(customDimensions["prop__instanceId"])
| extend state = tostring(customDimensions["prop__state"])
| extend isReplay = tobool(tolower(customDimensions["prop__isReplay"]))
| extend output = tostring(customDimensions["prop__output"])
| where isReplay != true
| summarize arg_max(timestamp, *) by instanceId
| project timestamp, instanceId, functionName, state, output, appName = cloud_RoleName
| order by timestamp asc

結果是執行個體識別碼的清單,以及其目前的執行階段狀態。

Application Insights 單一實例查詢

長期工作架構記錄

Durable 延伸模組記錄可用於了解協調流程邏輯的行為。 不過,這些記錄不一定會包含足夠的資訊,以偵錯架構層級效能和可靠性問題。 從 Durable 延伸模組 v2.3.0 開始,基礎長期工作架構 (DTFx) 發出的記錄也可供收集。

查看 DTFx 發出的記錄時,請務必了解 DTFx 引擎是由兩個元件所組成:核心分派引擎 (DurableTask.Core),以及許多支援的儲存體提供者之一 (Durable Functions 預設使用 DurableTask.AzureStorage,但還有其他選項可供使用)。

  • DurableTask.Core:核心協調流程執行以及低階排程記錄和遙測。
  • DurableTask.AzureStorage:Azure 儲存體狀態提供者特定的後端記錄。 這些記錄包含與用來儲存和擷取內部協調流程狀態之內部佇列、Blob 和儲存體資料表的詳細互動。
  • DurableTask.Netherite:如果啟用,則為 Netherite 儲存體提供者特定的後端記錄。
  • DurableTask.SqlServer:如果啟用,則為 Microsoft SQL (MSSQL) 儲存體提供者特定的後端記錄。

您可以藉由更新函數應用程式 host.json 檔案的 logging/logLevel 區段來啟用這些記錄。 下列範例示範如何同時從 DurableTask.CoreDurableTask.AzureStorage 啟用警告和錯誤記錄檔:

{
  "version": "2.0",
  "logging": {
    "logLevel": {
      "DurableTask.AzureStorage": "Warning",
      "DurableTask.Core": "Warning"
    }
  }
}

如果您已啟用 Application Insights,這些記錄會自動新增至 trace 集合。 您可以搜尋記錄,就像是使用 Kusto 查詢搜尋其他 trace 記錄一樣。

注意

針對生產應用程式,建議您使用 "Warning" 篩選來啟用 DurableTask.Core 和適當的儲存體提供者 (例如 DurableTask.AzureStorage)。 詳細程度較高的篩選 (例如 "Information") 對於偵錯效能問題非常有用。 不過,這些記錄事件的數量可能很大,而可能大幅增加 Application Insights 資料儲存成本。

下列 Kusto 查詢示範如何查詢 DTFx 記錄。 查詢最重要的部分是 where customerDimensions.Category startswith "DurableTask",因為這會將結果篩選為 DurableTask.CoreDurableTask.AzureStorage 類別的記錄。

traces
| where customDimensions.Category startswith "DurableTask"
| project
    timestamp,
    severityLevel,
    Category = customDimensions.Category,
    EventId = customDimensions.EventId,
    message,
    customDimensions
| order by timestamp asc 

結果是一組由長期工作架構記錄提供者所寫入的記錄。

Application Insights DTFx 查詢結果

如需哪些記錄事件可用的詳細資訊,請參閱 GitHub 上的長期工作架構結構化記錄文件 (英文)。

應用程式記錄

直接從協調器函式寫入記錄時,請務必記住協調器重新執行行為。 例如,請考慮下列協調器函式:

[FunctionName("FunctionChain")]
public static async Task Run(
    [OrchestrationTrigger] IDurableOrchestrationContext context,
    ILogger log)
{
    log.LogInformation("Calling F1.");
    await context.CallActivityAsync("F1");
    log.LogInformation("Calling F2.");
    await context.CallActivityAsync("F2");
    log.LogInformation("Calling F3");
    await context.CallActivityAsync("F3");
    log.LogInformation("Done!");
}

產生的記錄資料看起來會像下列範例輸出:

Calling F1.
Calling F1.
Calling F2.
Calling F1.
Calling F2.
Calling F3.
Calling F1.
Calling F2.
Calling F3.
Done!

注意

請記住,當記錄宣告要呼叫 F1、F2 和 F3 時,這些函式只會在第一次遇到時「實際」被呼叫。 會略過重新執行期間發生的後續呼叫,且輸出會重新執行至協調器邏輯。

如果您只想要寫入非重新執行的執行記錄,您可以撰寫條件運算式,僅在「正在重新執行」旗標為 false 時記錄。 請考慮上面的範例,但是這次使用重新執行檢查。

[FunctionName("FunctionChain")]
public static async Task Run(
    [OrchestrationTrigger] IDurableOrchestrationContext context,
    ILogger log)
{
    if (!context.IsReplaying) log.LogInformation("Calling F1.");
    await context.CallActivityAsync("F1");
    if (!context.IsReplaying) log.LogInformation("Calling F2.");
    await context.CallActivityAsync("F2");
    if (!context.IsReplaying) log.LogInformation("Calling F3");
    await context.CallActivityAsync("F3");
    log.LogInformation("Done!");
}

從 Durable Functions 2.0 開始,.NET 協調器函式也可讓您選擇建立 ILogger,以在重新執行期間自動篩選出記錄陳述式。 此自動篩選是使用 IDurableOrchestrationContext.CreateReplaySafeLogger(ILogger) API 來完成。

[FunctionName("FunctionChain")]
public static async Task Run(
    [OrchestrationTrigger] IDurableOrchestrationContext context,
    ILogger log)
{
    log = context.CreateReplaySafeLogger(log);
    log.LogInformation("Calling F1.");
    await context.CallActivityAsync("F1");
    log.LogInformation("Calling F2.");
    await context.CallActivityAsync("F2");
    log.LogInformation("Calling F3");
    await context.CallActivityAsync("F3");
    log.LogInformation("Done!");
}

注意

先前的 C# 範例適用於 Durable Functions 2.x。 針對 Durable Functions 1.x,您必須使用 DurableOrchestrationContext 而不是 IDurableOrchestrationContext。 如需版本差異的詳細資訊,請參閱 Durable Functions 版本一文。

在先前提及的變更下,記錄輸出會如下所示:

Calling F1.
Calling F2.
Calling F3.
Done!

自訂狀態

自訂協調流程狀態可讓您為協調器函式設定自訂狀態值。 外部用戶端可接著透過 HTTP 狀態查詢 API 或透過特定語言的 API 呼叫來查看此自訂狀態。 自訂協調流程狀態能更進一步監視協調器函式。 例如,協調器函式程式碼可以叫用「設定自訂狀態」API,以更新長期執行作業的進度。 用戶端 (例如網頁或其他外部系統) 則無法定期查詢 HTTP 狀態查詢 API,以取得更豐富的進度資訊。 以下提供在協調器函式中設定自訂狀態值的範例程式碼:

[FunctionName("SetStatusTest")]
public static async Task SetStatusTest([OrchestrationTrigger] IDurableOrchestrationContext context)
{
    // ...do work...

    // update the status of the orchestration with some arbitrary data
    var customStatus = new { completionPercentage = 90.0, status = "Updating database records" };
    context.SetCustomStatus(customStatus);

    // ...do more work...
}

注意

先前的 C# 範例適用於 Durable Functions 2.x。 針對 Durable Functions 1.x,您必須使用 DurableOrchestrationContext 而不是 IDurableOrchestrationContext。 如需版本差異的詳細資訊,請參閱 Durable Functions 版本一文。

當協調流程執行時,外部用戶端能擷取該自訂狀態:

GET /runtime/webhooks/durabletask/instances/instance123?code=XYZ

用戶端將取得下列回應:

{
  "runtimeStatus": "Running",
  "input": null,
  "customStatus": { "completionPercentage": 90.0, "status": "Updating database records" },
  "output": null,
  "createdTime": "2017-10-06T18:30:24Z",
  "lastUpdatedTime": "2017-10-06T19:40:30Z"
}

警告

自訂狀態承載僅限為 16 KB 的 UTF-16 JSON 文字,因為它必須符合 Azure 資料表儲存體資料行的大小。 如果您需要較大的承載,可以使用外部儲存體。

分散式追蹤

分散式追蹤會追蹤要求,並顯示不同的服務如何彼此互動。 在 Durable Functions 中,也會將協調流程和活動關聯在一起。 這有助於了解此協調流程相對於整個協調流程所花費的時間步驟。 了解應用程式發生問題的位置或擲回例外狀況的位置也很有用。 所有語言和儲存體提供者都支援這項功能。

注意

分散式追蹤 V2 需要 Durable Functions v2.12.0 或更新版本。 此外,分散式追蹤 V2 處於預覽狀態,因此不會檢測某些 Durable Functions 模式。 例如,不會檢測持久性實體作業,而且不會在 Application Insights 中顯示追蹤。

設定分散式追蹤

若要設定分散式追蹤,請更新 host.json 並設定 Application Insights 資源。

host.json

"durableTask": {
  "tracing": {
    "distributedTracingEnabled": true,
    "Version": "V2"
  }
}

Application Insights

如果未使用 Application Insights 資源設定函數應用程式,請依照這裡的指示進行設定。

檢查追蹤

在 Application Insights 資源中,導覽至 [交易搜尋]。 在結果中,檢查以 Durable Functions 特定前置詞開頭的 RequestDependency 事件 (例如 orchestration:activity: 等)。 選取其中一個事件將會開啟甘特圖,顯示端對端分散式追蹤。

顯示 Application Insights 分散式追蹤的甘特圖。

疑難排解

如果您在 Application Insights 中看不到追蹤,請務必在執行應用程式之後等候大約五分鐘,以確保所有資料傳播至 Application Insights 資源。

偵錯

Azure Functions 支援直接偵錯函式程式碼,相同支援適用於長期函式,無論是在 Azure 中或在本機執行。 不過,在偵錯時有一些要注意的行為:

  • 重新執行:當收到新的輸入時,定期重新執行協調器函式。 此行為表示單一「邏輯」執行協調器函式會導致叫用相同的中斷點多次,特別是當它先前已在函式程式碼中設定時。
  • 等候:每當在協調器函式中遇到 await 時,它會將控制權讓回給長期工作架構發送器。 如果這是第一次遇到特定 await,相關聯工作「永不」繼續。 因為工作永不繼續,所以「跨越」等候 (在 Visual Studio 中為 F10) 並不可能。 跨越只有在重新執行工作時可行。
  • 訊息逾時:Durable Functions 會在內部使用佇列訊息,以驅動協調器、活動和實體函式的執行。 在多部 VM 的環境中,中斷至偵錯一段延伸的時間可能會造成另一個 VM 選取訊息,導致重複執行。 這種行為也會結束一般佇列觸發函式,但是務必要在此內容中指出,因為佇列是實作詳細資料。
  • 停止和啟動:Durable Functions 中的訊息會在偵錯工作階段之間保存。 如果您在 Durable Functions 執行時停止偵錯並終止本機主機處理序,該函式可能會在未來的偵錯工作階段中自動重新執行。 如未預期,此行為可能會造成混淆。 使用全新的工作中樞或清除偵錯工作階段之間的工作中樞內容,是一種避免此行為之技術。

提示

在協調器函式中設定中斷點時,如果您只想要在非重新執行的執行中斷,您可以設定條件中斷點,僅在 [正在重新執行] 值為 false 時中斷。

儲存體

根據預設,長期函式會將狀態儲存在 Azure 儲存體。 此行為表示您可以使用工具 (例如 Microsoft Azure 儲存體總管) 來檢查協調流程的狀態。

Azure 儲存體 總管螢幕快照

這對於偵錯相當有用,因為您會確實看到協調流程的狀態。 也可以檢查佇列中的訊息來了解哪些工作擱置 (在某些情況下停滯)。

警告

可以很方便地查看資料表儲存體中的執行歷程記錄,而且避免此資料表上有任何相依性。 當 Durable Functions 擴充功能進化時,此相依性可能會改變。

注意

您可以設定其他儲存體提供者,而不是預設的 Azure 儲存體提供者。 視您應用程式設定的儲存體提供者而定,您可能需要使用不同的工具來檢查基礎狀態。 如需詳細資訊,請參閱 Durable Functions 儲存體提供者文件。

Durable Functions 監視器

Durable Functions 監視器 是一種圖形化工具,可用於監視、管理和偵錯協調流程和實體實例。 它可作為 Visual Studio Code 延伸模組或獨立應用程式使用。 您可以在此 Wiki 中找到有關設定和功能清單的資訊。

Durable Functions 疑難排解指南

若要針對常見的問題徵兆進行疑難排解,例如協調流程停滯、無法啟動、執行速度緩慢等,請參閱此疑難排解指南

下一步