【问题标题】:Firebase realtime database transaction and cloud functionsFirebase 实时数据库事务和云功能
【发布时间】:2020-05-15 23:12:08
【问题描述】:

我在 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-02-26 更新:显然有些 onCreate/onDelete 事件被多次接收!我们观察到它们在云函数实例之间的传播甚至达到了 3 倍。这是正常行为还是我们做错了什么?

【问题讨论】:

  • 您提到了一个实时数据库事务。你如何执行交易?为什么不使用标准的事务机制(firebase.google.com/docs/database/web/…)?
  • 事务实际上用在_changeSize()中。请看那里的第一行。

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


【解决方案1】:

您必须使用实时数据库transaction

递增如下:

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;
        }
      });

});

【讨论】:

  • 事务实际上用在_changeSize()中。请看那里的第一行。
  • 您是在使用真正的实时数据库事务还是在使用另一个node.js 库来实现这个“事务”?
  • 正品。 _changeSize 接收“list” ref,然后在 list.size 上启动事务。
  • 您能否将_changeSize 的确切代码添加到您的问题中?
  • 一切尽在此处,在代码 sn-p 中。 sn-p中有3个功能。 _changeSize() 是最后一个。
猜你喜欢
  • 1970-01-01
  • 2019-11-08
  • 1970-01-01
  • 1970-01-01
  • 2017-11-23
  • 1970-01-01
  • 1970-01-01
  • 2021-11-23
  • 2018-10-08
相关资源
最近更新 更多