Firebase 中非常接近的事件的数据一致性

Posted

技术标签:

【中文标题】Firebase 中非常接近的事件的数据一致性【英文标题】:Data Consistency on very close events in Firebase 【发布时间】:2016-01-13 23:17:15 【问题描述】:

我正在开发一款 ios 游戏。每个游戏室由两个用户构成。两个用户匹配后,我会在两台设备上显示“等待响应”计时器:他们需要在 8 秒内单击“我准备好了”按钮,否则他们都会被踢出房间 + 从 Firebase 中删除.

用户的正确状态(在他们每个人点击“我准备好了”按钮之前):

Parent
      Matches
             User 1
                   opponent : User2
                   state : "NotReady"
             User 2
                   opponent : User1
                   state : "NotReady"

重要说明 - 两台设备上的计时器时间差为 +-2 秒,换句话说 - 一次设备计时器将在另一个之前结束

当用户按下“我准备好了”按钮时,我正在更新state : "userReady",并检查其他用户是否也准备好了(观察其state 值)。

如果两个用户都userReady - 开始游戏。

问题

所以我们已经清楚,在 100% 的情况下,两个设备之间的时间差很小。 但是,例如,

User1 点击了I'm Ready 按钮。所以现在User2 得到了一个ChildUpdate 事件,据他所知-User2 已经完全准备好了。

User1 timer 首先结束(事实),所以当他的计时器结束时,User2 timer 将保持1 秒。 现在, User1 时间刚刚达到零,因此他被踢出房间,并在每个用户节点上发送 removeValue 事件。当这种情况发生时,在这个非常小的“间隙”,(在User1 timer 结束的零时间,User2 时钟显示的 1 秒(事实)之间 - 他按下准备按钮。比他认为User1 已经准备好开始游戏了,而且他也准备好了——然后游戏开始了。

最终结果 -

两名玩家都已从 Firebase 中删除

用户 1 不在房间内

User2 开始游戏(他认为自己是对手)

我该如何解决这种最终情况?,我已经尝试仅在“UpdateChild 状态”完成时调用startGame 函数,但它仍然进入,可能是因为订单对于 updateChild 和 removeValue"?

有什么建议吗?非常感谢 Firebase 团队一直以来的努力!!!

【问题讨论】:

对于其他寻找数据一致性文档的人,请参阅event guarantees here 嘿@Kato。谢谢你的回复。已经读过这个(几次)呵呵,还没有想出一个解决方案.. 这与您的问题无关,但标题(数据一致性)是一个常见的话题,因此希望对其他人有所帮助。 @Kato ,知道了 - 谢谢。 对于下一个问题:请包含您已经尝试过的代码。如果你展示你已经做过的事情,就更容易回应(和推理)你的问题。 【参考方案1】:

用户 1 接受然后过期是没有意义的。用户 2 应该是过期的,如果达到时间限制并且他还没有接受。

为了防止这种情况,您正在寻找transactions。当您要让用户“过期”时,请使用事务来执行此操作,这样就不会发生数据冲突。

var ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com/");

ref.child('Parent/Matches').child(user1).transaction(function(currentValue) 
    if( currentValue && currentValue.state === 'NotReady' ) 
       return null; // delete the user
    
    else 
       return undefined; // abort the transaction; status changed while we were attempting to remove it
    
);

可能很快就正确了:

var ref = Firebase(url: "https://<YOUR-FIREBASE-APP>.firebaseio.com/Parent/Matches/<user id>")

upvotesRef.runTransactionBlock(
    (currentData:FMutableData!) in
    if currentData && currentData.value["state"] != "NotReady" 
        return FTransactionResult.successWithValue(NSNull)
    
    return FTransactionResult.abort();
);

此外,您可以简化事情并减少混乱的机会,方法是在两个用户都达到其接受时间限制之前不删除/过期记录,然后在事务中同时执行这两项操作。

【讨论】:

在我深入阅读之前快速评论一下——我有这种架构——大厅类别和比赛类别。如果用户 1 单击准备好,但时间过去了。我正在删除 match cat' 处的节点,并立即在 Lobby 创建新节点并搜索对手(就像澄清一样)。我会深入阅读答案并告诉您是否进一步 好的,首先谢谢您!其次 - 关于这个的两个任务。是否可以将其翻译为 ios(swift 更好,但目标 c 也可以)?如果没有,没有苛刻的嘿嘿。第二。 “用户 1 接受然后过期是没有意义的”。但是如果时间到了 0(我正在显示计时器,所以用户将触发我准备好了按钮),它缺乏设计和用户体验来让用户留在房间里(即使时间设置为零) .我指望 Firebase 服务器将差异 top 保持 2 秒,所以即使 6 秒按下我准备好按钮听起来也很公平。我只是想避免小的差距 iOS 事务是covered here。我会尝试将此添加到我的答案中。 谢谢加藤 - 你的帮助是无价的..!你能分解交易状态吗? ' if( currentValue && currentValue.state === 'NotReady' ) ' ,我不完全理解 if 语句。我正在使用事务来更新用户的状态?还是删除它?很抱歉造成混乱 谢谢加藤!我会让你知道实现是如何进行的

以上是关于Firebase 中非常接近的事件的数据一致性的主要内容,如果未能解决你的问题,请参考以下文章

从 Azure SQL 中非常嵌套的 JSON 中提取数据

R中非常大的矩阵计算有效

python中非常好用的数据库管理工具

R中非常大的数据集处理和机器学习的推荐包[关闭]

Firebase + BigQuery - 唯一标识设备

MySQL 5.5 中的长时间运行查询在 5.6 中非常快