我有一个由Firestore数据库写入触发的云功能。它执行异步操作(从某些第三方API获取数据)可能需要很长时间,可能不会。完成后,它会将结果写入“搜索结果”字段。
可能存在竞争条件,较新的触发器的结果会被较旧的操作覆盖,以后再完成此操作。如何在Firebase云功能和Firestore环境中解决此问题?
答案 0 :(得分:12)
一般来说,这里有两种方法:
这通常是最具规模和架构简单的。当您对同一输入执行相同的幂等操作时,它具有相同的结果。这意味着操作多次执行并不重要,因为结果是相同的。
这方面的一个很好的例子是Firestore documentation on arrays and sets。想象一下,您正在使用类别标记博客文章。一个天真的模型是:
{
title: "My great post",
categories: [
"technology",
"opinion",
"cats"
]
}
但现在想象两个用户几乎在同一时间标记同一个帖子。你最终可能会
{
title: "My great post",
categories: [
"technology",
"opinion",
"cats",
"cats"
]
}
这显然不是你想要的。但由于数据结构允许,可能会发生这种情况。这里理想的解决方案是使用一种数据结构,使其变得不可能:一种数据结构,其中添加cat
是幂等操作。在数学术语中,这将是一个集合,在Firestore中,您将其模型化为:
{
title: "My great post",
categories: {
"technology": true,
"opinion": true,
"cats": true
}
}
现在,在此结构中,将cats
设置为true
的频率并不重要,结果将始终相同。
有时,使您的操作具有幂等性是不可能的(或不可行的)。在这种情况下,您还可以考虑使用比较和设置策略。
例如,假设第三方API以某种方式更改数据,并且如果数据库中的原始数据未经修改,您只想将结果写回数据库。在这种情况下,您需要在函数中执行以下步骤:
这种类型的比较和设置操作实际上是Firebase的实时数据库实现事务的方式,“第三方API”是您的应用程序事务处理程序。
您可能会看到第二种方法比使用幂等操作的方法更复杂。所以在可能的情况下,我总是建议这种做法。
答案 1 :(得分:1)
Firebase云函数提供了transact()函数,该函数仅可用于将一些数据自动保存到数据库中。
答案 2 :(得分:0)
尽管不是OP关于等待第三方答复的问题的直接答案,但对于那些通过Google搜索来寻找通用Firestore竞争条件解决方案的人,Firestore支持事务和批量写入:
Cloud Firestore支持用于读取和写入数据的原子操作。在一组原子操作中,要么所有操作都成功,要么不应用任何操作。 Cloud Firestore中有两种类型的原子操作:
交易:交易是对一个或多个文档的一组读写操作。
批量写入:批量写入是对一个或多个文档的一组写操作。
有关更多详细信息,请参见:https://firebase.google.com/docs/firestore/manage-data/transactions