繁体   English   中英

我怎样才能正确地消除 firebase 云 function 的执行

[英]How can i debounce the execution of a firebase cloud function correctly

我有一个 Firebase Cloud Function,它根据 Firebase 文档中提供的示例监视对我的实时数据库的更改。

我的 function 工作正常,每一次更改都按其编写的方式执行。

话虽如此,并且根据 Firebase 的建议:

• 去抖动——当监听Cloud Firestore 中的实时变化时,该解决方案很可能会触发多个变化。 如果这些更改触发的事件比您想要的多,请手动去抖动 Cloud Firestore 事件。

我想这样做。

任何人都可以提供一个好的方法吗?

如果我们根据 Firebase 的示例查看此 function:

exports.onUserStatusChanged = functions.database.ref('/status/{uid}').onUpdate(
            async (change, context) => {

  // Get the data written to Realtime Database
  const eventStatus = change.after.val();

  // Create a reference to the corresponding Firestore document
  const userStatusFirestoreRef = firestore.doc(`status/${context.params.uid}`);

  // re-read the current data and compare the timestamps.

  const statusSnapshot = await change.after.ref.once('value');
  const status = statusSnapshot.val();

  // If the current timestamp for this data is newer than
  // the data that triggered this event, we exit this function.

  if (status.last_changed > eventStatus.last_changed) {
    return null;
  }

  // Otherwise, we convert the last_changed field to a Date

  eventStatus.last_changed = new Date(eventStatus.last_changed);

  // write it to Firestore

  userStatusFirestoreRef.get().then((user: any) => {
    user.forEach((result: any) => {       
      result.ref.set(eventStatus, { merge: true })
    });
  });
  return;
});

我应该如何尝试去抖动它的执行?

我可以尝试去抖动.onUpdate()事件吗?

我最初认为以下内容就足够了:

functions.database.ref('/status/{uid}').onUpdate(
  debounce(async(change:any, context:any) => {
    ...
  }, 10000, {
    leading: true,
    trailing: false
  })
);

但是,感谢@doug-stevenson 指出尝试以这种方式去抖动 onUpdate 事件将不起作用,原因如下:

“那是行不通的,因为 function 的每次调用都可能发生在完全不同的没有共享上下文的服务器实例中。”

一种方法是使用任务调度程序(例如,Google Cloud Tasks)。 与其直接在云 function 本身中处理事件,不如使用任务调度程序来控制何时处理事件。

我提供了两种方法:一种用于去抖,一种用于延迟油门。

去抖动

这个想法是为每个云 function 调用排队一个任务。 如果已经为该实体安排了任务,则应取消现有任务。

例如,如果您的去抖间隔为 5 分钟,则将每个任务安排在未来 5 分钟后。 安排好每个任务后,取消该实体的前一个任务(如果有的话)。 当任务最终运行时,这意味着在 5 分钟内没有其他云调用(即成功的去抖动)。

延迟油门

延迟节流意味着您的事件在每个时间间隔最多处理一次,在时间间隔结束时。

这个想法是:每次云 function 运行时,仅当任务不是重复时才将其入队。 你会想要提出一个任务命名约定,让你删除冗余任务。

例如,您可以 append 具有计划执行时间的实体 ID。 当你的云 function 运行时,如果已经有那个 id 和时间的计划任务,你可以放心地忽略那个事件。

这是一个每分钟最多处理一次事件的代码示例。

// round up to the nearest minute
const scheduleTimeUnixMinutes = Math.ceil(new Date().getTime() / 1000 / 60);
const taskName = id + scheduleTimeUnixMinutes.toString();
const taskPath = client.taskPath(project, location, queue, taskName);

// if there's already a task scheduled for the next minute, we have nothing
// to do.  Google's client library throws an error if the task does not exist.
try {
  await client.getTask({ name: taskPath });
  return;
} catch (e) {
  // NOT_FOUND === 5.  If the error code is anything else, bail.
  if (e.code !== 5) {
    throw e;
  }
}

// TODO: create task here

由于每个事件可能会多次传递,因此您必须跟踪context.eventId中提供的事件 ID。 如果您看到重复的事件,您就知道它正在重复。

有许多策略可以做到这一点,而且没有一种正确的方法可以做到这一点。 您可以将处理后的 ID 存储在数据库或其他一些持久性存储中,但不能只将其存储在 memory 中,因为每个 function 调用都可以在彼此完全隔离的情况下发生。

另请阅读“幂等性”,因为这是函数的属性,每次调用的行为方式都相同。

https://firebase.google.com/docs/functions/tips#write_idempotent_functions

https://cloud.google.com/blog/products/serverless/cloud-functions-pro-tips-building-idempotent-functions

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM