Firebase中非常接近的事件的数据一致性 [英] Data Consistency on very close events in Firebase
问题描述
$ b
用户的正确状态(每个用户点击我准备就绪按钮之前):
父母
匹配
用户1
对手:用户2
状态:NotReady
用户2
对手:User1
state:NotReady
在两个设备上的时间差是+ 2秒,换句话说 - 一旦设备计时器将要结束在另一个之前 当用户按下我准备就绪按钮我正在更新 如果两个用户都是 userReady - 游戏开启。 问题 所以我们已经清楚,在100%的情况下,我有一个很小的时间差两个设备。 但是,例如,
状态:userReady
,并检查其他用户是否准备就绪(观察其状态
value)。
User1
点击 I准备好
按钮。所以现在 User2
得到了一个 ChildUpdate
事件,据他所知 - User2 <
$ b $ 用户计时器
最先结束(事实),所以当他的计时器将完成, User2计时器
将保持 1
秒。 现在在 User1
时间刚刚达到零,所以他被踢出房间,并发送 removeValue
User1定时器
结尾的零时间, User2
时钟显示的时间为1秒(事实),而他按下 User1
已准备好播放,比赛开始。
最终结果 -
这两名玩家都从Firebase中删除用户2离开房间
User2开始游戏(他认为他是对手)
我该如何解决这种情况?已经尝试只在UpdateChild状态完成时调用 startGame
函数,但它仍然进入,可能是因为updateChild和removeValue的顺序?
有什么建议吗?BIG非常感谢Firebase团队一直以来的努力!!!
U没有意义ser 1会接受,然后无论如何到期。用户2应该是一个过期,如果时间限制已经达到,他还没有接受。
为了防止这种情况,你正在寻找交易。当你过期的用户,使用一个事务来这样做,所以没有数据冲突。
var ref =新的Firebase(https://< YOUR-FIREBASE-APP> .firebaseio.com /);
$ b $ ref.child('Parent / Matches')。child(user1).transaction(function(currentValue){
if(currentValue&& currentValue.state ==='NotReady '){
return null; //删除用户
}
else {
return undefined; //中止事务;状态在我们试图删除的时候改变了
}
});
可能在swift中正确:
<$ p $
$ b var ref = Firebase(url:https://< YOUR-FIREBASE-APP> .firebaseio.com / Parent / Matches /< user id>) $ b upvotesRef.runTransactionBlock({
(currentData:FMutableData!)in
if currentData&&; currentData.value [state]!=NotReady{
return FTransactionResult.successWithValue (NSNull)
}
return FTransactionResult.abort();
});此外,您可以通过不删除/终止记录,直到两者都可以简化的事情,减少混乱的机会用户已经达到了他们的接受时间限制,然后在一次交易中同时进行。
I am building an iOS game. Each game room is constructed from two users. After two users get matched, I'm displaying a "waiting for respond" timer on both devices: they need to click am "I'm Ready" button within 8 second or both of them will get kicked from the room + deleted from Firebase.
The correct state of the users (before each of them clicked on the "I'm Ready Button"):
Parent
Matches
User 1
opponent : User2
state : "NotReady"
User 2
opponent : User1
state : "NotReady"
Critical note - The timer on both devices time difference is +-2 seconds, In other words - once device timer is going to end before the other one
When a user press the "I'm Ready" button i'm updating the state : "userReady"
,and check if the other user is ready too (observing its state
value).
If both users are userReady - game on.
PROBLEM
so we have already cleared that in 100% of the cases i have a small time difference between both devices. BUT, if for instance ,
User1
clicked I'm Ready
button. So now User2
got an ChildUpdate
event, and as far as he knows - User2
is completely ready to play.
User1 timer
is ending first(fact), so when his timer will finish, User2 timer
will remain 1
seconds. NOW, on User1
time just reached zero, so he get kicked out of the room, and send a removeValue
event on each of the Users nodes. While this is happening, at this very small "gap",(between the zero time of User1 timer
ending,User2
clock show's 1 sec(fact) - and he press the ready button. than he thinks that User1
is ready to play, and he as well - than the game starts playing.
Final Results -
Both players got deleted from Firebase
User1 is out of the room
User2 starts the game(and he think he is an opponent)
How can i solve this end-case scenario?, I have already tried calling startGame
function only when the "UpdateChild state" is done, but it still gets in, maybe because the order for updateChild,and removeValue"?
Any suggestions? And BIG thank you Firebase team for reaching how all the time!!!
It doesn't make sense that User 1 would accept and then expire anyway. User 2 should be the one expiring if the time limit is reached and he hasn't accepted yet.
To prevent this, you're looking for transactions. When you would "expire" a user, use a transaction to do so, so that there are no data conflicts.
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
}
});
Possibly correct in swift:
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();
});
Furthermore, you could simplify things and reduce the opportunity for chaos by not deleting/expiring the records until both users have reached their accept time limit, and then doing both at once in a transaction.
这篇关于Firebase中非常接近的事件的数据一致性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!