Как правильно отменить выполнение облачной функции Firebase? - PullRequest
2 голосов
/ 31 октября 2019

У меня есть облачная функция Firebase, которая отслеживает изменения в моей базе данных реального времени на основе примера, предоставленного в документации Firebase .

Моя функция работает правильно и выполняется для каждого изменения, каким оно былонаписано для выполнения.

С учетом сказанного и в соответствии с рекомендацией Firebase:

• Отмена ответа - при прослушивании изменений в реальном времени в Cloud Firestore, это решениеможет вызвать несколько изменений. Если эти изменения вызывают больше событий, чем вы хотите, вручную отмените события Cloud Firestore.

Я бы хотел сделать именно это.

Может кто-нибудь предложить хороший подход?

Если мы посмотрим на эту функцию на примере Firebase:

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 таким способом не будет работать по следующей причине:

"Это не сработает, потому что каждый вызов функции может происходить в совершенно другом экземпляре сервера без общего контекста."

1 Ответ

2 голосов
/ 31 октября 2019

Поскольку каждое событие может быть доставлено более одного раза, вы должны отслеживать предоставленный идентификатор события, указанный в context.eventId . Если вы видите повторяющееся событие, вы знаете, что оно повторяется.

Для этого существует множество стратегий, и не существует единственно правильного способа сделать это. Вы можете сохранить обработанный идентификатор в базе данных или другом постоянном хранилище, но вы не можете просто сохранить его в памяти, поскольку каждый вызов функции может происходить в полной изоляции друг от друга.

Также читайте о «идемпотентности»", поскольку это свойство функций, они ведут себя одинаково при каждом вызове.

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

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

...