删除文档时 Firestore 事务不会失败



我想将钱包分配给一个用户,然后删除该钱包,这样它就不会再次分配给另一个用户。我使用事务来完成这项工作,但即使我手动删除文档,事务也会在不抛出的情况下恢复:

try {
return await admin.firestore().runTransaction(async t => {
// get the user document (users collection)
const userSnapshot = await t.get(userRef);
const user = userSnapshot.data();
// if it has a wallet, just return it
if (user.wallet) return user.wallet;
// now I get a wallet (wallets collection, id was randomically picked)
const walletShapshot = await t.get(walletRef);
// if wallet was deleted by another execution, return undefined (it'll be retried by the code that started the transaction)
if (!walletShapshot.exists) return;
console.log('before', wallet.id, wallet.address);
await delay(20000); // <== here I manually delete the document from firestore
console.log('moving on')
const w = await walletShapshot.data();
console.log('after', walletShapshot.id, w.address);
await t.delete(walletRef); // here it's deleting the already deleted wallet
await t.update(userRef, {
wallet: w.address,
walletReferenceId: w.referenceId,
assigned: new Date().toISOString()
});
return w.address; // here I get the wallet that was deleted!
});
} catch (error) {
console.log(error)
// returning undefined will trigger a retry
}

文档指出,删除被视为对基础文档的更改,因此交易将恢复,但我得到的是在交易过程中删除的钱包。

这里出了什么问题?

编辑:以下是文档对事务中.delete()的描述:

事务由任意数量的get((操作组成,后跟任意数量的写操作,如set((、update((或delete((。在并发编辑的情况下,Cloud Firestore运行再次交易。例如,如果事务读取文档并且另一个客户端修改任何这些文档,Cloud Firestore重试事务。此功能可确保交易基于最新且一致的数据运行。

https://firebase.google.com/docs/firestore/manage-data/transactions#transactions

Firestore使用了两种并发模型:对于客户端SDK,它使用乐观控制;对于管理员SDK,它则使用悲观控制。

这意味着在后端,它将暂停顺序事务,并在锁定释放后立即执行它们。

按照Doug Stevenson的建议,我的测试似乎是错的。事务隔离将在事务启动的相同上下文中发生:

可能是"并发编辑";仅适用于多个客户端,每个客户端使用一个事务。

我确认在同一上下文中对同一文档进行的两次编辑都已排队并解决,没有出现错误。

https://firebase.google.com/docs/firestore/transaction-data-contention#isolation_within_a_transaction

最新更新