関数を管理する


Firebase CLI コマンドを使用するか、関数のソースコードでランタイム オプションを設定することにより、関数をデプロイ、削除、変更できます。

関数をデプロイする

関数をデプロイするには、次の Firebase CLI コマンドを実行します。

firebase deploy --only functions

デフォルトでは、Firebase CLI はソース内のすべての関数を同時にデプロイします。プロジェクトに 6 つ以上の関数が含まれている場合は、特定の関数名で --only フラグを使用して、編集した関数のみをデプロイすることをおすすめします。このようにして特定の関数をデプロイすると、デプロイ プロセスが迅速化され、デプロイの割り当ての問題を回避できます。次に例を示します。

firebase deploy --only functions:addMessage,functions:makeUppercase

多くの関数をデプロイすると、標準の割り当てを超過し、HTTP 429 または 500 エラー メッセージが表示されることがあります。これを解決するには、10 個以下のグループで関数をデプロイします。

使用可能なコマンドの一覧については、Firebase CLI リファレンスをご覧ください。

デフォルトでは、Firebase CLI によって functions/ フォルダ内でソースコードが検索されます。コードベースまたは複数のファイルセット内に関数を編成することもできます。

関数を削除する

過去にデプロイした関数は、次の方法で削除できます。

  • Firebase CLI で functions:delete を使用して明示的に行う。
  • Google Cloud コンソールで明示的に行う。
  • デプロイ前にソースから関数を削除して、暗黙的に行う。

本番環境から関数を削除しようとするたびに、削除操作の確認を求められます。

Firebase CLI で明示的に関数を削除する方法では、複数の引数だけでなく関数のグループもサポートされ、特定のリージョンで実行されている関数を指定できます。また、確認メッセージをオーバーライドすることもできます。

# Delete all functions that match the specified name in all regions.
firebase functions:delete myFunction
# Delete a specified function running in a specific region.
firebase functions:delete myFunction --region us-east-1
# Delete more than one function
firebase functions:delete myFunction myOtherFunction
# Delete a specified functions group.
firebase functions:delete groupA
# Bypass the confirmation prompt.
firebase functions:delete myFunction --force

暗黙的に関数を削除する方法では、firebase deploy によりソースが解析され、ファイルから削除されたすべての関数が本番環境から削除されます。

関数の名前、リージョン、トリガーを変更する

本番トラフィックを処理している関数のリージョンまたはトリガー(またはそれらの名前)を変更する場合は、このセクションの手順に沿って、変更中にイベントが失われないようにしてください。以下の手順を行う前に、まず関数がべき等であることを確認します。これは、関数の新旧両方のバージョンが変更中に同時に実行されるためです。

関数の名前を変更する

関数の名前を変更するには、関数の名前を変更した新しいバージョンをソースに作成してから、2 つの別々のデプロイ コマンドを実行します。最初のコマンドは新しい名前の関数をデプロイし、2 番目のコマンドは以前にデプロイされたバージョンを削除します。たとえば、webhook という Node.js 関数の名前を webhookNew に変更する場合は、次のようにコードを変更します。

// before
const functions = require('firebase-functions');

exports.webhook = functions.https.onRequest((req, res) => {
    res.send("Hello");
});

// after
const functions = require('firebase-functions');

exports.webhookNew = functions.https.onRequest((req, res) => {
    res.send("Hello");
});

続いて、次のコマンドを実行して新しい関数をデプロイします。

# Deploy new function called webhookNew
firebase deploy --only functions:webhookNew

# Wait until deployment is done; now both webhookNew and webhook are running

# Delete webhook
firebase functions:delete webhook

関数のリージョンを変更する

本番環境トラフィックを処理している関数のリージョンを変更する場合は、以下の手順を順番に実施すると、イベントが失われないようにできます。

  1. 関数の名前とリージョンを任意に変更します。
  2. 名前を変更した関数をデプロイします。これにより、一時的に両方のリージョンで同じコードが実行されます。
  3. 前の関数を削除します。

たとえば、現時点でデフォルトの関数リージョン us-central1webhook という関数があり、それを asia-northeast1 に移行する場合は、ソースコードを変更して関数の名前を変更してからリージョンを変更する必要があります。

// before
const functions = require('firebase-functions');

exports.webhook = functions
    .https.onRequest((req, res) => {
            res.send("Hello");
    });

// after
const functions = require('firebase-functions');

exports.webhookAsia = functions
    .region('asia-northeast1')
    .https.onRequest((req, res) => {
            res.send("Hello");
    });

続いて、次のコマンドを実行してデプロイします。

firebase deploy --only functions:webhookAsia

これで 2 つの同じ関数が実行されます。webhookus-central1 で実行され、webhookAsiaasia-northeast1 で実行されます。

次に、webhook を削除します。

firebase functions:delete webhook

これで、関数は asia-northeast1 で実行される webhookAsia だけになります。

関数のトリガータイプを変更する

Cloud Functions for Firebase デプロイの開発の進展に応じて、さまざまな理由により関数のトリガータイプを変更する必要が生じる場合があります。たとえば、あるタイプの Firebase Realtime Database または Cloud Firestore イベントから別のタイプに変更する必要があるとします。

ソースコードを変更して firebase deploy を実行するだけでは、関数のイベントタイプを変更できません。エラーを回避するために、次の手順に従って関数のトリガータイプを変更します。

  1. 目的のトリガータイプを使用する新しい関数が含まれるように、ソースコードを変更します。
  2. 関数をデプロイします。これにより、一時的に新旧両方の関数が実行されます。
  3. Firebase CLI を使用して、本番環境から古い関数を明示的に削除します。

たとえば、従来の onChange イベントタイプを使用する objectChanged という名前の Node.js 関数があり、それを onFinalize に変更する場合は、まず関数の名前を変更して、onFinalize イベントタイプを使用するように編集します。

// before
const functions = require('firebase-functions');

exports.objectChanged = functions.storage.object().onChange((object) => {
    return console.log('File name is: ', object.name);
});

// after
const functions = require('firebase-functions');

exports.objectFinalized = functions.storage.object().onFinalize((object) => {
    return console.log('File name is: ', object.name);
});

続いて、古い関数を削除する前に、先に次のコマンドを実行して新しい関数を作成します。

# Create new function objectFinalized
firebase deploy --only functions:objectFinalized

# Wait until deployment is done; now both objectChanged and objectFinalized are running

# Delete objectChanged
firebase functions:delete objectChanged

ランタイム オプションを設定する

Cloud Functions for Firebase ではランタイム オプションを選択できます。設定できるランタイム オプションには、Node.js ランタイムのバージョン、関数ごとのタイムアウト、メモリ割り当て、関数インスタンスの最小数と最大数などがあります。

これらのオプション(Node.js バージョンを除く)は、関数コード内の構成オブジェクトに設定することをおすすめします。この RuntimeOptions オブジェクトは関数のランタイム オプションの信頼できる情報源であり、他の方法(Google Cloud Console や gcloud CLI など)で設定されたオプションをオーバーライドします。

Google Cloud コンソールや gcloud CLI を使用して手動で設定するランタイム オプションが開発ワークフローに含まれていて、これらの値を各デプロイでオーバーライドしたくない場合は、preserveExternalChanges オプションを true に設定します。このオプションを true に設定すると、Firebase はコードに設定されているランタイム オプションと、現在デプロイされているバージョンの関数の設定を、次の優先順位で結合します。

  1. オプションが関数コードで設定されている場合、外部の変更をオーバーライドします。
  2. オプションが関数コードで RESET_VALUE に設定されている場合、外部の変更をデフォルト値でオーバーライドします。
  3. オプションは関数コードで設定されていないが、現在デプロイされている関数で設定されている場合、デプロイされている関数に指定されたオプションを使用します。

ほとんどのシナリオでは、preserveExternalChanges: true オプションの使用はおすすめしません。関数のランタイム オプションに関して、コードが信頼できる完全な情報源でなくなるためです。このオプションを使用する場合は、Google Cloud コンソールを確認するか、gcloud CLI を使用して関数の完全な構成を表示します。

Node.js のバージョンを設定する

Firebase SDK for Cloud Functions では、Node.js ランタイムを選択できます。プロジェクト内のすべての関数を、サポートされている以下のいずれかの Node.js バージョンに対応するランタイム環境のみで実行するように選択できます。

  • Node.js 20(プレビュー版)
  • Node.js 18
  • Node.js 16
  • Node.js 14

Node.js のバージョンを設定するには:

初期化時に functions/ ディレクトリに作成された package.json ファイルの engines フィールドにバージョンを設定できます。たとえば、バージョン 18 のみを使用するには、package.json の次の行を編集します。

  "engines": {"node": "18"}

Yarn パッケージ マネージャーを使用している場合、または engines フィールドに他の特定の要件がある場合は、代わりに firebase.json で Firebase SDK for Cloud Functions のランタイムを設定できます。

  {
    "functions": {
      "runtime": "nodejs18" // or nodejs14, nodejs16 or nodejs20
    }
  }

CLI では、firebase.json で設定された値が、package.json で個別に設定された値または範囲よりも優先して使用されます。

Node.js ランタイムをアップグレードする

Node.js ランタイムをアップグレードするには:

  1. プロジェクトで Blaze 料金プランを利用していることを確認します。
  2. Firebase CLI バージョン 11.18.0 以降を使用していることを確認します。
  3. 初期化時に functions/ ディレクトリに作成された package.json ファイルの engines の値を変更します。たとえば、バージョン 16 からバージョン 18 にアップグレードする場合、エントリは次のようになります。"engines": {"node": "18"}
  4. 必要に応じて、Firebase Local Emulator Suite を使用して変更をテストします。
  5. すべての関数を再デプロイします。

Python のバージョンを設定する

Firebase SDK for Cloud Functions バージョン 12.0.0 以降では、Python ランタイム(公開プレビュー機能)を選択できます。次のように firebase.json でランタイム バージョンを設定します。

  {
    "functions": {
      "runtime": "python310" // or python311
    }
  }

スケーリング動作を制御する

デフォルトでは、Cloud Functions for Firebase は受信リクエストの数に基づいて実行インスタンスの数をスケーリングします。トラフィックが減少すると、インスタンス数がゼロまでスケールダウンされる可能性があります。ただし、アプリでレイテンシを短縮する必要があり、コールド スタートの数を制限する場合は、ウォーム状態を維持し、いつでもリクエストを処理できるコンテナ インスタンスの最小数を指定して、このデフォルトの動作を変更できます。

同様に、受信リクエストに応じてスケーリングされるインスタンス数に最大数を設定して制限を設けることができます。この設定を使用して、コストの制御や、データベースなどのバッキング サービスへの接続数を制限できます。

これらの設定とインスタンスごとの同時実行(第 2 世代の新機能)を併用すると、関数のスケーリング動作を制御し、調整できます。最も費用対効果が高く、最適なパフォーマンスが得られる設定は、アプリケーションと機能の性質によって決まります。

トラフィックが少ないアプリの場合、マルチ同時実行を使用しない CPU オプションが最適です。また、コールド スタートが重要な問題である場合でも、同時実行数と最小インスタンス数を設定することで、インスタンスが常にウォーム状態を維持し、トラフィックの急増に対処できます。

トラフィックがほとんど発生しない小規模なアプリの場合は、最大インスタンス数を低く設定し、同時実行数を多くすることで、過剰な費用を発生させることなく、トラフィックのバーストを処理できます。ただし、最大インスタンス数の設定が低すぎると、上限に達してリクエストがドロップされる可能性があります。

同時リクエストを許可する

Cloud Functions for Firebase(第 1 世代)では、各インスタンスが一度に 1 つのリクエストを処理するため、スケーリング動作は最小インスタンス数と最大インスタンス数でのみ設定されていました。Cloud Functions for Firebase(第 2 世代)では、インスタンス数を管理するだけでなく、concurrency オプションを使用して、インスタンスが同時に処理できるリクエスト数を制御できます。同時実行のデフォルト値は 80 ですが、1~1,000 の任意の整数に設定できます。

同時実行の設定が高い関数は、各インスタンスに少し余裕があるため、コールド スタートを実行しなくてもトラフィックの急増に対応できます。1 つのインスタンスで最大 50 件の同時リクエストを処理できるように構成しているときに、25 件のリクエストしか処理していない場合、あと 25 件までは、追加のリクエストが急に発生しても、新しいインスタンスをコールド スタートすることなく対応できます。一方、同時実行数を 1 に設定している場合、リクエストの急増により 25 回のコールド スタートが発生する可能性があります。

この簡素化されたシナリオの場合、同時実行によって効率が向上する可能性があります。実際には、スケーリング動作で効率を最適化し、同時実行でコールド スタートを減らすのは複雑です。Cloud Functions for Firebase 第 2 世代の同時実行は Cloud Run を利用しているため、Cloud Run のコンテナ インスタンスの自動スケーリングのルールに従います。

Cloud Functions for Firebase(第 2 世代)で同時実行数の設定を増やす場合は、次の点に注意してください。

  • 同時実行の設定を高く設定した場合、最適なパフォーマンスを得るために、実用的な上限に達するまで CPU と RAM の増量が必要になることがあります。たとえば、負荷の高い画像処理や動画処理を行う関数を実行する場合は、CPU と RAM を最大に設定しても、同時に 1,000 件のリクエストを処理するためのリソースを確保できないことがあります。
  • Cloud Functions for Firebase(第 2 世代)は Cloud Run を利用しているため、同時実行の最適化に関する Google Cloud のガイダンスもご覧ください。
  • 本番環境をマルチ同時実行に切り替える前に、テスト環境で必ずマルチ同時実行をテストしてください。

最小数のインスタンスを常にウォーム状態にする

関数の最小インスタンス数はソースコードで設定できます。たとえば、次の関数ではウォーム状態を維持する最小インスタンス数を 5 に設定しています。

Node.js

const { onCall } = require("firebase-functions/v2/https");

exports.getAutocompleteResponse = onCall(
  {
    // Keep 5 instances warm for this latency-critical function
    minInstances: 5,
  },
  (event) => {
    // Autocomplete user’s search term
  }
);

Python(プレビュー)

@https_fn.on_call(min_instances=5)
def get_autocomplete_response(event: https_fn.CallableRequest) -> https_fn.Response:

インスタンスの最小数を設定する際は、次の点を考慮してください。

  • Cloud Functions for Firebase が設定を超えてアプリをスケーリングした場合、このしきい値を上回る各インスタンスにコールド スタートが発生することになります。
  • コールド スタートは、トラフィックの急増があるアプリに特に大きな影響を及ぼします。アプリのトラフィックが急増する場合、大きな値を設定すると、トラフィックが増加するたびにコールド スタートが発生するのを減らすことができ、レイテンシが大幅に短縮されます。トラフィックが一定しているアプリの場合、コールド スタートがパフォーマンスに大きな影響を与えることはほとんどありません。
  • 最小インスタンス数の設定は本番環境では意味がありますが、通常、テスト環境では避ける必要があります。テスト プロジェクトではゼロにスケーリングし、本番環境プロジェクトではコールド スタートを減らすようにするには、パラメータ化された構成に最小インスタンス値を設定します。

    Node.js

    const functions = require('firebase-functions');
    const { defineInt, defineString } = require('firebase-functions/params');
    
    // Define some parameters
    const minInstancesConfig = defineInt('HELLO_WORLD_MININSTANCES');
    const welcomeMessage = defineString('WELCOME_MESSAGE');
    
    // To use configured parameters inside the config for a function, provide them 
    // directly. To use them at runtime, call .value() on them.
    export const helloWorld = functions.runWith({ minInstances: minInstancesConfig}).https.onRequest(
      (req, res) => {
        res.send(`${welcomeMessage.value()}! I am a function.`);
      }
    );
    

    Python(プレビュー)

    MIN_INSTANCES = params.IntParam("HELLO_WORLD_MININSTANCES")
    WELCOME_MESSAGE = params.StringParam("WELCOME_MESSAGE")
    
    @https_fn.on_request(min_instances=MIN_INSTANCES.value())
    def get_autocomplete_response(event: https_fn.Request) -> https_fn.Response:
        return https_fn.Response(f"{WELCOME_MESSAGE.value()} I'm a function.")
    

関数の最大インスタンス数を制限する

関数のソースコードで最大インスタンス数を設定できます。たとえば、次の関数では、仮想上のレガシー データベースの過負荷を防ぐためにインスタンス数の上限を 100 に設定しています。

Node.js

const { onMessagePublished } = require("firebase-functions/v2/pubsub");

exports.mirrorevents = onMessagePublished(
  { topic: "topic-name", maxInstances: 100 },
  (event) => {
    // Connect to legacy database
  }
);

Python(プレビュー)

@pubsub_fn.on_message_published(topic="topic-name", max_instances=100)
def mirrorevents(event: pubsub_fn.CloudEvent):
#  Connect to legacy database

HTTP 関数が最大インスタンス数までスケールアップされると、新しいリクエストは 30 秒間キューに入れられ、その間にいずれのインスタンスも使用可能にならない場合は、レスポンス コード 429 Too Many Requests で拒否されます。

最大インスタンス数の設定に関するベスト プラクティスについては、最大インスタンス数を設定使用する際のベスト プラクティスをご覧ください。

タイムアウトとメモリ割り当てを設定する

場合によっては、長いタイムアウト値や大容量のメモリ割り当てに関して、関数に特別な要件が存在することがあります。これらの値は、Google Cloud コンソールまたは関数のソースコード(Firebase のみ)で設定できます。

関数のソースコードでメモリ割り当てとタイムアウトを設定するには、メモリとタイムアウト(秒単位)のグローバル オプションを使用して、関数を実行する仮想マシンをカスタマイズします。たとえば、次の Cloud Storage 関数は 1 GiB のメモリを使用し、300 秒経過するとタイムアウトします。

Node.js

exports.convertLargeFile = onObjectFinalized({
  timeoutSeconds: 300,
  memory: "1GiB",
}, (event) => {
  // Do some complicated things that take a lot of memory and time
});

Python(プレビュー)

@storage_fn.on_object_finalized(timeout_sec=300, memory=options.MemoryOption.GB_1)
def convert_large_file(event: storage_fn.CloudEvent):
# Do some complicated things that take a lot of memory and time.

タイムアウトの最大値は 540 秒または 9 分です。

Google Cloud コンソールでメモリ割り当てとタイムアウトを設定するには:

  1. Google Cloud コンソールで、左側のメニューから [Cloud Functions for Firebase] を選択します。
  2. 関数のリストで関数名をクリックして、関数を選択します。
  3. トップメニューの [編集] アイコンをクリックします。
  4. [割り当てられるメモリ] というプルダウン メニューから、メモリ割り当てを選択します。
  5. [詳細] をクリックして詳細オプションを表示し、[タイムアウト] テキスト ボックスに秒数を入力します。
  6. [保存] をクリックして関数を更新します。

CPU のデフォルトをオーバーライドする

メモリの割り当てが 2 GB 以下の場合、Cloud Functions for Firebase(第 2 世代)の各関数の CPU 数はデフォルトで 1 になります。4 GB と 8 GB の場合は 2 CPU になります。次の表に示すように、これは、第 1 世代のデフォルトの動作とは大きく異なるため、低メモリ関数の費用が若干高くなる可能性があります。

RAM 割り当て バージョン 1 のデフォルト CPU(小数) バージョン 2 のデフォルト CPU ミリ秒あたりの料金の違い
128 MB 1/12 1 10.5 倍
256 MB 1/6 1 5.3 倍
512 MB 1/3 1 2.7 倍
1 GB 7/12 1 1.6 倍
2 GB 1 1 1 倍
4 GB 2 2 1 倍
8 GB 2 2 1 倍
16 GB なし 4 なし

第 2 世代の関数で第 1 世代の動作を保持する場合は、第 1 世代のデフォルトをグローバル オプションとして設定します。

Node.js

// Turn off Firebase defaults
setGlobalOptions({ cpu: 'gcf_gen1' });

Python(プレビュー)

# Use 1st gen behavior
set_global_options(cpu="gcf_gen1")

第 2 世代では、大量の CPU を使用する関数の場合、追加の CPU を柔軟に構成できます。次に示すように、関数ごとに CPU を増やすことができます。

Node.js

// Boost CPU in a function:
export const analyzeImage = onObjectFinalized({ cpu: 2 }, (event) => {
  // computer vision goes here
});

Python(プレビュー)

# Boost CPU in a function:
@storage_fn.on_object_finalized(cpu=2)
def analyze_image(event: storage_fn.CloudEvent):
# computer vision goes here