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

时间:2018-02-19 01:03:38

标签: javascript firebase google-cloud-functions google-cloud-firestore

问题

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

  1. Document.state设置为stage1
  2. Document.state已更新为stage2
  3. Document.state已更新为stage3
  4. 触发云功能并读取stage3
  5. 触发云功能并读取stage2
  6. 在Cloud Functions文档中,它讨论了在失败时重试事务的能力。但是,此选项在GCP控制台的云功能部分中显示为灰色(未在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 :(得分:1)

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

  

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

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

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

答案 1 :(得分:0)

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

1。使用Google Cloud RETRY标志

部署功能时,您可以简单地启用重试功能,如果该功能抛出任何错误(或返回被拒绝的Promise),这将导致google-cloud环境自动调用您的功能,听起来不错,直到您意识到这可能会产生!大笔费用!,因为如果您的函数中存在错误,每次都会引发错误,则该函数将被调用数千次,直到最终重试限制一两天后就超过了。

您的函数可能如下所示:

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))