如何使用firebase云功能避免可能的竞争条件?

时间:2018-03-15 01:58:48

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

我有一个由Firestore数据库写入触发的云功能。它执行异步操作(从某些第三方API获取数据)可能需要很长时间,可能不会。完成后,它会将结果写入“搜索结果”字段。

可能存在竞争条件,较新的触发器的结果会被较旧的操作覆盖,以后再完成此操作。如何在Firebase云功能和Firestore环境中解决此问题?

3 个答案:

答案 0 :(得分:12)

一般来说,这里有两种方法:

  1. 确保您的操作是幂等的
  2. 确保您的操作检测到有冲突的更新并重试
  3. 确保您的操作是幂等的

    这通常是最具规模和架构简单的。当您对同一输入执行相同的幂等操作时,它具有相同的结果。这意味着操作多次执行并不重要,因为结果是相同的。

    这方面的一个很好的例子是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以某种方式更改数据,并且如果数据库中的原始数据未经修改,您只想将结果写回数据库。在这种情况下,您需要在函数中执行以下步骤:

    1. 阅读原始数据
    2. 使用数据
    3. 调用第三方API
    4. 等待结果
    5. 开始交易
    6. 再次加载原始数据
    7. 如果数据已被修改,请返回#2
    8. 如果未修改数据,请写入第三方API的结果
    9. 这种类型的比较和设置操作实际上是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