Firebase detecting connection state & Simultaneous connections to realtimeDB - firebase

Does listening to the client's connection state using
https://firebase.google.com/docs/database/ios/offline-capabilities#section-connection-state count as a "simultaneous connection" to the realtime database
let connectedRef = FIRDatabase.database().referenceWithPath(".info/connected")
connectedRef.observeEventType(.Value, withBlock: { snapshot in
if let connected = snapshot.value as? Bool where connected {
print("Connected")
} else {
print("Not connected")
}
})
And lastly, reading the documentation I'm confused as to whether this observer pings the RealTimeDB at all or if its a client side check on its connectivity status. This confusion comes from the word 'client' in this particular docs sentence "Firebase Realtime Database clients provide a special location at /.info/connected which is updated every time the client's connection state changes." Thanks

Any client that is connected to the Firebase servers counts as a connection. If you're listening to /.info/connected you are asking to stay connected to the Firebase servers, so it indeed counts as a connection.
If you want to be certain about such a thing, you can easily:
attach a listener in a little client-side browser script (e.g. jsfiddle/jsbin)
open that script in multiple browsers
check the Database > Usage > Connections chart in your Firebase Console

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

Firebase: First write is slow

Currently developing a hybrid mobile app using ionic. When the app starts up, and a user writes to the Realtime Database for the first time, it's always delayed by around 10 or more seconds. But any subsequent writes are almost instantaneous (less than 1 second).
My calculation of delay is based on watching the database in the Firebase console.
Is this a known issue, or maybe I am doing something wrong. Please share your views.
EDIT:
The write is happening via Firebase Cloud Function.
This is the call to the Firebase Cloud function
this.http.post(url+"/favouritesAndNotes", obj, this.httpOptions)
.subscribe((data) => {
console.log(data);
},(error)=>{
console.log(error);
});
This is the actual function
app.post('/favouritesAndNotes', (request, response) => {
var db = admin.database().ref("users/" + request.body.uid);
var favourites = request.body.favourites;
var notes = request.body.notes;
if(favourites!==undefined){
db.child("favourites/").set(favourites);
}
if(notes!==undefined){
db.child("notes/").set(notes);
}
console.log("Write successfull");
response.status(200).end();
});
The first time you interact with the Firebase Database in a client instance, the client/SDK has to do quite some things:
If you're using authentication, it needs to check if the token that it has is still valid, and if not refresh it.
It needs to find the server that the database is currently hosted on.
It needs to establish a web socket connection.
Each of these may take multiple round trips, so even if you're a few hundred ms from the servers, it adds up.
Subsequent operations from the same client don't have to perform these steps, so are going to be much faster.
If you want to see what's actually happening, I recommend checking the Network tab of your browser. For the realtime database specifically, I recommend checking the WS/Web Socket panel of the Network tab, where you can see the actual data frames.

Hitting 100 active connections limit in test env with only two users

I have a single web client and a few Lambda functions which use the Admin SDK. I've noticed recently that I've bumped into the 100 simultaneous connection limit but I really shouldn't be anywhere near that limit. Also it would appear that the connections established by my Lamba functions are not dropping off even after the function has completed.
Any idea on:
how I can prevent this run-up on connections from happening?
how I can release connections established by past Lambda scripts?
how can I monitor which processes/threads/stacks are holding connections?
Note: this is a testing environment I'm working out of so I'd prefer to keep this in the free tier and my requirements should definitely not be running into the 100 active limit. I am on a paid plan in prod.
I attempt to avoid calling initializeApp more than once by using the following connection code. In the example I'm talking about I only have a single database as a backend and so the default "name" of DEFAULT is used each time.
const runningApps = new Set(firebase.apps.map(i => i.name));
this.app = runningApps.has(name)
? firebase.app()
: firebase.initializeApp({
credential: firebase.credential.cert(serviceAccount),
databaseURL: config.databaseUrl
});
I'm now trying to explicitly close connections with goOffline but that leads to another issue where on the second connection -- aka, where the DEFAULT application is already setup and it just reuses the connection already established I get the following logging:
# Generated as result of `goOnline`
Connecting to Firebase: [https://xyz.firebaseio.com]
appears to be already connected
# Listening on ".info/connected" comes back as true, resulting in:
AbstractedAdmin: connected to [DEFAULT]
# but then I get this error
NotAllowed: You must first connect before using the database() API at Object._getFirebaseType
The fact that you have unexpected incoming connections to the database, makes it seem like the stale instances keep an open connection.
Best I can think off is to call goOffline() in your function before it completes to explicitly disconnect. That would probably also mean you have to call goOnline at the start of the function, since it might be running on an instance that previously went offline. Both goOnline and goOffline are synchronous calls afaik, but there's definitely going to be some time between going online and the data becoming available in your app.
If Lambda has a way for you to detect life-cycle events of its instances, that would be the preferred place to call goOffline and goOnline.
admin.initializeApp should only get called once in your script/node app.
The Firebase SDK's talks HTTP2 to the Firebase cloud system, so I'm not sure why you would encounter max connection issues as unique sockets are not stood up per call.
One thing to look out for is that calls to 3rd part API's (such as sendgrid) are not supported on the free tier.

Firebase onDisconnect when turning WIFI off

I noticed when I set up an onDisconnect(), hit my application on a different computer, and turn the WIFI off, my db is not updated; however, it is updated when I turn the WIFI back on. This worries me because I am building an application with expected mobile users and I want to gracefully handle temporary connection drops.
On the otherhand, /.info/connected knows about the disconnection and connection immediately.
Can anyone explain why this is happening and if there is a way to prevent the disconnect from happening once connection is reestablished?
Updated code:
var connectedRef, userRef;
connectedRef = new Firebase('https://{fb}/.info/connected');
userRef = new Firebase('https://{fb}/users/myUser');
connectedRef.on('value', function (snap) {
if (snap.val()) {
userRef.update({ online: true });
userRef.onDisconnect().update({ online: false }, function () {
console.log('Turn the Wi-Fi off after seeing this log.');
});
}
});
Result: The db does not set online to false when I turn the Wi-Fi off, unless I wait about 1 minute. The db does set online to false when I turn the Wi-Fi back on.
Turning off your wifi does not close the sockets in an efficient manner. Thus, the server has to wait for the socket to time out before it can fire onDisconnect. Since this is an entirely server-side process, the only possible outcomes are:
1) The user isn't allowed to perform the onDisconnect op (indicated in the callback immediately upon establishing the onDisconnect)
2) The event will fire when the socket times out or disconnects (the length of time is completely up to the browser/server negotiation (1 minute is not unreasonable)
3) Some data changes in Firebase between the time of establishing onDisconnect and the event firing that makes it invalid (the security rules won't allow it because the op is no longer valid)
To see your onDisconnect() fire a bit faster, try using goOffline(), which I believe will properly close the socket connections.

Resources