假设我已经实现了两个触发器,用于侦听实时数据库中已创建和已删除的用户,以跟踪用户数量:
import * as functions from "firebase-functions"
import * as admin from "firebase-admin"
admin.initializeApp()
const db = admin.database()
const userRef = functions.runWith({failurePolicy: true}).database.ref("users/{userId}")
export const onUserCreate = userRef.onCreate(() =>
db.ref("nUsers").set(admin.database.ServerValue.increment(1)))
export const onUserDelete = userRef.onDelete(() =>
db.ref("nUsers").set(admin.database.ServerValue.increment(-1)))
我的理解是,由于这些函数保证只触发一次,因此启用failurePolicy
后,即使事件发生的顺序不一致,也会导致最终一致的计数。
但是,如果我想将我的应用升级到第二代云功能,该怎么办?如果先部署新功能,则存在用户被计算两次的风险。如果先删除旧功能,则存在根本不计算用户的风险。有没有一种方法可以删除一个函数并添加另一个函数作为单个原子操作?
我可以想到另外两个解决方案:
1.使计数操作幂等。我只是想不出一种方法来使这个特定的操作独立,因为RTDB的事务支持有限。
1.接受计数将是错误的,并在完成到第2代的迁移后运行脚本来更正计数。如果用户经常被添加或删除,这可能很难。
有更好的解决方案吗?
1条答案
按热度按时间nnt7mjpx1#
完成这个迁移之后,我将尝试提供实际的答案。
我的问题有点误导,因为它假设Google Cloud有责任提供这种原子操作。没有。这个假设是基于像this这样的官方样本,它使用相同的计数器实现。
这是一种误导,因为如果您需要一致的计数,这实际上不是一个好的实现。有很多方法可以多次调用函数,包括切换到第二代,重命名函数或将其移动到另一个区域。相反,你需要做的是找到一种方法来确保自己的幂等性。This blog post是一个很好的灵感来源。请注意,使用上面描述的事件ID是不起作用的,因为第一代和第二代云函数之间是不同的。
在我的例子中,我能够实现一个租赁系统,其中唯一的令牌是用户ID和创建或删除的时间戳的散列。第1代和第2代之间的时间戳似乎一致。根据您的数据结构,可能有更好的方法来解决您的问题。