【发布时间】: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