簡體   English   中英

Firebase 實時數據庫事務和雲功能

[英]Firebase realtime database transaction and cloud functions

我在 Firebase 實時數據庫中有一個列表,結構如下:

list: {
  change: {
    rate: integer,
    last: Date
  },
  lock: string,
  elements: {
    ...
  },
  size: integer
}

客戶端只將元素添加到列表中。 元素的子元素上有一個由onCreate事件觸發的雲函數。 它事務性地增加數據庫中的list.size ,然后對可能涉及刪除所有或部分子項的元素執行計算。 還有另一個雲函數由元素的子元素上的onDelete事件觸發,它只會事務性地減少數據庫中的list.size 問題是計數器在一段時間后變得不准確。 有時它顯示列表中的更多元素,有時更少。 以下是[改編]代碼:

exports.element_add = functions.database.ref('/list/elements/{element}).onCreate(
  (snapshot, context) => {
    const elements = snapshot.ref.parent;

    return new Promise(
      (resolve, reject) => {
        const start = new Date().getTime();

        async.waterfall(
          [
            // read and write to list.change
            // ...
            (next) => {
              // increment list size
              _changeSize(elements.parent, +1, 1, next)
            },
            // acquire lock if required and do calculations on list elements
            // ...
          ],
          // finally
          function (e) {
            // release the lock
            // ...
            // handle errors
            if (e)
              return reject(e);

            resolve();
          }
        );
      });
  });


exports.element_remove = functions.database.ref('/list/elements/{element}).onDelete(
  (snapshot, context) => {
    const elements = snapshot.ref.parent;

    return new Promise(
      function (resolve, reject) {
        _changeSize(elements.parent, -1, 1,
          function (e) {
            if (e)
              return reject(e);

            resolve();
          }
        )
      }
    )
  });

function _changeSize(list, delta, attempt, done) {
  list.child('size').transaction(
    // update
    (size) => {
      if (size === null)
        return null;

      return size + delta;
    },
    // finally
    (e, committed, snapshot) {
      if (e) {
        console.error(`size transaction error: ${e}, retrying in 1 sec`);

        // try again
        return setTimeout(_changeSize, 1000, list, delta, attempt + 1, done);
      }

      console.log(committed ? `new list size is ${snapshot.val()}` : 'list size was not updated');

      // return new size if committed
      done(null, committed ? snapshot.val() : undefined);
    },
    // do not apply locally
    false
  );
}

除了上面的兩個雲函數之外,沒有其他實體使用list.size 問題是為什么list.size的值與list.elements不同步?

2020 年 2 月 26 日更新:顯然不止一次收到一些 onCreate/onDelete 事件! 我們已經觀察到它們在雲函數實例之間的傳播甚至達到了 3 次。 這是正常行為還是我們做錯了什么?

您必須使用實時數據庫事務

遞增如下:

exports.element_add = functions.database.ref('/list/elements/{element}').onCreate(
  (snapshot, context) => {

    const sizeRef = admin
    .database()
    .ref('/list/size');

    return sizeRef
      .transaction(current_value => {
        return (current_value || 0) + 1;
      });

});

並如下遞減:

exports.element_delete = functions.database.ref('/list/elements/{element}').onDelete(
  (snapshot, context) => {

    const sizeRef = admin
    .database()
    .ref('/list/size');

    return sizeRef
      .transaction(current_value => {
        if (current_value > 0) {
            return current_value - 1;
        } else  {
           //Normally we should never reach this line...
           return null;
        }
      });

});

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM