【问题标题】:Avoid triggering Firebase functions by real-time database on special cases避免在特殊情况下通过实时数据库触发 Firebase 功能
【发布时间】:2021-02-17 10:46:32
【问题描述】:

有时我们使用实时数据库触发的firebase函数(onCreate/onDelete/onUpdate ...)来做一些逻辑(如计数等)。

我的问题是,在某些情况下是否可以避免这种触发。主要是,当我想允许用户将巨大的 JSON 导入到 firebase 时?

示例: 在 /examples 中创建新子项时触发的函数 E。通常情况下,用户会一一添加示例到 /examples 并运行函数 E 来做一些逻辑。但是,我想允许用户(来自前端)将 2000 个子项导入到 /examples,并且函数 E 完成的逻辑在导入时是可能的,而不需要 E。然后,我不需要 E在可以执行大量功能的情况下触发。 (注意:我知道 1000 的限制)

更新: 根据接受的答案,提交我的答案。

【问题讨论】:

  • 可以使用参数,像这样: if(status === 'dont') return ?
  • 但这会触发函数,对吧?所以我们只是跳过逻辑并限制函数。

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


【解决方案1】:

据我所知,如果不删除云功能,就无法以编程方式禁用它。然而,这引入了一种边缘情况,即在导入时将数据添加到数据库中。

一种折衷方案是表明您上传的数据应进行后处理。假设您正在上传到/examples/{pushId},而不是将数据库触发器附加到/examples/{pushId},而是将其附加到/examples/{pushId}/needsProcessing(或类似的东西)。不幸的是,这样做的代价是无法将change 对象用于onUpdate()onWrite()

const result = await firebase.database.ref('/examples').push({
  title: "Example 1A",
  desc: "This is an example",
  attachments: { /* ... */ },
  class: "-MTjzAKMcJzhhtxwUbFw",
  author: "johndoe1970",
  needsProcessing: true
});
async function handleExampleProcessing(snapshot, context) {
  // do post processing if needsProcessing is truthy
  if (!snapshot.exists() || !snapshot.val()) {
    console.log('No processing needed, exiting.');
    return;
  }

  const exampleRef = admin.database().ref(change.ref.parent); // /examples/{pushId}, as admin
  const data = await exampleRef.once('value');

  // do something with data, like mutate it

  // commit changes
  return exampleRef.update({
    ...data,
    needsProcessing: null /* delete needsProcessing value */
  });
}

const functionsExampleProcessingRef = functions.database.ref("examples/{pushId}/needsProcessing");

export const handleExampleNeedingProcessingOnCreate = functionsExampleProcessingRef.onCreate(handleExampleProcessing);

// this is only needed if you ever intend on writing `needsProcessing = /* some falsy value */`, I recommend just creating and deleting it, then you can use just the above trigger.
export const handleExampleNeedingProcessingOnUpdate = functionsExampleProcessingRef.onUpdate((change, context) => handleExampleProcessing(change.after, context));

【讨论】:

  • 同意——我想我们找到了一个修改版本——我也可以分享一个答案。您建议的问题是我们无法知道更新时的旧值。此外,导入功能可能会删除一些会触发更多功能的键。我会接受答案。请查看我的回答以获取任何反馈
【解决方案2】:

Sam's approach 的替代方法是使用功能标志来确定云函数是否执行其主要功能。我的代码中经常有这个:

exports.onUpload = functions.database
  .ref("/uploads/{uploadId}")
  .onWrite((event) => {
  return ifEnabled("transcribe").then(() => {
    console.log("transcription is enabled: calling Cloud Speech");
    ...
  })
});

ifEnabled 是一个简单的辅助函数,用于检查(也在实时数据库中)是否启用了该功能:

function ifEnabled(feature) {
  console.log("Checking if feature '"+feature+"' is enabled");
  return new Promise((resolve, reject) => {
    admin.database().ref("/config/features")
      .child(feature)
      .once('value')
      .then(snapshot => {
        if (snapshot.val()) {
          resolve(snapshot.val());
        }
        else {
          reject("No value or 'falsy' value found");
        }
      });
  });
}

我对此的大部分使用是在会议的演讲中,以便在正确的时间启用云功能(因为部署所需的时间比我们想要的演示要长一些)。但同样的方法应该可以在例如数据导入期间暂时禁用功能。

【讨论】:

  • 感谢您及时帮助解决这个问题。恐怕这仍然会触发功能
【解决方案3】:

好的,另一种解决方案是

A:在 firebase 中添加一个新表,例如 /triggers-queue,其中添加了所有应该触发后台函数的 CRUD。在这个表中,我们为每个应该有触发器的表添加一个键 - 在我们的示例中为 /examples 表。表示表的任何键还应具有/created/updated/deleted 键,如下所示。

/examples
.../example-id-1

/triggers-queue
.../examples
....../created
........./example-id
....../updated
........./example-id
............old-value
....../deleted
........./example-id
............old-value

请注意,应从应用程序(前端等)添加旧值。 我们总是设置触发器 onCreate on /triggers-queue/examples/created/{exampleID}(模拟onCreate)

/triggers-queue/examples/updated/{exampleID}(模拟更新)

/triggers-queue/examples/deleted/{exampleID}(模拟 onDelete)

被触发的函数可以知道处理逻辑的所有必要信息,如下所示:

  • 操作类型:来自路径(要么:创建、更新或删除)
  • 对象的键:来自路径
  • 当前数据:通过读取对应表(即/examples/id
  • 旧数据:来自触发器表

优点:

  • 您可以将大量数据导入/examples 表而不触发任何函数,因为我们不添加到/triggers-queue
  • 您可以将函数扇出以超过 1000/秒的限制。那是通过设置触发器(作为创建时扇出的示例) /triggers-queue/examples/created0/{exampleID}/triggers-queue/examples/created1/{exampleID}

坏点:

  • 更难实施
  • 需要从应用向 Firebase 写入更多数据(如旧数据)。

B- 另一种方法(虽然不是这个问题的答案)是将后台函数中的登录移动到 HTTP 函数并在每个 crud 操作上调用它。

【讨论】:

    猜你喜欢
    • 2018-11-06
    • 1970-01-01
    • 1970-01-01
    • 2018-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-10
    相关资源
    最近更新 更多