管理函数(第 1 代)

您可以使用 Firebase CLI 命令或在函数源代码中设置运行时选项来部署、删除和修改函数。

部署函数

如需部署函数,请运行以下 Firebase CLI 命令:

firebase deploy --only functions

默认情况下,Firebase CLI 会同时部署源代码中的所有函数。如果您的项目包含 5 个以上的函数,建议您使用 --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 会解析源代码并从生产环境中移除已从文件中移除的任何函数。

修改函数的名称、区域或触发器

如需更改正在处理生产流量的函数的名称、区域或触发器,请按本部分中的步骤操作,以免在修改期间丢失事件。在执行这些步骤之前,请先确保您的函数为幂等函数,因为在更改期间,函数的新版本和旧版本均会处于运行状态。

重命名函数

如需重命名函数,请在源代码中创建函数改名后的新版本,然后分别运行两条部署命令。第一条命令部署改名后的函数,而第二条命令则移除以前部署的版本。例如,如果您要将名为 webhook 的 Node.js 函数更名为 webhookNew,请按以下方式修改代码:

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

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

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

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. 删除先前的函数。

例如,如果您有一个名为 webhook 的函数当前位于 us-central1 的默认函数区域,您希望将其迁移到 asia-northeast1,则需要先修改源代码,重命名该函数并修改区域。

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

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

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

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

然后运行以下命令部署函数:

firebase deploy --only functions:webhookAsia

现在有两个相同的函数在运行:webhookus-central1 中运行,webhookAsiaasia-northeast1 中运行。

然后,删除 webhook

firebase functions:delete webhook

现在只存在一个函数 - webhookAsia,它在 asia-northeast1 中运行。

更改函数的触发器类型

当您的 Cloud Functions for Firebase 部署工作开展一段时间后,您可能会出于各种原因而需要更改函数的触发器类型。例如,您可能希望将触发器类型从 Firebase Realtime DatabaseCloud Firestore 的一种事件类型更改为另一种事件类型。

仅凭更改源代码和运行 firebase deploy 无法更改函数的事件类型。为避免错误,请按以下流程更改函数的触发器类型:

  1. 修改源代码,加入具备所需触发器类型的新函数。
  2. 部署该函数,这样暂时会同时运行新旧两个函数。
  3. 使用 Firebase CLI 从生产环境中明确删除旧函数。

例如,如果您有一个名为 objectChanged 的 Node.js 函数具有旧版 onChange 事件类型,而您希望将其更改为 onFinalize,请先重命名该函数,再将其事件类型修改为 onFinalize

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

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

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

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 控制台或 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 版本的持续支持的重要信息。

如需设置 Node.js 版本,请执行以下操作:

您可以在初始化期间于 functions/ 目录下创建的 package.json 文件的 engines 字段中设置版本。例如,如仅需使用版本 20,请在 package.json 中修改下面一行内容:

  "engines": {"node": "20"}

如果您使用的是 Yarn 软件包管理系统,或者对 engines 字段有其他特定要求,则可以改为在 firebase.json 中为 Firebase SDK for Cloud Functions 设置运行时:

  {
    "functions": {
      "runtime": "nodejs20"
    }
  }

CLI 会优先使用 firebase.json 中设置的值,而不是您在 package.json 中单独设置的任何值或范围。

升级 Node.js 运行时

如需升级 Node.js 运行时,请执行以下操作:

  1. 确保您的项目采用的是 Blaze 定价方案
  2. 确保您使用的是 Firebase CLI v11.18.0 或更高版本。
  3. 更改在初始化期间于 functions/ 目录下创建的 package.json 文件中的 engines 值。例如,如果您要从版本 16 升级到版本 18,请按如下方式设置该字段:"engines": {"node": "18"}
  4. (可选)使用 Firebase Local Emulator Suite 测试您的更改。
  5. 重新部署所有函数。

选择 Node.js 模块系统

Node.js 中的默认模块系统是 CommonJS (CJS),但当前 Node.js 版本也支持 ECMAScript 模块 (ESM)。Cloud Functions 支持这两种模块。

默认情况下,您的函数使用 CommonJS。这意味着导入和导出如下所示:

const functions = require("firebase-functions/v1");

exports.helloWorld = functions.https.onRequest(async (req, res) => res.send("Hello from Firebase!"));

如需改为使用 ESM,请在 package.json 文件中设置 "type": "module" 字段:

  {
   ...
   "type": "module",
   ...
  }

设置此项后,请使用 ESM importexport 语法:

import functions from "firebase-functions/v1";

export const helloWorld = functions.https.onRequest(async (req, res) => res.send("Hello from Firebase!"));

这两个模块系统均完全受支持。您可以选择最适合您项目的系统。 如需了解详情,请参阅有关模块的 Node.js 文档

控制伸缩行为

默认情况下,Cloud Functions for Firebase 会根据传入请求数量调整运行的实例数量,当流量减少时可能会将实例数缩减为零。但是,如果您的应用要求更低的延迟时间,并且您希望限制冷启动次数,您可以指定保持备用状态并已准备好处理请求的容器实例数下限,来更改此默认行为。

同样,您也可以设置数量上限,限制为应对传入请求而扩增的实例数。使用此设置可以控制您的费用或限制与支持性服务(如数据库)的连接数。

减少冷启动次数

如需在源代码中为函数设置实例数下限,请使用 runWith 方法。此方法接受符合 RuntimeOptions 接口的 JSON 对象(定义 minInstances 的值)。例如,此函数将保持备用状态的实例数下限设置为 5:

exports.getAutocompleteResponse = functions
    .runWith({
      // Keep 5 instances warm for this latency-critical function
      minInstances: 5,
    })
    .https.onCall((data, context) => {
      // Autocomplete a user's search term
    });

minInstances 设置值时,您需要考虑以下事项:

  • 如果 Cloud Functions for Firebase 将您的应用扩容到超过 minInstances 设置范围,超出该阈值以后的每个实例都会进行冷启动。
  • 冷启动对于有流量激增现象的应用会产生最为严重的影响。如果您的应用流量会激增,并且您将 minInstances 值设置得足够高,可以在每次流量增加时减少冷启动次数,延迟时间将明显缩短。对于流量稳定的应用,冷启动不太可能严重影响性能。
  • 设置实例数下限可能适合生产环境,但在测试环境中通常应避免。如需在测试项目中缩减至零,但仍在生产项目中减少冷启动,您可以根据 FIREBASE_CONFIG 环境变量设置 minInstances

    // Get Firebase project id from `FIREBASE_CONFIG` environment variable
    const envProjectId = JSON.parse(process.env.FIREBASE_CONFIG).projectId;
    
    exports.renderProfilePage = functions
        .runWith({
          // Keep 5 instances warm for this latency-critical function
          // in production only. Default to 0 for test projects.
          minInstances: envProjectId === "my-production-project" ? 5 : 0,
        })
        .https.onRequest((req, res) => {
          // render some html
        });
    

限制函数的实例数上限

如需在函数源代码中设置实例数上限,请使用 runWith 方法。此方法接受符合 RuntimeOptions 接口的 JSON 对象(定义 maxInstances 的值)。例如,以下函数将实例数上限设置为 100,以避免假设的旧数据库超负荷:

exports.mirrorOrdersToLegacyDatabase = functions
    .runWith({
      // Legacy database only supports 100 simultaneous connections
      maxInstances: 100,
    })
    .firestore.document("orders/{orderId}")
    .onWrite((change, context) => {
      // Connect to legacy database
    });

如果 HTTP 函数扩容到 maxInstances 上限,则新请求将在队列中等候 30 秒;如果这段时间内仍没有可用的实例,则系统将拒绝这些请求并返回响应代码 429 Too Many Requests

如需详细了解使用实例数上限设置的最佳做法,请查看这些使用 maxInstances 的最佳做法

设置服务账号

第 1 代函数的默认服务账号 PROJECT_ID@appspot.gserviceaccount.com(名为 App Engine 默认服务账号)具有广泛的权限,可让您与其他 Firebase 和 Google Cloud 服务互动。

您可能需要覆盖默认服务账号,并将函数限制为仅使用所需的资源。为此,您可以创建一个自定义服务账号,并使用 .runWith() 方法将其分配给相应的函数。此方法接受一个包含配置选项(包括 serviceAccount 属性)的对象。

const functions = require("firebase-functions/v1");

exports.helloWorld = functions
    .runWith({
        // This function doesn't access other Firebase project resources, so it uses a limited service account.
        serviceAccount:
            "my-limited-access-sa@", // or prefer the full form: "my-limited-access-sa@my-project.iam.gserviceaccount.com"
    })
    .https.onRequest((request, response) => {
        response.send("Hello from Firebase!");
    });

设置超时时间和内存分配

在某些情况下,您的函数可能有特殊要求,需要具备较长的超时值或分配较多的内存。您可以在 Google Cloud 控制台或函数源代码(仅限 Firebase)中设置这些值。

如需在函数源代码中设置内存分配和超时,请使用 Firebase SDK for Cloud Functions 2.0.0 中引入的 runWith 参数。此运行时选项接受符合 RuntimeOptions 接口的 JSON 对象(定义 timeoutSecondsmemory 的值)。例如,以下存储函数使用 1GB 的内存,并会在 300 秒后超时:

exports.convertLargeFile = functions
    .runWith({
      // Ensure the function has enough memory and time
      // to process large files
      timeoutSeconds: 300,
      memory: "1GB",
    })
    .storage.object()
    .onFinalize((object) => {
      // Do some complicated things that take a lot of memory and time
    });

timeoutSeconds 的最大值为 540 或 9 分钟。 授予函数的内存量与为该函数分配的 CPU相对应,详见下列 memory 的有效值列表:

  • 128MB - 200MHz
  • 256MB - 400MHz
  • 512MB - 800MHz
  • 1GB - 1.4 GHz
  • 2GB - 2.4 GHz
  • 4GB - 4.8 GHz
  • 8GB - 4.8 GHz

如需在 Google Cloud 控制台中设置内存分配和超时,请执行以下操作:

  1. 在 Google Google Cloud 控制台中,从左侧菜单中选择 Cloud Functions
  2. 点击函数列表中的名称,选择相应函数。
  3. 点击顶部菜单中的修改图标。
  4. 从名为分配的内存的下拉菜单中选择内存分配。
  5. 点击更多以显示高级选项,并在超时文本框中输入秒数。
  6. 点击保存以更新函数。