在我的第二代云函数中,我有以下代码:
export const roomEnter = functions.https.onCall(async (request: any) => {
// initial validation to verify user authentication and valid request data passes first
...
const roomRef = admin.database().ref(`rooms/${request.data.roomId}`);
const roomSnapshot = await roomRef.once("value");
const testDataExists = {
exists: roomSnapshot.exists(),
data: roomSnapshot.val()
};
functions.logger.log("[room enter] CHECK ROOM EXISTS:", JSON.stringify(testDataExists));
// In the logs, the data that exists DOES print to the console successfully
const transactionRef = admin.database().ref(`rooms/${request.data.roomId}`);
const transactionResult = await transactionRef.transaction((currentData) => {
functions.logger.log("[room enter] Transaction current data:", JSON.stringify(currentData));
// In the logs, `currentData` prints as `null`, why?
// As a result, the transaction never gets beyond this condition and fails i assume after it has exhausted all internal retries
if (currentData !== null) {
if (currentData.memberTotal) {
currentData.memberTotal += 1;
} else {
currentData.memberTotal = 1;
}
return currentData;
} else {
functions.logger.log("[room enter] Transaction needs to retry, room current data is null", {
roomId: request.data.roomId
});
return; // Returning undefined should cause Firebase to retry the transaction
}
});
if (transactionResult.committed) {
// never able to reach this point
} else {
functions.logger.log("[room enter] transaction to increment member total failed");
throw new functions.https.HttpsError("internal", "transaction to increment member total failed", {
customData: {
roomId: request.data.roomId
}
});
}
...
});
我在交易之前执行的测试查询只是作为确认数据存在的测试。
正如上面代码注释中所述,尽管现有数据的引用路径已被确认存在,但事务仍失败。
除了尝试尽可能记录错误之外,我不知道如何解决此问题。
我拥有的其他不使用事务的云功能能够毫无问题地读取和写入数据库。
除了日志之外,我拥有的唯一附加信息是客户端将错误作为 500 内部服务器错误以及响应报告给客户端,其中包含包含消息
transaction to increment member total failed
的错误响应。
关于我的数据库安全规则,作为一个测试,为了排除这个原因,我为
".write": true
和rooms
设置了
rooms/$roomId
那么,为什么
currentData
null
会出现在交易中?
我还能做什么来排除故障?
Firebase 实时数据库事务处理程序几乎总是会在最初使用可变数据中的
null
值进行调用,无论数据库中的实际值是什么。
这是因为 SDK 会立即使用对当前值的最佳猜测来调用您的处理程序,这通常是
null
。您的代码需要处理这种情况,以便 SDK 可以将空值和新值发送到服务器,意识到它的猜测是错误的,然后重试。