How to perform transactions in firestore when user is offline? - google-cloud-firestore

I'm creating a multi page application where i need to create and store transactions even when the users are offline. How do i achieve this using firestore ? Also i need some idea on how to persist the data received from the firestore locally.

You can't run transactions when offline,but if you think that your data is not changed while you are offline you can get the data from cache and update it it there using dbRef.addSnapshotListener(MetadataChanges.INCLUDE) and dbRef.update()

How to perform transactions in Firestore when the user is offline?
You cannot! Transactions are not supported for offline use, they can't be cached or saved for later. This is because a transaction absolutely requires round trip communications with the server in order to ensure that the code inside the transaction completes successfully. So you can use transaction only while online because the transactions are network dependent.
Also I need some idea on how to persist the data received from the Firestore locally.
According to the official documentation of Cloud Firestore regarding offline persistence:
For Android and iOS, offline persistence is enabled by default. To disable persistence, set the PersistenceEnabled option to false.
For the web, offline persistence is disabled by default. To enable persistence, call the enablePersistence method. Cloud Firestore's cache isn't automatically cleared between sessions. Consequently, if your web app handles sensitive information, make sure to ask the user if they're on a trusted device before enabling persistence.
Important: For the web, offline persistence is an experimental feature that is supported only by Chrome, Safari, and Firefox web browsers. Also, if a user opens multiple browser tabs that point to the same Cloud Firestore database, and offline persistence is enabled, Cloud Firestore will work correctly only in the first tab.
Edit:
The Firestore SDK for Android has a local cache that's enabled by default. So all read operations will come from the cache when there is no connectivity. So Firestore provides this feature to handle offline data. This means that if the user tries to add/delete documents while offline, every operation is added to a queue. Once the user regains the connection, every change that is made while offline will be updated on Firebase servers. In other words, all queries will be committed on the server.
Please also note that when you are offline, pending writes that have not yet been synced to the server are held in a queue. If you do too many write operations without going online to sync them, that queue will grow fast and it will not slow down only the write operations it will also slow down your read operations. So I suggest using this database for its online capabilities.

Related

Firestore SDK - Where does onSnapshot event listener/pending writes store data?

As per the answer in the link below:
Does Firebase Firestore keep a local copy of snapshot
The Firestore SDK keeps a local copy of:
All data that you have an active listener for.
All pending writes.
In addition, if offline persistence is enabled,
it also keeps a local copy of data that
your code has recently read.
Does this mean that even if offline persistence is disabled on the web, onSnapshot event listeners and pending writes will still be stored locally to cache regardless?
I'm worried about sensitive data on shared computers for these listeners and pending writes that's stored locally (if they did not successfully write to the server, i.e. went offline in the process, etc.). Can malicious users access this data somehow? Is this a flaw of firestore for web apps?
If offline persistence is disabled, only pending writes are stored in the local cache.
You should assume that all data that is entered on the local device can be intercepted by a malicious actor who gets access to that device. If that is not acceptable for your use-case, consider not using a Firebase SDK for Firestore but using the REST API or gRPC API directly.

General question: Firestore offline persistence and synchronization

I could not find detailed information in the documentation. I have several questions regarding the offline persistence of firestore.
I understood that firestore locally caches everything and syncs back once online. My questions:
If I attach an onCompleteListener to my setDocument method it only fires when the device is online and has network access. But with offline persistence enabled, how can I detect that data has successfully been written to the cache (Is it always successful?!) - I see data is immediatly there without any listener ever triggering.
What if I wrote data to the cache while the device is offline then comes back online and everything gets synched. What if now any sort of error happens (So the onSuccessListener would contain an error, but the persistence cache already has the data). How do I know that offline and online data are ALWAYS in sync once network connection is restored on all devices?
What about race conditions? Lets say two users update a document at the "same time" while the device is offline. What happens once it comes back online?
But the most pressing question is: right now I continue with my programflow when the onSuccessListener fires, but it never does as long as the device is offline (showing an indefinete progress bar forever). I still need to continue with my program (thats why we have offline persistence) - How do I do this?
How can I detect that data has successfully been written to the cache
This is the case when the statement that write the data has completed. If writing to the local cache fails, an exception is thrown from that write statement.
You second point is hard to summarize, but:
Firestore keeps the pending writes separate from the snapshots it returns for local reads, and will update the cached snapshot correctly both for successful and for rejected writes.
If you want to know whether the snapshot you read contains any pending writes, you can check the pendingWrites field in its metadata.
What about race conditions? Let's say two users update a document at the "same time" while the device is offline. What happens once it comes back online?
The last write wins. If that's not what you need, use security rules to enforce your requirements on the server.

IndexedDB persistence in PWA application

PWA application storage (IndexedDB) isn't able to provide data persistence.
In case that PWA is pinned to home screen it is possible to clear all application data from browser by clearing browsing history.
It might be unclear for users that cleaning browser data can affect pinned application and unsynchronised data will be lost.
Is there any way to avoid this?
The only way I see for now - turn back to native apps.
The clear storage mechanism in browsers is to put the user in control of their device.
This is why you as an application should never (native or web) assume your cached assets are cached.
If it is absolutely important to you to make sure you have core assets and data persisted then you need to have some sort of integrity check when the service worker initiates. That way you can restore cached state in case the application goes offline.
You also need to realize the operating system, looking at you iOS, will purge data when it feels like it (think when the available disk space gets critical), which takes you out fo control. It does this for native apps too as far as I know.
I do not know a way around that. The function in Chrome to "clear storage" (for example) does exactly that. I suppose it is reasonable for a user to be able to remove any data from their own device, but I agree it is not a good situation for the developer.
This is not possible.
The Storage API provides a StorageManager.persist() method to request the user explicit permission to persist data until deleted by the user itself:
if (navigator.storage && navigator.storage.persist)
navigator.storage.persist().then(function(persistent) {
if (persistent)
console.log("Storage will not be cleared except by explicit user action");
else
console.log("Storage may be cleared by the UA under storage pressure.");
});
If the local storage is running out of space, the User Agent will start automatically pruning cached resourced except the ones set as "persistent". However if the user itself chooses to clear the local data, there is no way to prevent this.
As far as I am aware, there is no event you can intercept in order to detect a browser clear action from the user.
See API reference doc :
https://developer.mozilla.org/en-US/docs/Web/API/StorageManager/persist

Angular PWA Offline Storage

I’m building a new web application which needs to work seamlessly even when there is no internet connection. I’ve selected Angular and am building a PWA as it comes with built-in functionality to make the application work offline. So far, I have the service worker working perfectly and driven by the manifest file, this very nicely caches the static content and I’ve set it to cache a bunch of API requests which I want to use whilst the application is offline.
In addition to this, I’ve used localStorage to store attempts to invoke put, post and delete API requests when the user is offline. Once the internet connection is re-established, the requests stored in localStorage are sent to the server.
This far in my proof of concept, the user can access content whilst offline, edit data and the data gets synced with the server once the user’s internet connection is re-established. This is where my quandary begins though. There is API request data cached automatically by the service worker as defined in the manifest file, and there is a separate store of data for data edits whilst offline. This leads to a situation where the user edits some data, saves the data, refreshes the page and the data is served by the service worker cached API.
Is there a built in mechanism to update API data cached automatically by the service worker? I don’t fancy trying to unpick this manually as it seems hacky and I can’t imagine it’ll be future proof as service workers evolve.
If there isn’t a standard way to achieve what I need to do, is it common for developers to take full control of offline data by storing it all in IndexedDB/localStorage manually? i.e. I could invoke API requests and write some code which caches the results in a structured format in IndexedDB to form an offline database, then writes back to the offline database whenever the user edits some data, and uploads any data edits when the user is back online. I don’t envisage any technical problems with doing this, it just seems like a lot of effort to achieve something which I was hoping to be standard functionality.
I’m fairly new to developing with Angular, but have many years of other development experience. So please forgive me if I’m asking obvious questions, I just can’t seem to find a good article on best practices for working with data storage with service workers.
Thanks
I have a project where my users can edit local data when they are offline and I use Cloud Firestore to have a local database cached available. If I understood you correctly, this would be exactly your requirement.
The benefit of this solution is that with just one line of code, you get not only a local db, but also all the changes made offline are automatically synchronised with the server once the client gets online again.
firebase.firestore().enablePersistence()
.catch(function(err) {
// log the error
});
// Subsequent queries will use persistence, if it was enabled successfully
If using this NoSQL database is an option for you I would go with it, otherwise you need to implement the local updates by yourself as there is not a built in solution for that.

Keep firesotrore collection available offline and sync it on foreground

What is the best approach to keep data of collection available offline (0 - 100 docs) and sync it on app startup if connection available?
UPD: I'm looking to setPersistenceEnabled but is there any guarantee my collection will be cached after first retrieve?
If you call setPersistenceEnabled(true) these documents will be available offline and synced when connection is available again (not necessarily at app startup). Check documentation:
https://firebase.google.com/docs/database/android/offline-capabilities
By enabling persistence, any data that the Firebase Realtime Database
client would sync while online persists to disk and is available
offline, even when the user or operating system restarts the app. This
means your app works as it would online by using the local data stored
in the cache. Listener callbacks will continue to fire for local
updates.
Also be aware that when you use this, then at app startup your listeners will be called TWICE! One - for offline (cached) data and second - online (read from firebase).