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

我正在构建一个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时间刚刚达到零,所以他被踢出了房间,并在每个Users节点上发送了removeValue事件。 当发生这种情况时,在这个非常小的“间隙”,(在User1 timer结束的零时间, User2时钟显示1秒(事实)之间)和他按下就绪按钮,而不是他认为User1已准备好播放,并且他也是 – 比赛开始比赛。

最终结果 –

两名玩家都从Firebase中删除了

User1不在房间里

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

我该如何解决这种最终案例? ,我已经尝试仅在“UpdateChild状态”完成时调用startGame函数,但它仍然进入,可能是因为updateChild和removeValue的顺序“?

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

用户1无论如何都会接受然后过期是没有意义的。 如果达到时间限制且用户尚未接受,则用户2应该是到期的。

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

 var ref = new Firebase("https://.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 } }); 

可能在swift中正确:

 var ref = Firebase(url: "https://.firebaseio.com/Parent/Matches/") upvotesRef.runTransactionBlock({ (currentData:FMutableData!) in if currentData && currentData.value["state"] != "NotReady" { return FTransactionResult.successWithValue(NSNull) } return FTransactionResult.abort(); }); 

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