多次调用 Cloud Functions for Firebase

Posted

技术标签:

【中文标题】多次调用 Cloud Functions for Firebase【英文标题】:Cloud Functions for Firebase invoked many times 【发布时间】:2017-08-07 16:50:37 【问题描述】:

我只是在试用 Cloud Functions for Firebase,以便将我的 firebase-queue 工作人员转移到云功能。每当我在给定的 ref 创建一个新节点时,我添加了一个简单的函数来添加最后更新的时间戳。函数如下所示:

var functions = require('firebase-functions');
const admin = require('firebase-admin');

admin.initializeApp(functions.config().firebase);

exports.setLastUpdatedTimestamp = functions.database.ref('/nodes/nodeId')
  .onWrite(event => 
    const original = event.data.val();
    console.log('Adding lastUpdatedTimestamp to node ', original.name);
    return event.data.ref.child('lastUpdatedAtFromFC').set(Date.now());
  );

我部署了这个云功能并从我的应用程序中添加了一个节点。我去了 Firebase Functions 仪表板,发现该函数已被调用 169 次,但我不知道为什么。当我查看日志时,我会看到类似将函数附加到所有过去节点的日志。

onWrite 的行为是否类似于child_added 并为所有现有实体运行该函数?

每次我更改并再次部署该功能时是否会重复此操作?

我希望它只为新添加的节点运行一次。

【问题讨论】:

检查下面的答案 【参考方案1】:

这是编写处理数据库写入的函数时的常见错误。当您在某个位置处理初始写入的事件时,然后对同一位置进行第二次写回,第二次写入将触发另一个事件,该事件将再次运行该函数,依此类推,这将是一个无限循环。

您的函数中需要一些逻辑来确定第二个写入事件是否不应重新写入数据库。这将停止循环。在您的情况下,您不需要设置上次更新时间的功能。您可以在客户端使用特殊值来告诉服务器将当前时间插入到字段中。

https://firebase.google.com/docs/reference/js/firebase.database.ServerValue#.TIMESTAMP

【讨论】:

感谢您的回答。像这样更新上次更新的时间戳并不是我真正打算做的事情,而只是我认为可以尝试云功能的事情。 这很公平 - 像这样自动更新值绝对是一个用例。有时要确保在该终止情况下进行编码可能会很棘手。 :-) 是的,我很高兴当我犯了这个错误时我没有使用付费计划。 :) 不知道我会被收取多少费用。我让它在一夜之间运行,我可以在函数控制台上看到大量日志,这些日志由于已达到配额而无法调用函数。【参考方案2】:

道格是正确的。此外,最好知道如果您有一个函数陷入无限循环,让它停止的方法是重新部署您的函数(使用firebase deploy)并修复循环,或删除该函数完全(通过将其从您的 index.js 中删除并运行 firebase deploy)。

【讨论】:

感谢停止云功能的提示。 真的希望将来有办法通过管理门户禁用功能.. :) 你不能删除 index.js 然后运行firebase deploy。它抛出Error: functions\index.js does not exist, can't deploy Firebase Functions 是的 - 要删除所有函数,您需要从 index.js 中删除所有函数,但在运行 firebase deploy 时保持文件(空)。【参考方案3】:

我有这个确切的问题。这里有两个问题。如何在无限循环开始后停止它。已经回答了。但真正的问题是如何使用 Firebase Cloud Function 触发器向您的对象添加 lastUpdated 日期字段。

这是我处理onWrite() 循环问题的尝试。

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();


exports.onWriteFeatherUpdateSummary = functions.database.ref('/messages/id')
    .onWrite((change, context) => 
      // Grab the current value of what was written to the Realtime Database.
      let updated = change.after.val();
      // Grab the previous value of what was written to the Realtime Database.
      const previous = change.before.val();
      let isChanged = true;
      let isCreated = (previous === null); // object 'created'

      // Only when the object gets updated
      if (!isCreated) 
        // An object should never directly change the lastUpdated value, this is for trhe trigger only
        isChanged = (updated.lastUpdated === previous.lastUpdated);
      

      console.log(`isChanged: $isChanged ; isCreated: $isCreated`);

      if(isChanged) 
        // Insert whatever extra data you wnat on the update trigger
        const summary = `This is an update!`;

        // Add a 'createdDate' field on the first trigger
        if (isCreated) 
          // Make sure your object has a createdDate (Date) before the lastUpdated (Date)!
          Object.assign(updated,
              
                createdDate : admin.database.ServerValue.TIMESTAMP
              
            );
        

        // Add lastUpdated Date field on very update trigger (but not when you just changed it with the trigger!)
        Object.assign(updated,
            
              summary : summary,
              lastUpdated : admin.database.ServerValue.TIMESTAMP
            
          );
      

      return change.after.ref.set(updated);
    );

【讨论】:

以上是关于多次调用 Cloud Functions for Firebase的主要内容,如果未能解决你的问题,请参考以下文章

Cloud Functions for Firebase 组织

如何在 Cloud Functions for Firebase 中使 HTTP 请求异步/等待?

如何使用 Google Python Client for Cloud Functions 获取 Google Cloud Functions 列表?

Cloud Functions for Firebase 超时

Cloud Functions for Firebase onWrite 超时

在 Cloud Functions for Firebase 中访问 db 数据