簡體   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