I have been scouring the firestore docs and the angularfire2 docs looking for any information regarding how firebase/angularfire handles it's write promises when my progressive web app is offline.
The problem is that all of my promises returned from the batch writes are not being resolved (or rejected), so should I be assuming that all promises made offline will be resolved? If so, am I correct in saying I should rather be handling redirects and success messages before the promise is resolved?
Besides my unresolved firebase promises, the offline mode seems to work well. It correctly changes data in various places throughout many collections and documents, and the changes are displayed correctly in the web app.
Once returning to online mode, the relevant changes are made to the database and my pending promises all seem to get resolved at once.
Is this expected behaviour? And if it is what would the correct way about handling success/error messages and redirects be (if they were previously handled in the promise then and catch)
Firestore promises (and completion handlers on other platforms) indeed resolve/reject when the write operation has been committed/rejected on the server. So what you see is indeed the expected behavior.
Related
I'm currently using Axon Framework alongside Axon Server for my event-based microservices application. Recently I've encountered the need to wait for saga to fully complete and return its execution result (success or error) to the client, and I've solved it by creating a subscription query before dispatching a command that triggers the saga that locks then waits for updates that are being dispatched from saga and returns the result to client.
Now, that worked a treat in reporting on saga completion status to client, but now I've stumbled upon another seemingly connected problem. Every time a client queries our system's API, we perform an existence check of the client's account - and we do that by dispatching the corresponding query before we perform any business logic. After I've introduced the subscription query, when the client receives the response about saga completion status they immediately send a query to us for an updated list of certain entities, but the query that checks for account's existence fails with org.axonframework.queryhandling.NoHandlerForQueryException: No handler for query: ... which is returned by Axon Server upon sending despite the fact that there definitely is a handler registered for it and it's just handled exactly the same command during the previous request by client. This started to happen after I've added the inner subscription query mechanism to the equation.
This error disappears if we repeat the exact same query a bit later or put a delay of a couple hundred milliseconds between the calls, but that's certainly not a solution - what if our clients start to send loads of requests simultaneously, what will happen to account checking query? Are we unable to process some type of query when the subscription is not closed? I close the subscription on doFinally of Mono returned from SubscriptionQueryResult, but is there a chance that it doesn't actually get closed in Axon Server when the next query arrives? Or, which I think is closer to the truth, I need to somehow tune the query handling capacity of Axon Server? The documentation is rather concise on this topic, IMHO, especially concerning queries, not events/commands.
From the sound of it, you've hit a bug, #Ivan. I assume you are on Axon Server SE? It wouldn't hurt to construct an issue there describing the problem at hand.
As far as I know, the Subscription Query does not impact the capability to send other queries. So, it is not like a Query Handler suddenly unregisters once a subscription query is active. Or, it definitely shouldn't.
By the way, would you be able to share the versions of Axon Framework and Axon Server you are using? That helps with deducing the issue but also helps others that might hit the same problem.
This is rather just a straight forward question.
Does Firebase Realtime Database guarantees to follow 'First come first serve' rule when handling requests?
But when there is a write-request, and then instantaneously followed by a read-request, is the read-request will fetch updated data?
When there is a write-read-write sequence of requests, does for sure read-request fetch the data written by first write?
Suppose there is a write-request, which was unable to perform (due to some connection issues). As firebase can work even in offline, that change will be saved locally. Now from somewhere else another write-request was made and it completed successfully. After this, if the first device comes online, does it modify the values(since it arrived latest)? or not(since it was initiated prior to the latest changes)?
There are a lot of questions in your post, and many of them depend on how you implement the functionality. So it's not nearly as straightforward as you may think.
The best I can do is explain a bit of how the database works in the scenarios you mention. If you run into more questions from there, I recommend implementing the use-case and posting back with an MCVE for each specific question.
Writes from a single client are handled in the order in which that client makes them.
But writes from different clients are handled with a last-write-wins logic. If your use-case requires something else, include a client-side timestamp in the write and use security rules to reject writes that are older than the current state.
Firebase synchronizes state to the listeners, and not necessarily all (write) events that led to this state. So it is possible (and fairly common) for listeners to not get all state changes that happened, for example if multiple changes to the same state happened while they were offline.
A read of data on a client that this client itself has changed, will always see the state including its own changes.
My current application developed in Unity uses Firebase Realtime Database with database persistence enabled. This works great for offline use of the application (such as in areas of no signal).
However, if a new user runs the application for the first time without an internet connection - the application freezes. I am guessing, it's because it needs to pull down the database for the first time in order for persistence to work.
I am aware of threads such as: 'Detect if Firebase connection is lost/regained' that talk about handling database disconnection from Firebase.
However, is there anyway I can check to see if it is the users first time using the application (eg via presence of the persistent database?). I can then inform them they must go online for 'first time setup'?
In addition to #frank-van-puffelen's answer, I do not believe that Firebase RTDB should itself cause your game to lock up until a network connection occurs. If your game is playable on first launch without a network connect (ie: your logic itself doesn't require some initial state from the network), you may want to check the following issues:
Make sure you can handle null. If your game logic is in a Coroutine, Unity may decide to silently stop it rather than fully failing out.
If you're interacting with the database via Transactions, generally assume that it will run twice (once against your local cache then again when the cache is synced with the server if the value is different). This means that the first time you perform a change via a transaction, you'll likely have a null previous state.
If you can, prefer to listen to ValueChanged over GetValueAsync. You'll always get this callback on your main Unity thread, you'll always get the callback once on registration with the data in your local cache, and the data will be periodically updated as the server updates. Further, if you see #frank-van-puffelen answer elsewhere, if you're using GetValueAsync you may not get the data you expect (including a null if the user is offline). If your game is frozen because it's waiting on a ContinueWithOnMainThread (always prefer this to ContinueWith in Unity unless you have a reason not to) or an await statement, this could ValueChanged may work around this as well (I don't think this should be the case).
Double check your object lifetimes. There are a ton of reasons that an application may freeze, but when dealing with asynchronous logic definitely make sure you're aware of the differences between Unity's GameObject lifecycle and C#'s typical object lifecycle (see this post and my own on interacting with asynchronous logic with Unity and Firebase). If an objects OnDestroy is invoked before await, ContinueWith[OnMainThread], or ValueChanged is invoked, you're in danger of running into null references in your own code. This can happen if a scene changes, the frame after Destroy is called, or immediately following a DestroyImmediate.
Finally, many Firebase functions have an Async and synchronous variant (ex: CheckDependencies and CheckDependenciesAsync). I don't think there are any to call out for Realtime Database proper, but if you use the non async variant of a function (or if you spinlock on the task completing, including forgetting to yield in a coroutine), the game will definitely freeze for a bit. Remember that any cloud product is i/o bound by nature, and will typically run slower than your game's update loop (although Firebase does its best to be as fast as possible).
I hope this helps!
--Patrick
There is nothing in the Firebase Database API to detect whether its offline cache was populated.
But you can detect when you make a connection to the database, for example by listening to the .info/connected node. And then when that first is set to true, you can set a local flag in the local storage, for example in PlayerPrefs.
With this code in place, you can then detect if the flag is set in the PlayerPrefs, and if not, show a message to the user that they need to have a network connection for you to download the initial data.
If a cloud function times out, I would like to have that as an error in the logs, so I can track the health of the functions, and if necessary take steps to improve speeds.
Is it possible to make that log to show as an error?
Also, is there a way to catch such timeout? I have a function that if an exception is thrown, saves something to the realtime-database. Is it possible to catch this error as well?
Firebase Response:
Thank you for reaching out, and for providing your feedback to us. I'm
Kyle from Firebase Support and I'll be happy to handle this case
regarding Cloud Functions with Firebase.
I understood that Cloud Function timeouts should be regarded as
"errors" instead of "info" logs. I also agree that having another
trigger that responds to timeout events like functions.onTimeout()
would be very cool to be included in the future version of Cloud
Functions.
For this, please note that I've cascaded your feedback (and use-case)
about treating function timeouts as an error log, and not as an info
log. I've also filed an internal feature request ticket for your
suggestion of having functions.onTimeout() trigger. This will be
processed to be discussed internally within the team, but I can't
provide any ETAs or specific timeline as to when this requested
feature will be implemented. In the meantime, you may keep an eye on
our release notes and Firebase blog for upcoming features and bug
fixes that Firebase offers to our valued developers.
I figured out a workaround to accomplish this.
I used Google Cloud Functions tools to monitor timeouts of my Firebase Cloud Functions.
I set up a custom alert whenever "finished with status: 'timeout'" is logged by any of my functions:
I went over to https://console.cloud.google.com/logs/viewer and created a custom advanced search:
resource.type="cloud_function"
"finished with status: 'timeout'"
Then, I used the "Create Metric" feature to track instances of that log.
Then under https://console.cloud.google.com/logs/metrics, I found my user-defined metric and created a custom alert for it.
When a function times out, you will see a line in the logs for that. Are you suggesting that you don't see it?
You can't catch timeouts. This is a hard restriction of Cloud Functions that prevents your code from running away outside of its control.
It seems restricting that I can only get a snapshot from my database to read data from on data change. Is there something I'm missing about OnDataChange?
What if I want to populate a page with data read dynamically from my database, yet no data is changing in the database? I still need to call OnDataChange?
Firebase's onDataChange fires immediately with a snapshot of the current value in the database and subsequently whenever the data changes.
In fact, the Firebase documentation says this:
This method is triggered once when the listener is attached and again every time the data, including children, changes.
The simple answer is you can't block the User Interface with a long running task such as a database query or network request. At best the user will have an unresponsive application at worst an "application not responding exception" (ANR)crash will happen. That's why it is designed with a listener pattern. I assume this is android we are talking about, however the answer is valid for other platforms. If you are doing this on a background thread yes you could do what you are saying, in theory. I don't think firebase is designed that way.