Google Cloud Platform / Firebase Function 未通过 onWrite 触发

KGC*_*beX 6 node.js firebase google-cloud-functions google-cloud-firestore

我的应用程序利用Firestore 函数触发器根据 Firestore 中的更改(例如用户配置文件更改)执行后台操作。例如,如果他们更改手机号码,则会发送验证码。

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

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

要使Firebase 触发器正常工作,除了表示已创建/更改/删除的文档的文档 ID/通配符之外,还需要特定格式。

常数:

const collections = {
    ...
    conversations: "conversations",
    ...
}
Run Code Online (Sandbox Code Playgroud)

可调用函数(更新 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: ""
    }
});
Run Code Online (Sandbox Code Playgroud)

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)});
    });
Run Code Online (Sandbox Code Playgroud)

在我的移动应用程序中,用户(调用)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)
...
Run Code Online (Sandbox Code Playgroud)

我应该期待看到的:

...
{"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)
...
Run Code Online (Sandbox Code Playgroud)

我做错什么了吗?

KGC*_*beX 1

这个问题是一个离我们家较近的问题。

我正在使用firebase 模拟器进行开发,并使用 Flutter 的 firebase 包中内置的模拟器功能中的模拟器连接到它们。

Firebase 模拟器设置(例如Firebase 功能)可以在此处找到

长话短说:

启动 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.

...
Run Code Online (Sandbox Code Playgroud)

但是你会看到这一点 -这非常重要!

i  functions[us-central1-api-user-onConversationProfileCollectionCreate ]: function ignored because the database emulator does not exist or is not running.
Run Code Online (Sandbox Code Playgroud)

这是因为 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.
Run Code Online (Sandbox Code Playgroud)

并且这些函数不会自动附加到生产 Firestore/数据库(这可能会造成破坏),这些触发器在本地模拟时没有按我预期的方式运行。

解决方案:

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

  2. 上传函数以与 Firestore/数据库配合使用(请小心执行此操作


更多细节:

下面我提供了导致我出现问题的详细信息,以及我如何解决这个问题:

我在做什么:

firebase emulators:start --inspect-functions --only functions,auth
Run Code Online (Sandbox Code Playgroud)
  • [本地] Firebase 函数 我正在使用 Firebase 函数开发和测试我的移动应用程序的后端,以实现各种交互性。
  • 由于Firebase 身份验证是通过在我的 Firebase 函数应用程序上使用自定义令牌在本地处理的,因此我使用本地身份验证进行测试

我已经在 Firestore 中预填充了数据,因此我打算在本地模拟时使用 Firestore 数据,该数据已按预期工作,但由于在本地模拟,Firebase Firestore 和数据库触发器将无法工作。

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

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

firebase 模拟器:start --inspect-functions --only 函数,auth,firestore,数据库

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

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

从生产 Firestore 导入数据

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

有关详细信息,请参阅此内容 - 我无法从终端导出,因此我转到 Google Console 导出到存储桶,并通过控制台从那里下载它。

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

firebase emulators:start --inspect-functions --import ./functions/{path/to/data} --only functions,auth,firestore,database
Run Code Online (Sandbox Code Playgroud)

细节:

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