Does firebase guarantee all events will be received, or just that state will be consistent? [duplicate] - firebase

Do event listeners guarantee that all data ever written to a path will be delivered to the client eventually?
For instance if I have a game client that pushes moves to the same path one after the other will the listening client receive all updates?
What would happen in this situation: client A pushes move 1 to game1/user1/move_data which client B is listening on; client A then immediately pushes another move updating the value at game1/user1/move_data.
Will the listening client be guaranteed to receive all moves pushed?
Currently I have a system that creates a new path per move and then I am calling single listeners on each move as each client reaches that move in it's state. It doesn't seem efficient as if the client A receives the most recent move that client B has made then client A begins listening on a path that doesn't exist yet.
The below quotes are from this link: https://firebase.google.com/docs/database/admin/retrieve-data
"The value event is used to read a static snapshot of the contents at a given database path, as they existed at the time of the read event. It is triggered once with the initial data and again every time the data changes. The event callback is passed a snapshot containing all data at that location, including child data. In the code example above, value returned all of the blog posts in your app. Everytime a new blog post is added, the callback function will return all of the posts."
The part about as they existed at the time of the read event causes me to think that if a listener is on a path then the client will receive all values ever on that path eventually.
There is also this line from the guarantees section which I am struggling to decipher:
"Value events are always triggered last and are guaranteed to contain updates from any other events which occurred before that snapshot was taken."
I am working with a language that does not have a Google based sdk and am asking this question, so I can further assess Firebases' suitability for my uses.

Firebase Realtime Database performs state synchronization. If a client is listening to data in a location, it will receive the state of that data. If there are changes in the data, it will receive the latest state of that data.
...if I have a game client that pushes moves to the same path one after the other will the listening client receive all updates?
If there are multiple updates before the Firebase server has a chance to send the state to a listener, it may skip some intermediate values. So there is no guarantee that your client will see every state change, there is just a guarantee that it will eventually see the latest state.
If you want to ensure that all clients (can) see all state changes, you should store the state changes themselves in the database.

try to this code to get update value from firebase database:-
mFirebaseInstance = FirebaseDatabase.getInstance();
mFirebaseDatabase = mFirebaseInstance.getReference();
mFirebaseDatabase.child("new_title").setValue("Realtime Database");
mFirebaseDatabase.child("new_title").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String appTitle = dataSnapshot.getValue().toString();
Log.e("Hey", appTitle);
title.setText(appTitle);
}
#Override
public void onCancelled(DatabaseError error) {
// Failed to read value
Log.e("Hey", "Failed to read app title value.", error.toException());
}
});

Related

firebase onDisconnect() is not fired when user lose connection

Hello React native community, I'm trying to use onDisconnect() in firebase but the problem is that the void isn't getting fired when the network loses its connection but it is working if I close the app or when the app crashes.
This code is working if Wi-Fi is on but it's not working at all if Wi-Fi is off..
firebase.database().ref('users/test/connected').onDisconnect().set(false)
Any ideas?
You can combine disconnect operations with connection status monitoring and server time stamps to build a user connection status system. On this system, each user stores data in a specific database location to alert the real-time database client to online. The client sets this location to true when it comes online and to time stamp when it disconnects. This timestamp indicates the last time the user was online.
Apps have a disconnect operation ahead of the user's online display, so that there is no contention if the client loses network connectivity before the two commands are sent to the server.
// since I can connect from multiple devices or browser tabs, we store each connection instance separately
// any time that connectionsRef's value is null (i.e. has no children) I am offline
var myConnectionsRef = firebase.database().ref('users/test/connections');
// stores the timestamp of my last disconnect (the last time I was seen online)
var lastOnlineRef = firebase.database().ref('users/test/lastOnline');
var connectedRef = firebase.database().ref('.info/connected');
connectedRef.on('value', function(snap) {
if (snap.val() === true) {
// We're connected (or reconnected)! Do anything here that should happen only if online (or on reconnect)
var con = myConnectionsRef.push();
// When I disconnect, remove this device
con.onDisconnect().remove();
// Add this device to my connections list
// this value could contain info about the device or a timestamp too
con.set(true);
// When I disconnect, update the last time I was seen online
lastOnlineRef.onDisconnect().set(firebase.database.ServerValue.TIMESTAMP);
}
});

Firestore Timeout [duplicate]

We are building a real-time chat app using Firestore. We need to handle a situation when Internet connection is absent. Basic message sending code looks like this
let newMsgRef = database.document(“/users/\(userId)/messages/\(docId)“)
newMsgRef.setData(payload) { err in
if let error = err {
// handle error
} else {
// handle OK
}
}
When device is connected, everything is working OK. When device is not connected, the callback is not called, and we don't get the error status.
When device goes back online, the record appears in the database and callback triggers, however this solution is not acceptable for us, because in the meantime application could have been terminated and then we will never get the callback and be able to set the status of the message as sent.
We thought that disabling offline persistence (which is on by default) would make it trigger the failure callback immediately, but unexpectedly - it does not.
We also tried to add a timeout after which the send operation would be considered failed, but there is no way to cancel message delivery when the device is back online, as Firestore uses its queue, and that causes more confusion because message is delivered on receiver’s side, while I can’t handle that on sender’s side.
If we could decrease the timeout - it could be a good solution - we would quickly get a success/failure state, but Firebase doesn’t provide such a setting.
A built-in offline cache could be another option, I could treat all writes as successful and rely on Firestore sync mechanism, but if the application was terminated during the offline, message is not delivered.
Ultimately we need a consistent feedback mechanism which would trigger a callback, or provide a way to monitor the message in the queue etc. - so we know for sure that the message has or has not been sent, and when that happened.
The completion callbacks for Firestore are only called when the data has been written (or rejected) on the server. There is no callback for when there is no network connection, as this is considered a normal condition for the Firestore SDK.
Your best option is to detect whether there is a network connection in another way, and then update your UI accordingly. Some relevant search results:
Check for internet connection with Swift
How to check for an active Internet connection on iOS or macOS?
Check for internet connection availability in Swift
As an alternatively, you can check use Firestore's built-in metadata to determine whether messages have been delivered. As shown in the documentation on events for local changes:
Retrieved documents have a metadata.hasPendingWrites property that indicates whether the document has local changes that haven't been written to the backend yet. You can use this property to determine the source of events received by your snapshot listener:
db.collection("cities").document("SF")
.addSnapshotListener { documentSnapshot, error in
guard let document = documentSnapshot else {
print("Error fetching document: \(error!)")
return
}
let source = document.metadata.hasPendingWrites ? "Local" : "Server"
print("\(source) data: \(document.data() ?? [:])")
}
With this you can also show the message correctly in the UI

How does the value event work on updates with Firebase listeners?

Do event listeners guarantee that all data ever written to a path will be delivered to the client eventually?
For instance if I have a game client that pushes moves to the same path one after the other will the listening client receive all updates?
What would happen in this situation: client A pushes move 1 to game1/user1/move_data which client B is listening on; client A then immediately pushes another move updating the value at game1/user1/move_data.
Will the listening client be guaranteed to receive all moves pushed?
Currently I have a system that creates a new path per move and then I am calling single listeners on each move as each client reaches that move in it's state. It doesn't seem efficient as if the client A receives the most recent move that client B has made then client A begins listening on a path that doesn't exist yet.
The below quotes are from this link: https://firebase.google.com/docs/database/admin/retrieve-data
"The value event is used to read a static snapshot of the contents at a given database path, as they existed at the time of the read event. It is triggered once with the initial data and again every time the data changes. The event callback is passed a snapshot containing all data at that location, including child data. In the code example above, value returned all of the blog posts in your app. Everytime a new blog post is added, the callback function will return all of the posts."
The part about as they existed at the time of the read event causes me to think that if a listener is on a path then the client will receive all values ever on that path eventually.
There is also this line from the guarantees section which I am struggling to decipher:
"Value events are always triggered last and are guaranteed to contain updates from any other events which occurred before that snapshot was taken."
I am working with a language that does not have a Google based sdk and am asking this question, so I can further assess Firebases' suitability for my uses.
Firebase Realtime Database performs state synchronization. If a client is listening to data in a location, it will receive the state of that data. If there are changes in the data, it will receive the latest state of that data.
...if I have a game client that pushes moves to the same path one after the other will the listening client receive all updates?
If there are multiple updates before the Firebase server has a chance to send the state to a listener, it may skip some intermediate values. So there is no guarantee that your client will see every state change, there is just a guarantee that it will eventually see the latest state.
If you want to ensure that all clients (can) see all state changes, you should store the state changes themselves in the database.
try to this code to get update value from firebase database:-
mFirebaseInstance = FirebaseDatabase.getInstance();
mFirebaseDatabase = mFirebaseInstance.getReference();
mFirebaseDatabase.child("new_title").setValue("Realtime Database");
mFirebaseDatabase.child("new_title").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String appTitle = dataSnapshot.getValue().toString();
Log.e("Hey", appTitle);
title.setText(appTitle);
}
#Override
public void onCancelled(DatabaseError error) {
// Failed to read value
Log.e("Hey", "Failed to read app title value.", error.toException());
}
});

Getting Firebase timestamp before pushing data

I have a chat app powered by Firebase, and I'd like to get a timestamp from Firebase before pushing any data.
Specifically, I'd like to get the time that a user pushes the send button for a voice message. I don't actually push the message to Firebase until the upload was successful (so that the audio file is guaranteed to be there when a recipient receives the message). If I were to simply use Firebase.ServerValue.TIMESTAMP, there could be an ordering issue due to different upload durations. (A very short message following a very long one, for example.)
Is there anyway to ping Firebase for a timestamp that I'm not seeing in the docs? Thank you!
If you want to separate the click, from the actual writing of the data:
var newItemRef = ref.push();
uploadAudioAndThen(audioFile, function(downloadURL) {
newItemRef.set({
url: downloadURL,
savedTimestamp: Firebase.ServerValue.TIMESTAMP
});
});
This does a few things:
it creates a reference for the item item before uploading. This reference will have a push ID based on when the upload started. Nothing is written to the database at this point, but the key of the new location is determined.
it then does the upload and "waits for it" to complete.
in the completion handler of the upload, it writes to the new location it determine in step 1.
it writes the server timestamp at this moment, which is when the upload is finished
So you now have two timestamps. One is when the upload started and is encoded into the key/push id of the new item, the other is when the upload completed and is in the savedTimestamp property.
To get the 3 most recently started uploads that have already completed:
ref.orderByKey().limitToLast(3).on(...
To get the 3 most recently finished uploads:
ref.orderByChild('savedTimestamp').limitToLast(3).on(...

signalr send group notification with delay

I have a signal r application. I have an issue of concurrent connection maxing out on iis. To avoid that i want my hub to send notification to groups created by in pack of 25 with delay of suppose 500ms. I add users to group as they connect. After count of 25 i add them to next group.Need help with how shall i send notification to each group with delay of 500ms.
I have looped through the number of groups and used
Thread.Sleep(500);
but all connected users do not receive the notification
Your question almost describes the solution - buffer the notifications fro 500ms then send an array of all of them.
You could do that by pushing the notification in a queue or list and and use a timer to send the notifications every 500ms.
A far better solution though would be to use Reactive Extensions and the Observable.Buffer(Timespan) method, thus avoiding queues and timers.
Subject<string> _subject;
.....
public void InitSubject()
{
_subject=new Subject<string>();
_subject.Buffer(Timespan.FromMilliseconds(500))
.Subscribe(notifications=>SendBatch(notifications));
}
....
public void SendBatch(IList<string> notifications)
{
//Get hold of the SignalR context and send the notifications here
}
public void QueueNotification(string notification)
{
_subject.OnNext(notification);
}
Buffer also allows you to batch a specific number of notifications, or use both a timespan and item limit to send a batch whenever one of the limits is reached.
Your code should call QueueNotification instead of sending the notification directly. Reactive Extensions also provide LINQ extensions, so you could apply filtering with the Where() method, eg to use different delays for different user groups, bypass buffering completely, or use any other combination.
You should note that since a Hub is transient, you can't put your subject inside the hub, although you can put QueueNotification in there, provided you provide a reference to the subject somewhere, eg by using Dependency injection to initialize the hub

Resources