我有一个云功能,可根据文档state
字段中的更改更新Cloud Firestore文档。这些更新必须以特定顺序发生。当快速连续进行两次更改时,无法保证云功能将以正确的顺序运行。有没有办法让Cloud Firestore事务重试,直到成功或超时?
Document.state
设置为stage1
Document.state
已更新为stage2
Document.state
已更新为stage3
stage3
stage2
在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);
});
答案 0 :(得分:1)
默认情况下,Firestore事务会自行重试。 The documentation for transactions州:
事务由任意数量的get()操作组成 任意数量的写操作,如set(),update()或delete()。 在并发编辑的情况下,Cloud Firestore运行整个 再次交易。例如,如果事务读取文档和 另一个客户端修改任何这些文档,Cloud Firestore 重试事务。此功能确保事务 运行最新且一致的数据。
此重试采用事务处理函数的重复调用形式(传递给runTransaction的函数)。
云功能重试机制不同。它重试不完全成功的功能。有关其工作原理的详细信息,请参阅here。它与Firestore事务无关。这些重试的语义与所使用的触发器类型无关。
答案 1 :(得分:0)
针对您的问题,基本上有两种选择:
部署功能时,您可以简单地启用重试功能,如果该功能抛出任何错误(或返回被拒绝的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
}
})
如果您只想在一段时间后进行一次重试,则只需返回一个Promise,即可通过setTimeout()进行解析,以等待一小段时间然后重试。这看起来需要做更多的工作,但是您可以对重试次数进行更多控制。但是与Firebase重试相反,您将不得不处理函数的最大运行时限制。
else {
return new Promise(r => window.setTimeout(tryUpdate, 100))