Azure Functions のエラー処理と再試行

Azure Functions でのエラーの処理は、データの損失やイベントの漏れを防ぎ、アプリケーションの正常性を監視するために重要です。 また、イベント ベースのトリガーの再試行動作を理解するための重要な方法でもあります。

この記事では、エラー処理の一般的な戦略と、使用可能な再試行方法について説明します。

重要

特定のトリガーに対するプレビュー再試行ポリシーのサポートは、2022 年 12 月に削除されました。 サポートされているトリガーの再試行ポリシーが一般公開 (GA) になりました。 再試行ポリシーを現在サポートしている拡張機能の一覧については、「再試行」セクションを参照してください。

エラーを処理する

Azure 関数で発生するエラーは、次のいずれかによるものである可能性があります。

  • Functions の組み込みのトリガーとバインドの使用
  • 基になっている Azure サービスの API の呼び出し
  • REST エンドポイントの呼び出し
  • クライアント ライブラリ、パッケージ、またはサードパーティ API の呼び出し

データやメッセージが失われないようにするには、適切なエラー処理を行うことが重要です。 この表では、推奨されるエラー処理方法について説明し、詳細情報へのリンクを示します。

推奨事項 詳細
[Application Insights を有効にする] Azure Functions は、Application Insights と統合して、エラー データ、パフォーマンス データ、ランタイム ログを収集します。 Application Insights を使用して、関数の実行で発生するエラーを検出し、よりよく理解する必要があります。 詳細については、「Azure Functions を監視する」を参照してください。
構造化エラー処理を使用する アプリケーションの正常性を監視するには、エラーをキャプチャしてログすることが重要です。 関数コードの最上位レベルに、try/catch ブロックを含める必要があります。 catch ブロックでは、エラーをキャプチャしてログできます。 バインドによって発生する可能性があるエラーの詳細については、バインド エラー コードに関する記事を参照してください。 特定の再試行戦略によっては、関数を再度実行するために新しい例外を発生させることもできます。
再試行戦略を計画する いくつかの Functions バインド拡張機能では、再試行の組み込みサポートが提供され、その他の拡張機能では、Functions ランタイムによって実装される再試行ポリシーを定義できます。 再試行動作が提供されないトリガーの場合は、独自の再試行スキームの実装を検討する必要があります。 詳細については、「報酬」に関する記事を参照してください。
べき等に設計する データの処理時にエラーが発生すると、関数にとって問題になる可能性があります (特にメッセージを処理しているとき)。 エラーが発生したときに起きることと、重複する処理を回避する方法を検討することが重要です。 詳細については、「同一入力のための Azure Functions の設計」を参照してください。

再試行

関数では、2 種類の再試行を使用できます。

  • 個々のトリガー拡張機能の組み込みの再試行動作
  • Functions ランタイムによって提供される再試行ポリシー

次の表は、再試行をサポートするトリガーと、再試行動作が構成されている場所を示しています。 また、基になるサービスからのエラーに関する詳細情報にもリンクされています。

トリガー/バインド 再試行ソース 構成
Azure Cosmos DB 再試行ポリシー 関数レベル
Blob Storage バインド拡張機能 host.json
Event Grid バインド拡張機能 イベント サブスクリプション
Event Hubs 再試行ポリシー 関数レベル
Kafka 再試行ポリシー 関数レベル
Queue Storage バインド拡張機能 host.json
RabbitMQ バインド拡張機能 配信不能キュー
Service Bus バインド拡張機能 host.json*
Timer 再試行ポリシー 関数レベル

*Azure Service Bus 拡張機能のバージョン 5.x が必要です。 以前の拡張機能バージョンでは、再試行動作は Service Bus の配信不能キューによって実装されます。

再試行ポリシー

Azure Functions では特定のトリガーの種類の再試行ポリシーを定義でき、それらはランタイムによって適用されます。 現時点で再試行ポリシーがサポートされているトリガーの種類は、次のとおりです。

再試行のサポートは、v1 と v2 の両方の Python プログラミング モデルで同じです。

再試行ポリシーは、Functions ランタイムのバージョン 1.x ではサポートされていません。

再試行ポリシーは、正常に完了するか、または再試行の最大数に達するまで、失敗した実行を再実行するようにランタイムに指示します。

再試行ポリシーは、サポートされているトリガーの種類によって実行された関数で、キャッチされない例外が発生したときに評価されます。 ベスト プラクティスとして、コード内のすべての例外をキャッチし、再試行を必要とするエラーに対して新しい例外を発生させる必要があります。

重要

実行の再試行ポリシーが完了するまで、Event Hubs チェックポイントは書き込まれません。 この動作により、特定のパーティションの進行は、現在のバッチの処理が完了するまで一時停止されます。

Event Hubs 拡張機能のバージョン 5.x では、Functions ホストとイベント ハブの間の対話のために追加の再試行機能がサポートされます。 詳細については、Event Hubs host.json のリファレンスにある clientRetryOptions を参照してください。

再試行戦略

ポリシーでサポートされている 2 つの再試行戦略を構成できます。

各再試行の間に指定された時間を経過させることができます。

従量課金プランで実行する場合、関数のコードが実行されている時間に対してのみ課金されます。 どちらの再試行戦略でも、実行間の待機時間は課金されません。

最大再試行回数

関数の実行が最終的に失敗するまでに再試行される最大回数を構成できます。 現在の再試行回数は、インスタンスのメモリに格納されます。

再試行と再試行の間に、インスタンスでエラーが発生する可能性があります。 再試行ポリシーの実行中にインスタンスでエラーが発生した場合、再試行回数は失われます。 インスタンスでエラーが発生すると、Event Hubs トリガーは処理を再開し、新しいインスタンスでバッチを再試行できます。再試行回数はゼロにリセットされます。 Timer トリガーは、新しいインスタンスで再開されません。

この動作は、最大再試行回数がベスト エフォートであることを意味します。 まれに、要求されている最大回数より多く、実行が再試行されることがあります。 Timer トリガーの場合、再試行が要求されている最大回数より少ないことがあります。

再試行の例

固定遅延とエクスポネンシャル バックオフの両方の戦略の例を示します。 特定の戦略の例を表示するには、まず前のタブでその戦略を選択する必要があります。

関数レベルの再試行は、次の NuGet パッケージでサポートされています。

[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 のバージョンによって異なります。

固定遅延の再試行戦略を使用する Timer トリガー関数の例を次に示します。

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 のバージョンによって異なります。

固定遅延の再試行戦略を使用する Timer トリガー関数の例を次に示します。

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 という形式の文字列として指定します。

固定遅延の再試行戦略を使用する Timer トリガー関数の例を次に示します。

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());
}

エラー コードのバインド

Azure サービスと統合しているとき、基になるサービスの API からエラーが発生する場合があります。 バインド固有のエラーに関する情報については、以下の記事の例外とリターン コードに関するセクションをご覧ください。

次のステップ