處理 Azure Functions 錯誤有助於避免資料遺失、避免錯過事件,並監控應用程式健康狀況。 這也是協助您了解事件型觸發程序的重試行為的重要方式。
本文說明錯誤處理和可用重試策略的一般策略。
重要事項
針對某些觸發器的重試政策支援預覽於 2022 年 12 月被移除。 支援的觸發器的重試策略現已正式推出(GA)。 本文的 重試 部分列出目前支援重試政策的擴充功能。
處理錯誤
Azure 函式中發生的錯誤可能來自:
- 使用內建的 Azure Functions 觸發器與繫結。
- 呼叫底層 Azure 服務的 API。
- 呼叫 REST 端點。
- 呼叫用戶端函式庫、套件或非 Microsoft API。
為避免資料遺失或錯過訊息,你應該練習良好的錯誤處理。 下表說明了一些建議的錯誤處理做法,並提供更多資訊連結:
| 建議 | 詳細資料 |
|---|---|
| 啟用 Application Insights | Azure Functions 與 Application Insights 整合,收集錯誤資料、效能資料及執行時日誌。 運用應用洞察(Application Insights)來發現並更深入理解函式執行中發生的錯誤。 欲了解更多,請參閱 Azure Functions 中的監控執行。 |
| 使用結構化錯誤處理 | 擷取及記錄錯誤對於監視應用程式的健康狀態至關重要。 任何函式程式碼的頂層都應該包含嘗試/接取區塊。 在 catch 區塊中,您可以擷取及記錄錯誤。 關於綁定可能產生的錯誤資訊,請參閱本文中的 綁定錯誤代碼 。 視您的特定重試策略而定,您可能也會引發新的例外狀況,以重新執行函式。 |
| 規劃你的重試策略 | Azure Functions 中的多個綁定擴充功能內建支援重試功能。 其他則允許你定義 Azure Functions 執行時實作的重試策略。 對於不提供重試行為的觸發器,可以考慮實施自己的重試方案。 欲了解更多資訊,請參閱本文中的 重試 。 |
| 冪等性設計 | 處理資料時發生錯誤可能是函式的問題,特別是在處理訊息時。 務必考慮發生錯誤時會發生什麼情況,以及如何避免重複處理。 欲了解更多,請參閱 設計Azure Functions以取得相同的輸入。 |
秘訣
當你使用輸出綁定時,無法處理存取遠端服務時產生的錯誤。 由於此行為,您應該驗證傳遞至輸出系結的所有數據,以避免引發任何已知的例外狀況。 如果您必須在函式程式碼中處理這類例外狀況,請使用用戶端 SDK 來存取遠端服務,而不是依賴輸出繫結。
重試
您的函式有兩種可以使用的重試方式:
- 個別觸發程序延伸模組的內建重試行為
- Azure Functions 執行環境提供的重試策略
下表指出哪些觸發程序支援重試,以及設定重試行為的位置。 它也會連結至來自基礎服務的錯誤詳細資訊。
| 觸發程序/繫結 | 重試來源 | 組態 |
|---|---|---|
| Azure Cosmos DB | 重試原則 | 函數層級 |
| Azure Blob 儲存體 | 綁定擴展 | host.json |
| Azure 事件方格 | 綁定擴展 | 事件訂閱 |
| Azure 事件中樞 | 重試原則 | 函數層級 |
| Kafka | 重試原則 | 函數層級 |
| Azure 佇列儲存體 | 綁定擴展 | host.json |
| RabbitMQ | 綁定擴展 | 死信佇列 |
| Azure 服務匯流排 | 綁定擴展 | host.json* |
| 計時器 | 重試原則 | 函數層級 |
* 需要 Azure 服務匯流排 擴充套件的 5.x 版本。 在較舊的擴充版本中,服務匯流排死字佇列實作重試行為。
重試原則
使用 Azure Functions,你可以為特定觸發類型定義重試政策。 執行時會強制執行這些重試策略。 以下觸發類型目前支援重試政策:
重試支援對 v1 和 v2 的 Python 程式設計模型都是一樣的。
除非成功完成或達到重試次數上限,否則重試原則會告知執行階段重新執行失敗的執行。
當支援的觸發程序類型執行的函式引發未處理的例外時,會評估重試原則。 最佳做法是,您應該攔截程式碼中的所有例外狀況,並針對任何想要導致重試的錯誤引發新的例外狀況。
重要事項
要等到執行的重試原則完成後,才會寫入事件中樞檢查點。 因此,該分割區的進度會暫停,直到當前批次完成處理。 欲了解更多資訊,請參閱 Reliable Event Processing with Azure Functions and Event Hubs。
Event Hubs 擴充套件的 5.x 版本支援額外的重試功能,用於 Azure Functions 主機與事件中心之間的互動。 更多資訊請參閱clientRetryOptionsEvent Hubs 的 host.json 參考文檔。
重試策略
您可以設定原則支援的兩個重試策略:
使用使用量方案時,您只需為函數程式碼執行的時間付費。 在上述任一重試策略中,兩次執行之間的等候時間不會向您收取費用。
最大重試次數
您可以設定在最終失敗前重試函式執行的次數上限。 目前的重試次數會儲存在實例的記憶體中。
執行個體在重試嘗試之間可能會失敗。 當執行個體在重試原則期間失敗時,重試計數就會遺失。 當實例失敗時,事件中心的觸發器可以恢復處理並在新實例上重試批次,重試次數會重置為零。 計時器觸發程序不會在新執行個體上繼續。
此行為表示重試計數上限是最佳數量。 在某些情況下,執行可能會重試超過要求次數的上限。 對於計時器觸發器,重試次數可能少於請求的最大次數。
重試範例
固定延遲和指數輪詢策略有提供範例。 要查看特定策略的範例,必須先在前一個分頁選擇該策略。
下列 NuGet 套件支援函式層級重試:
- Azure.Functions.Sdk 版本 1.0.0 及更新版本
- Microsoft。Azure.Functions.Worker.Extensions.EventHubs版本 5.2.0 及後續版本
- Microsoft。Azure.Functions.Worker.Extensions.Kafka版本 3.8.0 及後續版本
- Microsoft.Azure.Functions.Worker.Extensions.Timer 版本 4.2.0 及以後
[Function(nameof(TimerFunction))]
[FixedDelayRetry(5, "00:00:10")]
public static void Run([TimerTrigger("0 */5 * * * *")] TimerInfo timerInfo,
FunctionContext context)
{
var logger = context.GetLogger(nameof(TimerFunction));
logger.LogInformation($"Function Ran. Next timer schedule = {timerInfo.ScheduleStatus?.Next}");
}
| 屬性 | 描述 |
|---|---|
MaxRetryCount |
必要。 每個函式執行允許的重試次數上限。
-1 的值表示無限期重試。 |
DelayInterval |
兩次重試之間所使用的延遲。 將其指定為格式為 HH:mm:ss 的字串。 |
以下是在 function.json 檔案中定義的重試策略範例:
{
"disabled": false,
"bindings": [
{
....
}
],
"retry": {
"strategy": "fixedDelay",
"maxRetryCount": 4,
"delayInterval": "00:00:10"
}
}
您可以在重試原則定義上設定這些屬性:
| 屬性 | 描述 |
|---|---|
strategy |
必要。 要使用的重試策略。 有效值為 fixedDelay 和 exponentialBackoff。 |
maxRetryCount |
必要。 每個函式執行允許的重試次數上限。
-1 的值表示無限期重試。 |
delayInterval |
當你使用 fixedDelay 策略時,所使用的重試之間的延遲時間。 將其指定為格式為 HH:mm:ss 的字串。 |
minimumInterval |
當你使用策略 exponentialBackoff 時,重試延遲最短。 將其指定為格式為 HH:mm:ss 的字串。 |
maximumInterval |
當您使用 exponentialBackoff 策略時的最大重試延遲。 將其指定為格式為 HH:mm:ss 的字串。 |
你如何定義觸發器的重試政策,取決於你的 Node.js 版本:
這裡有一個使用固定延遲重試策略的計時器觸發函數範例:
const { app } = require('@azure/functions');
app.timer('timerTriggerWithRetry', {
schedule: '0 */5 * * * *',
retry: {
strategy: 'fixedDelay',
delayInterval: {
seconds: 10,
},
maxRetryCount: 4,
},
handler: (myTimer, context) => {
if (context.retryContext?.retryCount < 2) {
throw new Error('Retry!');
} else {
context.log('Timer function processed request.');
}
},
});
你如何定義觸發器的重試政策,取決於你的 Node.js 版本:
這裡有一個使用固定延遲重試策略的計時器觸發函數範例:
import { app, InvocationContext, Timer } from '@azure/functions';
export async function timerTriggerWithRetry(myTimer: Timer, context: InvocationContext): Promise<void> {
if (context.retryContext?.retryCount < 2) {
throw new Error('Retry!');
} else {
context.log('Timer function processed request.');
}
}
app.timer('timerTriggerWithRetry', {
schedule: '0 */5 * * * *',
retry: {
strategy: 'fixedDelay',
delayInterval: {
seconds: 10,
},
maxRetryCount: 4,
},
handler: timerTriggerWithRetry,
});
您可以在重試原則定義上設定這些屬性:
| 屬性 | 描述 |
|---|---|
strategy |
必要。 要使用的重試策略。 有效值為 fixedDelay 和 exponentialBackoff。 |
maxRetryCount |
必要。 每個函式執行允許的重試次數上限。
-1 的值表示無限期重試。 |
delayInterval |
當你使用 fixedDelay 策略時,所使用的重試之間的延遲時間。 將其指定為格式為 HH:mm:ss 的字串。 |
minimumInterval |
當你使用策略 exponentialBackoff 時,重試延遲最短。 將其指定為格式為 HH:mm:ss 的字串。 |
maximumInterval |
當您使用 exponentialBackoff 策略時的最大重試延遲。 將其指定為格式為 HH:mm:ss 的字串。 |
這裡有一個使用固定延遲重試策略的計時器觸發函數範例:
import logging
from azure.functions import AuthLevel, Context, FunctionApp, TimerRequest
app = FunctionApp(http_auth_level=AuthLevel.ANONYMOUS)
@app.timer_trigger(schedule="*/1 * * * * *", arg_name="mytimer",
run_on_startup=False,
use_monitor=False)
@app.retry(strategy="fixed_delay", max_retry_count="3",
delay_interval="00:00:01")
def mytimer(mytimer: TimerRequest, context: Context) -> None:
logging.info(f'Current retry count: {context.retry_context.retry_count}')
if context.retry_context.retry_count == \
context.retry_context.max_retry_count:
logging.info(
f"Max retries of {context.retry_context.max_retry_count} for "
f"function {context.function_name} has been reached")
else:
raise Exception("This is a retryable exception")
您可以在重試原則定義上設定這些屬性:
| 屬性 | 描述 |
|---|---|
strategy |
必要。 要使用的重試策略。 有效值為 fixed_delay 和 exponential_backoff。 |
max_retry_count |
必要。 每個函式執行允許的重試次數上限。
-1 的值表示無限期重試。 |
delay_interval |
當你使用 fixed_delay 策略時,所使用的重試之間的延遲時間。 將其指定為格式為 HH:mm:ss 的字串。 |
minimum_interval |
當你使用策略 exponential_backoff 時,重試延遲最短。 將其指定為格式為 HH:mm:ss 的字串。 |
maximum_interval |
當您使用 exponential_backoff 策略時的最大重試延遲。 將其指定為格式為 HH:mm:ss 的字串。 |
@FunctionName("TimerTriggerJava1")
@FixedDelayRetry(maxRetryCount = 4, delayInterval = "00:00:10")
public void run(
@TimerTrigger(name = "timerInfo", schedule = "0 */5 * * * *") String timerInfo,
final ExecutionContext context
) {
context.getLogger().info("Java Timer trigger function executed at: " + LocalDateTime.now());
}
在 Go 中,註冊函式時,可使用 sdk.WithRetry 和 sdk.RetryOptions 設定重試:
minimumInterval := 10 * time.Second
maximumInterval := 15 * time.Minute
app.Timer("TimerTriggerGo", timerHandler,
sdk.WithSchedule("0 */5 * * * *"),
sdk.WithRetry(&sdk.RetryOptions{
MaxRetryCount: 5,
MinimumInterval: &minimumInterval,
MaximumInterval: &maximumInterval,
Strategy: sdk.ExponentialBackoff,
}),
)
繫結錯誤碼
當你整合 Azure 服務時,錯誤可能來自底層服務的 API。 下列文章的<例外狀況和傳回碼>一節提供繫結特定錯誤的相關資訊: