處理 Azure Functions 中的錯誤十分重要,可協助您避免遺失資料、避免遺漏事件以及監視應用程式的健康情況。 這也是協助您了解事件型觸發程序的重試行為的重要方式。
本文說明錯誤處理和可用重試策略的一般策略。
重要事項
2022 年 12 月已移除特定觸發程序的預覽重試原則支援。 受支援觸發程序的重試原則現已正式發行 (GA)。 如需目前受支援重試原則的延伸模組清單,請參閱重試一節。
處理錯誤
Azure 函式中所發生的錯誤可能來自:
- 使用內建功能 觸發器和繫結
- 呼叫基礎 Azure 服務的 API
- 對 REST 端點的呼叫
- 對客戶端連結庫、套件或非Microsoft API 的呼叫
若要避免遺失資料或遺漏訊息,良好的錯誤處理做法十分重要。 下表描述一些建議的錯誤處理做法,並提供詳細資訊的連結。
| 建議 | 詳細資料 |
|---|---|
| 啟用 Application Insights | Azure Functions 與 Application Insights 整合,以收集錯誤資料、效能資料和執行階段記錄。 您應該使用 Application Insights 來探索並進一步了解函式執行中發生的錯誤。 若要深入瞭解,請參閱 監視 Azure Functions 中的執行。 |
| 使用結構化錯誤處理 | 擷取及記錄錯誤對於監視應用程式的健康狀態至關重要。 任何函式程式碼的最上層都應該包含 try/catch 區塊。 在 catch 區塊中,您可以擷取及記錄錯誤。 如需繫結可能引發哪些錯誤的相關資訊,請參閱繫結錯誤碼。 視您的特定重試策略而定,您可能也會引發新的例外狀況,以重新執行函式。 |
| 規劃重試策略 | 有數個 Functions 繫結延伸模組提供了內建的重試支援,其他延伸模組則可讓您定義 Functions 執行階段所實作的重試原則。 針對未提供重試行為的觸發程序,您應該考慮實作自己的重試配置。 如需詳細資訊,請參閱重試。 |
| 等冪性的設計 | 處理資料時發生錯誤可能是函式的問題,特別是在處理訊息時。 務必考慮發生錯誤時會發生什麼情況,以及如何避免重複處理。 若要深入了解,請參閱設計相同輸入的 Azure Functions。 |
秘訣
使用輸出繫結時,您無法處理存取遠端服務時所發生的錯誤。 由於此行為,您應該驗證傳遞至輸出系結的所有數據,以避免引發任何已知的例外狀況。 如果您必須在函式程式碼中處理這類例外狀況,請使用用戶端 SDK 來存取遠端服務,而不是依賴輸出繫結。
重試
函式有兩種可用的重試:
- 個別觸發程序延伸模組的內建重試行為
- Functions 執行階段提供的重試原則
下表指出哪些觸發程序支援重試,以及設定重試行為的位置。 它也會連結至來自基礎服務的錯誤詳細資訊。
| 觸發程序/繫結 | 重試來源 | 組態 |
|---|---|---|
| Azure Cosmos DB | 重試原則 | 函數層級 |
| Blob 儲存體 | 繫結延伸模組 | host.json |
| 事件方格 | 繫結延伸模組 | 事件訂閱 |
| 事件中樞 | 重試原則 | 函數層級 |
| Kafka | 重試原則 | 函數層級 |
| 佇列儲存體 | 繫結延伸模組 | host.json |
| RabbitMQ | 繫結延伸模組 | 無效信件佇列 |
| 服務匯流排 | 繫結延伸模組 | host.json* |
| 計時器 | 重試原則 | 函數層級 |
*需要 5.x 版的 Azure 服務匯流排延伸模組。 在舊版延伸模組中,重試行為是由服務匯流排無效信件佇列 (部分機器翻譯) 實作。
重試原則
Azure Functions 可讓您為特定的觸發程序類型定義執行階段所強制執行的重試原則。 以下觸發程序類型目前支援重試原則:
v1 和 v2 Python 程式設計模型有相同的重試支援。
1.x 版的 Functions 執行階段不支援重試原則。
除非成功完成或達到重試次數上限,否則重試原則會告知執行階段重新執行失敗的執行。
當受支援的觸發程序類型所執行的函式引發未攔截到的例外狀況時,系統就會評估重試原則。 最佳做法是,您應該攔截程式碼中的所有例外狀況,並針對任何想要導致重試的錯誤引發新的例外狀況。
重要事項
要等到執行的重試原則完成後,才會寫入事件中樞檢查點。 因為此行為,所以除非目前的批次已處理完成,否則特定分割區的進度會暫停。 如需詳細資訊,請參閱 Azure Functions 可靠的事件處理。
事件中樞擴充功能 5.x 版支援 Functions 主機與事件中樞之間互動的額外重試功能。 如需詳細資訊,請參閱事件中樞 host.json 參考 (部分機器翻譯) 中的 clientRetryOptions。
重試策略
您可以設定原則支援的兩個重試策略:
在使用量方案中執行時,您只需針對函式程式碼的執行時間支付費用。 在上述任一重試策略中,兩次執行之間的等候時間不會向您收取費用。
重試計數上限
您可以設定在最終失敗前重試函式執行的次數上限。 目前的重試計數會儲存於執行個體的記憶體中。
執行個體在重試嘗試之間可能會失敗。 當執行個體在重試原則期間失敗時,重試計數就會遺失。 發生執行個體失敗時,事件中樞觸發程序能夠繼續處理,並在新的執行個體上重試批次,並將重試計數重設為零。 計時器觸發程序不會在新執行個體上繼續。
此行為表示重試計數上限是最佳數量。 在某些情況下,執行可能會重試超過要求次數的上限。 針對計時器觸發程序,重試可以小於要求的次數上限。
重試範例
固定延遲和指數輪詢策略有提供範例。 若要查看特定策略的範例,您必須先在上一個索引標籤中選取該策略。
下列 NuGet 套件支援函式層級重試:
- Microsoft.Azure.Functions.Worker.Sdk>= 1.9.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 表示無限期重試。 |
| 延遲時間間隔 | 兩次重試之間所使用的延遲。 將其指定為格式 HH:mm:ss 的字串。 |
以下是 function.json 檔案中所定義重試原則的範例:
{
"disabled": false,
"bindings": [
{
....
}
],
"retry": {
"strategy": "fixedDelay",
"maxRetryCount": 4,
"delayInterval": "00:00:10"
}
}
您可以在重試原則定義上設定這些屬性:
| 屬性 | 描述 |
|---|---|
| 策略 | 必要。 要使用的重試策略。 有效值為 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,
});
您可以在重試原則定義上設定這些屬性:
| 屬性 | 描述 |
|---|---|
| 策略 | 必要。 要使用的重試策略。 有效值為 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")
您可以在重試原則定義上設定這些屬性:
| 屬性 | 描述 |
|---|---|
| 策略 | 必要。 要使用的重試策略。 有效值為 fixed_delay 或 exponential_backoff。 |
| 最大重試次數 | 必要。 每個函式執行允許的重試次數上限。 -1 表示無限期重試。 |
| 延遲間隔 | 當您使用 fixed_delay 策略時,兩次重試之間所使用的延遲。 將其指定為格式 HH:mm:ss 的字串。 |
| 最小間隔 | 使用 exponential_backoff 策略時的重試延遲下限。 將其指定為格式 HH:mm:ss 的字串。 |
| 最大間隔 | 使用 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());
}
繫結錯誤碼
在與 Azure 服務整合時,錯誤可能會來自基礎服務的 API。 下列文章的<例外狀況和傳回碼>一節提供繫結特定錯誤的相關資訊: