首页 文章

如何在 Cloud 函数中重试Cloud Firestore事务,直到state == true

提问于
浏览
2

问题

我有一个Cloud Function,它根据文档 state 字段中的更改来更新Cloud Firestore文档 . 这些更新 must 按特定顺序发生 . 当快速连续进行两次更改时,无法保证 Cloud 功能将以正确的顺序运行 . 有没有办法让Cloud Firestore事务重试,直到成功或超时?

  • Document.state 设为 stage1

  • Document.state 已更新至 stage2

  • Document.state 已更新至 stage3

  • Cloud 功能被触发并读取 stage3

  • Cloud 功能被触发并读取 stage2

在Cloud Functions文档中,它讨论了在失败时重试事务的能力 . 但是,此选项在GCP控制台的“ Cloud 功能”部分中显示为灰色(未在Firebase控制台中显示)

示例代码

传入的变量

myDocumentRef: db.doc('myCollection/myDocument')
newState: stage3

交易代码

var transaction = db.runTransaction(t => {
    return t.get(myDocumentRef)
        .then(doc => {
            if ((newState = 'stage2' && doc.data().state = 'stage1') ||
                (newState = 'stage3' && doc.data().state = 'stage2')) {
              t.update(myDocumentRef, { population: newPopulation });
            } else {
              // Keep retrying the transaction until it succeeds
            }
        });
}).then(result => {
    console.log('Transaction success!');
}).catch(err => {
    console.log('Transaction failure:', err);
});

2 回答

  • 0

    默认情况下,Firestore事务会自行重试 . The documentation for transactions州:

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

    此重试采用事务处理函数(您传递给runTransaction的函数)的重复调用的形式 .

    Cloud 功能重试机制是不同的 . 它重试不完全成功的功能 . 有关其工作原理的详细信息,请参阅here . 它与Firestore事务无关 . 这些重试的语义与所使用的触发器类型无关 .

  • 1

    您的问题基本上有两种选择:

    1.使用Google Cloud RETRY标记

    当您部署一个函数时,您只需启用重试,这将导致google-cloud环境自动调用您的函数,如果它抛出 any error (或返回被拒绝的Promise)这听起来相当不错,直到您意识到这可能会创建 !significant charges! ,因为如果你您的函数中有一个错误,每次都会抛出一个错误,该函数将被调用数千次,直到一两天后最终超过重试限制 .

    你的功能可能如下所示:

    return t.get(myDocumentRef)
        .then(doc => {
            if ((newState = 'stage2' && doc.data().state = 'stage1') ||
                (newState = 'stage3' && doc.data().state = 'stage2')) {
              t.update(myDocumentRef, { population: newPopulation });
            } else {
              throw new Error('Illegal state') 
            }
        });
    }).then(result => {
        console.log('Transaction success!');
    }).catch(err => {
        if (event.timeStamp < Date.now()-300000) {
            // We have tried for 5 minutes and still an error, we give up
            console.error('Bad things happen: ', err)
        } else {
            throw new Error(err) // Firebase will receive this as a rejected Promise and retry
        }
    })
    

    2.创建自己的重试逻辑

    如果您只想在一段时间后重试一次,您只需返回一个Promise,它将通过setTimeout()解析等待很短的时间并再试一次 . 这看起来更多一些工作,但您可以更多地控制重试次数 . 但与Firebase重试相比,您必须处理函数的最大运行时限制 .

    else {
      return new Promise(r => window.setTimeout(tryUpdate, 100))
    

相关问题