Firebase 事务不会在失败时重复

Firebase transaction is not repeating on failure

更新:

这是我收到的 console.error(err) 消息:

Error: 6 ALREADY_EXISTS: Document already exists: projects/projectOne-e3999/databases/(default)/documents/storage/AAAAAAAAAA1111111111

我明白为什么会出现错误。因为并行事务 运行ning 执行事务的 else 部分速度更快。因此返回错误的事务不必创建而是更新文档。如果交易重新运行就足够了。但它并没有说明 Transactions are committed once 'updateFunction' resolves and attempted up to five times on failure.

这就是问题的重点。当文档已经存在时,我如何防止交易失败,因为它是并行创建的,或者如何重新运行交易?

原题:

我有一个云函数,每当创建另一个集合中的文档时,它就会更新另一个文档。由于可以并行创建多个文档,所有这些文档都访问同一个文档,这将 运行 作为事务处理,保证了幂等性。

函数的结构如下所示。问题是第一次写入(因此创建了存储文档)。正如我所说,可以并行创建两个文档。但是现在事务读取了一个不存在的文档并尝试创建它,但是由于另一个事务(并行 运行ning 一个)已经创建了该文档,事务失败了。 (我一开始就不明白,因为我认为交易会在执行时阻止所有访问)

这根本不是问题,但它不会重试(尽管它声明最多会自动重试 5 次)。我认为这与我的异步函数的 try & catch 块有关。

如果重试,它将检测到文档存在并自动更新现有文档。

让我们简单点。此交易绝不能失败。如果没有可能的自动恢复方式,它会使数据库不一致。

.onCreate(async (snapshot, context) => {
        //Handle idempotence
        const eventId = context.eventId;
        try {
            const process = await shouldProcess(eventId)
            if (!process) {
                return null
            }

            const storageDoc = admin.firestore().doc(`storage/${snapshot.id}`)

           
            await admin.firestore().runTransaction(async t => {
                    const storageDbDoc = await storageDoc.get()
                    const dataDb = storageDbDoc.data()

                    if (dataDb) {
                        //For sake of testing just rewrite it
                        t.update(storageDoc, dataDb )
                    } else {
                        //Create new     
                        const storage = createStorageDoc()
                        t.create(storageDoc, storage )    
                    }
            })
            return markProcessed(eventId)
        } catch (err) {
            console.error(`Execution of ${eventId} failed: ${err}`)
            throw new Error(`Transaction failed.`);
        }

您的事务坚持能够创建一个新文档:

t.create(storageDoc, storage)

由于create()在文档已经存在的条件下失败,整个交易就失败了,无法恢复。

如果您的交易必须能够恢复,您应该在尝试写入之前检查该文档是否存在,并决定在这种情况下您想要做什么。