非同期関数の再試行

このドキュメントでは、失敗時に非同期(非 HTTPS)バックグラウンド関数をリクエストして再試行する方法について説明します。

再試行のセマンティクス

デフォルトでは、再試行を有効にしない場合、バックグラウンド関数を実行するセマンティクスは「ベスト エフォート」です。つまり関数を 1 回だけ実行することが目的ですが、必ず成功するとは限りません。

ただし、バックグラウンド関数で再試行を有効にすると、セマンティクスは「at-least-once」配信に変更されます(この場合、何日も失敗し続ける関数が最終的にタイムアウトする可能性があります)。

バックグラウンド関数が完了しない理由

まれに、内部エラーのため関数が早期に終了することがあります。関数は、デフォルトで自動的に再試行される場合もあれば、再試行されない場合もあります。

よくあるのは、関数コード内でエラーがスローされるためにバックグラウンド関数が正常に完了できないケースです。これが起こる理由としては、次のようなものがあります。

  • 関数にバグがあるため、ランタイムから例外がスローされる。
  • 関数がサービス エンドポイントに到達できないか、エンドポイントに到達しようとしている間にタイムアウトする。
  • 関数から意図的に例外がスローされる(たとえば、パラメータの検証に失敗した場合)。
  • Node.js に記述されている関数が Promise のリジェクトを返すか、コールバックに null 以外の値を渡す場合。

上記のいずれの場合も、関数はデフォルトで実行を停止し、イベントが破棄されます。エラーが発生したときに関数を再試行する場合は、「失敗時に再試行する」プロパティを設定して、デフォルトの再試行ポリシーを変更できます。これにより、関数が正常に完了するまで数日間イベントが繰り返し再試行されます。

再試行の有効化と無効化

API Console の使用

API Console で再試行を有効または無効にする手順は次のとおりです。

  1. Cloud Platform Console の [Cloud Functions の概要] ページに移動します。

  2. [関数を作成] をクリックします。または、既存の関数をクリックしてその詳細ページに移動し、[編集] をクリックします。

  3. 関数の必須フィールドを入力します。

  4. [トリガー] フィールドがバックグラウンド関数のトリガータイプ(Cloud Pub/Sub や Cloud Storage など)に設定されていることを確認します。

  5. [詳細] をクリックして詳細設定を表示します。

  6. [失敗時に再試行する] というラベルが付いたチェックボックスをオンまたはオフにします。

ベスト プラクティス

ここでは、再試行の使用に関するベスト プラクティスを説明します。

再試行を使用して一時的なエラーを処理する

関数は成功するまで継続的に再試行されるため、バグなどの永続的なエラーを完全に削除してから再試行を有効にしてください。再試行によって解決される可能性が高い断続的なエラーや一時的なエラー(サービス エンドポイントの不安定さやタイムアウトなど)を処理するには、再試行が最適です。

無限再試行ループを避けるための終了条件の設定

再試行を使用する場合は、関数が連続ループに陥らないように保護することをおすすめします。そのためには、明確に定義された終了条件を含めてから関数の処理を開始します。簡単で効果的なアプローチは、特定の時間よりも古いタイムスタンプを持つイベントを破棄することです。これにより、エラーが持続的である場合や継続時間が予想よりも長い場合に、実行時間が過度に長くなるのを回避できます。

たとえば、次のコード スニペットは 10 秒を超えるすべてのイベントを破棄します。

const eventAgeMs = Date.now() - Date.parse(event.timestamp);
const eventMaxAgeMs = 10000;
if (eventAgeMs > eventMaxAgeMs) {
  console.log(`Dropping event ${event} with age[ms]: ${eventAgeMs}`);
  callback();
  return;
}

Promises で catch を使用する

再試行を有効にした場合は、Promises に catch を追加することを検討してください。Cloud Functions は、再試行すべきでない致命的なエラーを認識できないため、致命的なエラーに対応する場合はコードを適宜変更する必要があります。

対処例を次に示します。

return doFooAsync().catch((err) => {
    if (isFatal(err)) {
        console.error(`Fatal error ${err}`);
    }
    return Promise.reject(err);
});

再試行可能なバックグラウンド関数をべき等にする

再試行できるバックグラウンド関数は、べき等にする必要があります。バックグラウンド関数をべき等化するための一般的なガイドラインを次に示します。

  • 多くの外部 API(Stripe など)では、べき等のキーをパラメータとして指定できます。このような API を使用している場合は、イベント ID をべき等のキーとして使用します。
  • べき等では再試行が安全に行われるため、at-least-once 配信でうまく機能します。したがって、信頼性の高いコードを書くための一般的なベスト プラクティスは、べき等と再試行を組み合わせることです。
  • コードが内部でべき等であることを確認します。次に例を示します。
    • 結果が変わらずにミューテーションが 2 回以上起こることを確認する。
    • 状態を変更する前にトランザクション内のデータベース状態を照会する。
    • すべての副作用がそれ自体べき等であることを確認する。
  • コードとは関係なく、トランザクション チェックを関数の外側に置きます。たとえば、指定されたイベント ID がすでに処理されたことを記録しているどこかの状態を保持します。
  • 重複した関数呼び出しにアウトバンドで対応します。たとえば、重複した関数呼び出しの後にクリーンアップする別のクリーンアップ プロセスを用意します。

フィードバックを送信...

ご不明な点がありましたら、Google のサポートページをご覧ください。