管理函数


您可以使用 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 会解析源代码并从生产环境中移除已从文件中移除的任何函数。

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

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

重命名函数

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

Node.js

// before
const {onRequest}  = require('firebase-functions/v2/https');

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

// after
const {onRequest}  = require('firebase-functions/v2/https');

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

Python

# before
from firebase_functions import https_fn

@https_fn.on_request()
def webhook(req: https_fn.Request) -> https_fn.Response:
    return https_fn.Response("Hello world!")

# after
from firebase_functions import https_fn

@https_fn.on_request()
def webhook_new(req: https_fn.Request) -> https_fn.Response:
    return https_fn.Response("Hello world!")

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

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

# Wait until deployment is done; now both functions are running

# Delete webhook
firebase functions:delete webhook

更改函数的一个或多个区域

如需更改正在处理生产流量的函数的指定区域,您可以按顺序执行以下步骤,以防止丢失事件:

  1. 重命名该函数,并根据需要更改其一个或多个区域。
  2. 部署重命名的函数,这样就会暂时在两组区域中运行相同的代码。
  3. 删除先前的函数。

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

Node.js

// before
exports.firestoreTrigger = onDocumentCreated(
  "my-collection/{docId}",
  (event) => {},
);

// after
exports.firestoreTriggerAsia = onDocumentCreated(
  {
    document: "my-collection/{docId}",
    region: "asia-northeast1",
  },
  (event) => {},
);

更新后的代码应指定正确的事件过滤器(在本例中为 document)以及区域。如需了解详情,请参阅 Cloud Functions 位置

Python

# Before
@firestore_fn.on_document_created("my-collection/{docId}")
def firestore_trigger(event):
    pass

# After
@firestore_fn.on_document_created("my-collection/{docId}",
                                  region="asia-northeast1")
def firestore_trigger_asia(event):
    pass

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

firebase deploy --only functions:firestoreTriggerAsia

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

然后,删除 firestoreTrigger

firebase functions:delete firestoreTrigger

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

更改函数的触发器类型

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

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

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

例如,如果您有一个在对象遭到删除时触发的函数,但随后您启用了对象版本控制,并希望改为订阅归档事件,请先重命名该函数,再将其触发器类型修改为新类型。

Node.js

// before
const {onObjectDeleted} = require("firebase-functions/v2/storage");

exports.objectDeleted = onObjectDeleted((event) => {
    // ...
});

// after
const {onObjectArchived} = require("firebase-functions/v2/storage");

exports.objectArchived = onObjectArchived((event) => {
    // ...
});

Python

# before
from firebase_functions import storage_fn

@storage_fn.on_object_deleted()
def object_deleted(event):
  # ...

# after 
from firebase_functions import storage_fn

@storage_fn.on_object_archived()
def object_archived(event):
  # ...

然后运行以下命令,以便先创建新函数,然后再删除旧函数:

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

# Wait until deployment is done; now both objectDeleted and objectArchived are running

# Delete objectDeleted
firebase functions:delete objectDeleted

设置运行时选项

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 22(预览版)
  • Node.js 20
  • Node.js 18

Node.js 版本 14 和 16 已弃用,并将于 2025 年初停用。已禁止使用这些已弃用版本进行部署。

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

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

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

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

  {
    "functions": {
      "runtime": "nodejs18" // or nodejs20
    }
  }

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

升级 Node.js 运行时

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

  1. 确保您的项目采用的是 Blaze 定价方案
  2. 确保您使用的是 Firebase CLI v11.18.0 或更高版本。
  3. 更改在初始化期间于 functions/ 目录下创建的 package.json 文件中的 engines 值。例如,如果您要从版本 18 升级到版本 20,请按如下方式设置该字段:"engines": {"node": "20"}
  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 代)中,每个实例一次可以处理一个请求,因此只能通过实例数下限和上限设置来设定扩缩行为。在 Cloud Functions for Firebase(第 2 代)中,除了控制实例数之外,您还可以使用 concurrency 选项来控制每个实例可以同时处理的请求数量。并发设置的默认值为 80,但您可以将其设为 1 到 1000 之间的任何整数。

并发设置值较高的函数可以在没有冷启动的情况下吸收流量高峰,因为每个实例都可能有一些提升潜力。如果某个实例配置为最多处理 50 个并发请求,但当前仅处理 25 个请求,那么该实例另外还能处理 25 个请求,而无需冷启动新实例。相比之下,如果并发设置设为 1,请求激增可能会导致 25 次冷启动。

这一简化的场景展示了并发能带来的潜在高效率。实际情况中,通过并发机制来进行扩缩行为,从而优化效率并减少冷启动次数,这个过程会更为复杂。Cloud Functions for Firebase 第 2 代中的并发由 Cloud Run 提供支持,并遵循 Cloud Run容器实例自动扩缩规则。

Cloud Functions for Firebase(第 2 代)中尝试使用更高的并发设置时,请注意以下几点:

  • 更高的并发设置可能需要更高的 CPU 和 RAM 才能获得最佳性能,直到达到实际限制。例如,执行大量图像或视频处理的函数可能缺乏处理 1,000 个并发请求的资源,即使其 CPU 和 RAM 设置已设为最大值也是如此。
  • 由于 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/v1');
    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,然后可以增加到 2 个 CPU,分配的内存分别为 4 GB 和 8 GB。请注意,这与第 1 代默认行为明显不同,可能会导致低内存函数的费用略高,如下表所示:

分配的 RAM 版本 1 的默认 CPU 数(分数) 版本 2 的默认 CPU 数 每毫秒的价格上调情况
128 MB 1/12 1 10.5x
256 MB 1/6 1 5.3x
512 MB 1/3 1 2.7x
1 GB 7/12 1 1.6x
2 GB 1 1 1x
4 GB 2 2 1x
8 GB 2 2 1x
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")

对于 CPU 密集型函数,第 2 代可让您灵活地配置额外的 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