ヒントとアドバイス

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

正確性

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

べき等関数を作成する

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

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

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

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

一時ディレクトリ以外への書き込みはしないでください。また、os.tmpdir()path.join() などのプラットフォームに依存しないメソッドを使用して一時的なファイルパスを構築し、関数がどのプラットフォームのエミュレータでも機能するようにします。

一時ファイルの作成に関する問題は、パイプラインを使用して回避できます。たとえば、Cloud Storage でファイルを処理するには、読み取りストリームを作成し、それを sharp のスケーリング パイプに渡してから、書き込みストリームを使用して Cloud Storage に直接書き戻します。詳細については、Node.js ストリームと sharp を使用したイメージのサイズ変更を参照してください。

ツール

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

既存のツールを使用する

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

最後に、独自のモジュールを作成するのではなく、既存の一般的なモジュールを使用してみてください。

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

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

パフォーマンス

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

依存関係を最小化する

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

関数によって従属パッケージが require() で指定されている場合、パッケージの読み込み時間が加わることでコールド スタート時の呼び出しレイテンシが長くなります。このレイテンシと関数のデプロイ時間は、関数によって読み込まれる依存関係の数を最小限に抑えることで低減することができます。

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

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 のサポートページをご覧ください。