Firebase Summit で発表されたすべての情報をご覧ください。Firebase を使用してアプリ開発を加速し、自信を持ってアプリを実行する方法を紹介しています。詳細

ヒントとコツ

コレクションでコンテンツを整理 必要に応じて、コンテンツの保存と分類を行います。

このドキュメントでは、Cloud Functions を設計、実装、テスト、デプロイするためのベスト プラクティスについて説明します。

正しさ

このセクションでは、Cloud Functions を設計および実装するための一般的なベスト プラクティスについて説明します。

冪等関数を書く

関数は、複数回呼び出されても同じ結果を生成する必要があります。これにより、前の呼び出しがコードの途中で失敗した場合に、呼び出しを再試行できます。詳細については、イベント ドリブン関数の再試行を参照してください。

バックグラウンド アクティビティを開始しない

バックグラウンド アクティビティは、関数が終了した後に発生するものです。 Node.js イベント駆動型関数でcallback引数を呼び出すなどして、関数が戻るか、完了を通知すると、関数呼び出しは終了します。正常終了後に実行されるコードは、CPU にアクセスできず、進行しません。

さらに、後続の呼び出しが同じ環境で実行されると、バックグラウンド アクティビティが再開され、新しい呼び出しが妨げられます。これにより、予期しない動作や診断が困難なエラーが発生する可能性があります。関数の終了後にネットワークにアクセスすると、通常、接続がリセットされます ( ECONNRESETエラー コード)。

バックグラウンド アクティビティは、呼び出しが終了したことを示す行の後にログに記録されているものを見つけることで、個々の呼び出しのログで検出できることがよくあります。特にコールバックやタイマーなどの非同期操作が存在する場合は、バックグラウンド アクティビティがコードの奥深くに埋もれていることがあります。関数を終了する前に、コードを見直して、すべての非同期操作が終了していることを確認してください。

一時ファイルを常に削除する

一時ディレクトリ内のローカル ディスク ストレージは、メモリ内ファイル システムです。書き込むファイルは、関数で使用できるメモリを消費し、呼び出し間で持続する場合があります。これらのファイルを明示的に削除しないと、最終的にメモリ不足エラーが発生し、コールド スタートが発生する可能性があります。

GCP Console の関数のリストで関数を選択し、[メモリ使用量] プロットを選択すると、個々の関数で使用されているメモリを確認できます。

一時ディレクトリの外に書き込もうとしないでください。また、必ずプラットフォーム/OS に依存しない方法を使用してファイル パスを作成してください。

パイプライン処理を使用して大きなファイルを処理する場合、メモリ要件を減らすことができます。たとえば、読み取りストリームを作成し、それをストリームベースのプロセスに渡し、出力ストリームを Cloud Storage に直接書き込むことで、Cloud Storage 上のファイルを処理できます。

ツール

このセクションでは、ツールを使用して Cloud Functions を実装、テスト、および操作する方法に関するガイドラインを提供します。

ローカル開発

関数のデプロイには少し時間がかかるため、多くの場合、関数のコードをローカルでテストする方が高速です。

Firebase デベロッパーはFirebase CLI Cloud Functions Emulatorを使用できます。

Sendgrid を使用してメールを送信する

Cloud Functions はポート 25 でのアウトバウンド接続を許可しないため、SMTP サーバーへの非セキュア接続を確立することはできません。電子メールを送信するための推奨される方法は、 SendGridを使用することです。メールを送信するためのその他のオプションについては、Google Compute Engineのインスタンスからメールを送信するのチュートリアルをご覧ください。

パフォーマンス

このセクションでは、パフォーマンスを最適化するためのベスト プラクティスについて説明します。

依存関係を賢く使う

関数はステートレスであるため、実行環境は最初から初期化されることがよくあります (いわゆるコールド スタート中)。コールド スタートが発生すると、関数のグローバル コンテキストが評価されます。

関数がモジュールをインポートする場合、それらのモジュールの読み込み時間が、コールド スタート中の呼び出しの待機時間に追加される可能性があります。依存関係を正しく読み込み、関数が使用しない依存関係を読み込まないようにすることで、この待機時間と関数のデプロイに必要な時間を短縮できます。

グローバル変数を使用して、将来の呼び出しでオブジェクトを再利用します

Cloud Function の状態が将来の呼び出しのために保持されるという保証はありません。ただし、Cloud Functions は多くの場合、以前の呼び出しの実行環境をリサイクルします。グローバル スコープで変数を宣言すると、その値を再計算することなく、後続の呼び出しで再利用できます。

このようにして、各関数呼び出しで再作成するのにコストがかかる可能性があるオブジェクトをキャッシュできます。このようなオブジェクトを関数本体からグローバル スコープに移動すると、パフォーマンスが大幅に向上する場合があります。次の例では、重いオブジェクトを関数インスタンスごとに 1 回だけ作成し、指定されたインスタンスに到達するすべての関数呼び出しでそれを共有します。

console.log('Global scope');
const perInstance = heavyComputation();
const functions = require('firebase-functions');

exports.function = functions.https.onRequest((req, res) => {
    console.log('Function invocation');
    const perFunction = lightweightComputation();

    res.send(`Per instance: ${perInstance}, per function: ${perFunction}`);
});

ネットワーク接続、ライブラリ参照、および API クライアント オブジェクトをグローバル スコープでキャッシュすることは特に重要です。例については、ネットワーキングの最適化を参照してください。

グローバル変数の遅延初期化を行う

グローバル スコープで変数を初期化すると、初期化コードは常にコールド スタート呼び出しを介して実行されるため、関数のレイテンシが増加します。特定のケースでは、 try / catchブロックで適切に処理されない場合、呼び出されているサービスに断続的なタイムアウトが発生します。一部のオブジェクトがすべてのコード パスで使用されていない場合は、必要に応じて遅延して初期化することを検討してください。

const functions = require('firebase-functions');
let myCostlyVariable;

exports.function = functions.https.onRequest((req, res) => {
    doUsualWork();
    if(unlikelyCondition()){
        myCostlyVariable = myCostlyVariable || buildCostlyVariable();
    }
    res.status(200).send('OK');
});

これは、1 つのファイルで複数の関数を定義し、異なる関数が異なる変数を使用する場合に特に重要です。遅延初期化を使用しない限り、初期化されているが使用されていない変数でリソースを浪費する可能性があります。

インスタンスの最小数を設定してコールド スタートを減らす

デフォルトでは、Cloud Functions は受信リクエストの数に基づいてインスタンスの数をスケーリングします。このデフォルトの動作を変更するには、Cloud Functions が要求を処理するために準備しておく必要があるインスタンスの最小数を設定します。インスタンスの最小数を設定すると、アプリケーションのコールド スタートが減少します。アプリケーションが遅延の影響を受けやすい場合は、インスタンスの最小数を設定することをお勧めします。

これらのランタイム オプションの詳細については、スケーリング動作の制御を参照してください。

その他のリソース

パフォーマンスの最適化について詳しくは、「Google Cloud Performance Atlas」のビデオCloud Functions Cold Boot Timeをご覧ください。