ヒントとアドバイス

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

正確性

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

べき等関数を作成する

関数は、何回呼び出されても結果が同じになることが必要です。これにより、前の呼び出しがコードの途中で失敗した場合は、呼び出しを再試行できます。詳しくは、バックグラウンド関数の再試行についての記事をご覧ください。

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

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

個々の関数で使用されるメモリを確認するには、API Console の関数リストで関数を選択してから、[メモリ使用量] プロットを選択します。

一時ディレクトリ以外への書き込みはしないでください。また、プラットフォームや OS に依存しない方法でファイルパスを構築してください。

一時ファイルのサイズ制限は、パイプラインを使用して回避できます。たとえば、Cloud Storage でファイルを処理するために、読み取りストリームを作成し、これをストリームベースのプロセスに渡してから、出力ストリームを Cloud Storage に直接書き込むことができます。

ツール

このセクションでは、ツールを使用して Cloud Functions を実装、テスト、操作する方法を説明します。

ローカルでの開発

関数のデプロイには時間がかかるため、多くの場合、shim を使用して関数のコードをローカルでテストするほうが時間を短縮できます。

Cloud Functions Node.js エミュレータを shim として使用することをおすすめします。

SendGrid を使ってメールを送信する

Cloud Functions はポート 25 での送信接続を許可しないため、保護されていない接続では SMTP サーバーに接続できません。メールを送信するには、SendGrid を使用することをおすすめします。完全な例は SendGrid のチュートリアルで確認できます。また、メールの送信に関するその他のオプションについては、Google Compute Engine ドキュメントのインスタンスからのメールの送信をご覧ください。

パフォーマンス

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

依存関係を適切に使用する

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

関数によってモジュールがインポートされる場合、それらのモジュールの読み込み時間は、コールド スタート時の呼び出しレイテンシに加算されます。依存関係を正しく読み込み、関数が使用しない依存関係を読み込まないようにすることで、このレイテンシと関数のデプロイに必要な時間を短縮できます。

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

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

この方法では、関数の呼び出しごとに再作成するためコストが高くなりがちなオブジェクトをキャッシュに保存できます。このようなオブジェクトを関数の本文からグローバル スコープに移動して、パフォーマンスを大幅に向上することができます。次の例では、heavy オブジェクトを関数のインスタンスにつき 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 クライアントをグローバル スコープにキャッシュすることが非常に重要です。例については、ネットワークの最適化の記事をご覧ください。

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

グローバル スコープで変数を初期化する場合、初期化コードは常にコールド スタート呼び出しによって実行され、関数のレイテンシが長くなります。一部のコードパスでのみ使用されるオブジェクトについては、必要に応じて遅延させて初期化することを検討してください。

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 つのファイルに定義し、関数ごとに異なる変数を使用する場合に重要です。遅延初期化を使用しないと、初期化されたが使用されない変数にリソースを浪費することがあります。

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

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