【问题标题】:Google Cloud Platform / Firebase Function not triggering with onWriteGoogle Cloud Platform / Firebase 功能未通过 onWrite 触发
【发布时间】:2021-09-14 02:50:41
【问题描述】:

我的应用程序使用 Firestore Function Triggers 根据 Firestore 中的更改执行后台操作,例如用户配置文件更改。例如,如果他们更改了手机号码,则会发送验证码。

我有一个触发器,当特定集合上发生onWrite() 事件时应该运行该触发器。 onWrite() 在 Firebase 中针对特定集合发生以下任何操作时运行:

在我的用例中,我需要它为onCreate()onUpdate() 运行,因此我使用onWrite()

对于 Firebase Triggers to work,除了表示已创建/更改/删除的文档的文档 ID/通配符之外,还需要特定格式。

常量:

const collections = {
    ...
    conversations: "conversations",
    ...
}

可调用函数(更新 firestore):

/**
 * Add an conversation to conversations collection
 * @type {HttpsFunction & Runnable<any>}
 */
exports.addConversations = functions.https.onCall(async (data, context) =>  {
    // expects conversation & interested state
    const {valid, errors} = validateRequiredBody(data, [
        "conversation",
    ]);
    if (!valid) {
        return {
            status: false,
            message: "Missing or invalid parameters",
            errors: errors,
            jwtToken: "",
        };
    }

    // get conversation item
    const conversation = {
        id: data["conversation"]["id"],
        name: data["conversation"]["name"],
    }

    // create conversation with empty counter
    // let writeResult = await collectionRefs.conversationsRef.doc(conversation.id).set({
    let writeResult = await admin.firestore().collection(collections.conversations).doc(conversation.id).set({
        id: conversation.id,
        name: conversation.name,
        count: 0
    });
    console.log(`[function-addConversations] New Conversation [${conversation.name}] added`);

    return {
        status: true,
        message: ""
    }
});

Firestore 触发器(未触发):

/**
 * On conversations updated/removed, update corresponding counter
 * @type {CloudFunction<Change<QueryDocumentSnapshot>>}
 */
exports.onConversationProfileCollectionCreate = functions.firestore.document(`${collections.conversations}/{id}`)
    .onWrite(async snapshot => {
        console.log("Conversation Collection Changed");
        // let conversation = collectionRefs.conversationsRef.doc(snapshot.id);
        // await conversation.update({count: FieldValue.increment(1)});
    });

在我的移动应用程序中,用户(调用)addConversations() firebase 函数,这会将新对话添加到清晰可见的 Firestore,但计数器触发器(触发函数)不运行。

模拟器输出:

...
{"verifications":{"app":"MISSING","auth":"MISSING"},"logging.googleapis.com/labels":{"firebase-log-type":"callable-request-verification"},"severity":"INFO","message":"Callable request verification passed"}
[function-addConversations] New Conversation [Test Conversation Topic] added
Profile updated 
(print profile data)
...

我应该看到的:

...
{"verifications":{"app":"MISSING","auth":"MISSING"},"logging.googleapis.com/labels":{"firebase-log-type":"callable-request-verification"},"severity":"INFO","message":"Callable request verification passed"}
[function-addConversations] New Conversation [Test Conversation Topic] added
Conversation Collection Changed      // this is output by the trigger
Profile updated 
(print profile data)
...

我是不是做错了什么?

【问题讨论】:

  • 你从日志中的函数执行中看到了什么吗?例如。 onConversationProfileCollectionCreate Function execution started
  • 嗨@RenaudTarnec 没有。我有一个配置文件onWrite() 触发器输出Profile Updated,但标准终端输出中没有其他内容。您对我如何启用详细日志记录有什么建议吗?
  • 如果您尝试部署 Cloud Functions 会发生什么?
  • 可能是集合名称声明不正确或其他原因。您是否检查过${collections.conversations} 是否具有您期望的值?另外,firebase-debug.log 中是否出现任何错误?
  • 当你在你的系统上测试这个时,你确定你的云函数是writing to the emulators而不是你的实时数据库吗?

标签: node.js firebase google-cloud-firestore google-cloud-functions


【解决方案1】:

您使用了错误的值。快照仅适用于 onDelete 和 onCreate 方法

exports.useWildcard = functions.firestore
    .document('users/{userId}')
    .onWrite((change, context) => {
      // If we set `/users/marie` to {name: "Marie"} then
       context.params.userId == "marie"
      // ... and ...
      change.after.data() == {name: "Marie"}
    });

更多信息请阅读这里feedbackCloud Firestore triggers

【讨论】:

  • 来自 firebase 示例:firebase.google.com/docs/functions/…
  • 我添加了链接。这就是为什么我说“更多信息请阅读这里”
  • 啊 - 我看到了混乱。 snapshot.onWrite(async snapshot =&gt; { 的上下文中可能会引起混淆,但这基本上只是一个变量名称,例如上下文、更改等。这不是它不起作用的根本原因/原因 - 你的建议仅仅是美学。有关原因和解决方案,请参阅我发布的答案。
【解决方案2】:

问题是离家更近。

我正在使用firebase emulators 进行开发,并使用在emulator feature 中内置的 Flutter 的 firebase 包中添加的模拟器来连接它们。

Firebase 模拟器设置,例如Firebase Functions可以找到here

TL;DR:

启动 Firebase 模拟器时,您应该会看到类似以下内容:

C:\Users\User\MyApp\awesome-app-server>firebase emulators:start --only functions
i  emulators: Starting emulators: functions
!  functions: You are running the functions emulator in debug mode (port=9229). This means that functions will execute in sequence rather than in parallel.
!  functions: The following emulators are not running, calls to these services from the Functions emulator will affect production: auth, firestore, database, hosting, pubsub, storage
!  Your requested "node" version "12" doesn''t match your global version "14"
i  ui: Emulator UI logging to ui-debug.log
i  functions: Watching "C:\Users\User\MyApp\awesome-app-server\functions" for Cloud Functions...
>  Debugger listening on ws://localhost:9229/03dc1d62-f2a3-418e-a343-bb0b357f7329
>  Debugger listening on ws://localhost:9229/03dc1d62-f2a3-418e-a343-bb0b357f7329
>  For help, see: https://nodejs.org/en/docs/inspector
!  functions: The Cloud Firestore emulator is not running, so calls to Firestore will affect production.
!  functions: The Realtime Database emulator is not running, so calls to Realtime Database will affect production.

...

但是你看到了 - 这非常重要!

i  functions[us-central1-api-user-onConversationProfileCollectionCreate ]: function ignored because the database emulator does not exist or is not running.

由于 Firestore 和(实时)数据库使用在函数中找到的触发器,因此函数需要找到本地 Firestore/数据库模拟器。

因为本地没有运行任何 Firestore/数据库模拟器

!  functions: The Cloud Firestore emulator is not running, so calls to Firestore will affect production.
!  functions: The Realtime Database emulator is not running, so calls to Realtime Database will affect production.

并且这些函数不会自动附加到生产 Firestore/Database(s)(这可能会破坏),这些触发器没有按我的预期运行他们在本地模拟

解决方案:

  1. 使用firebase emulators:start --only functions,...,firestore,database在本地模拟firestore和数据库(请参阅this将您的firestore数据导入本地模拟器)

  2. 上传函数以使用 Firestore/数据库(请谨慎操作


更多详情:

下面我提供了导致我遇到问题的详细信息,以及我是如何解决问题的:

我在做什么:

firebase emulators:start --inspect-functions --only functions,auth
  • [local] Firebase Functions 我正在使用 Firebase Functions 为我的移动应用开发和测试后端,以实现各种交互性。
  • 由于 Firebase Auth 是通过在我的 firebase 函数应用上使用 custom tokens 在本地处理的,因此我使用本地身份验证进行测试

我已经用数据预先填充了我的 Firestore,因此我打算在本地模拟时使用 Firestore 数据,这已按预期工作,但是由于在本地模拟它们,firebase firestore 和数据库触发器将无法工作。

我知道我的一些触发器 DID 实际上是正确触发的,因此它一定是某种配置错误。

扩展解决方案将 firestore 数据导入本地模拟器

firebase 模拟器:开始 --inspect-functions --only 函数、auth、firestore、数据库

注意最后 2 个,firestore 和数据库 - 应该添加它以使触发器在本地工作

  • 我注意到在启动时查看日志时,指示某些功能的文本将无法运行。这让我意识到我犯了一个重大错误——原因。

从生产 Firestore 导入数据

使用生产(开发期间)firestore 的原因是不为每个测试重新创建所有数据。解决方案是从 firestore 导出并将您的数据导入模拟器。

看到这个details - 我无法从终端导出,因此我去谷歌控制台导出到存储桶,然后从那里通过控制台下载它。

要启动模拟器(并允许调试 firebase 函数),我使用:

firebase emulators:start --inspect-functions --import ./functions/{path/to/data} --only functions,auth,firestore,database

详情:

  • firebase emulators:start - 启动模拟器
  • --inspect-functions 允许通过 websockets 调试功能 - 例如端口 9229 上的 Webstorm NodeJs 调试器
  • --import ./functions/{path/to/data} - 使用项目根目录将数据导入到 Firestore 模拟器 ./
  • --only functions,auth,firestore,database 指定要模拟的模块

【讨论】:

    猜你喜欢
    • 2018-05-16
    • 2018-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-25
    • 2023-03-28
    • 2019-01-25
    相关资源
    最近更新 更多