Let me try to explain what we are trying to achieve first.
Whenever our users launch the application for the first time there are 2 possible cases
- They have previously used the app and have data in the Realm cloud
- They are logging into the system for the first time ever
If the user is logging in for the first time ever, we need to bootstrap their database with basic data which is required for our business application to work.
If they have been previously used the system, the basic data is there, and there’s no need to generate it.
I know, the ideal solution would have been to do this in the backend, but for now, we do not need such complication and we decided to do the bootstrapping on the client-side.
Thus, whenever we launch the app, we show a special bootstrap screen, which should first try to download the data that the user might have in the cloud. At this step we need to force-sync the data, before moving forward, otherwise, we risk duplicating the initial bootstrap data. Up until recent times we were doing it by utilizing the Realm.GetInstanceAsync(syncConfiguration)
method, which will wait for all of the data to be synced if it’s used with SyncConfiguration
.
However, now we need to also show the progress of the initial synchronization, cause that may take some time for large databases and we want to give some visibility to the user about how far the process went. Unfortunately, Realm.GetInstanceAsync
can’t be used in that case and one would need to use the Realm.GetInstance
method and then monitor for the progress as explained in this StackOverflow post
If we do so, now we will need to somehow be able to wait for the synchronization to complete without using the Realm.GetInstanceAsync
method. The logical pick would have been the RefreshAsync
method. According to the docs
Asynchronously wait for the Realm instance and outstanding objects to get updated
to point to the most recent persisted version.
The behaviour that I see when invoking this method, is that it completes immediately without downloading the user’s current cloud data. The doc is a bit misleading here, but I believe what happens is that this method only synchronizes the uplink changes and won’t download the existing data. If it was meant to actually do a full 2-way synchronization, then I guess I have found a bug that should be fixed.
I couldn’t find any other API that would do force 2-way synchronization on the background thread that wouldn’t block the progress from happening… I tried to somehow doing that using upload/download progress. Basically, I subscribe to the upload/download messages and wait until they both are complete.
var session = realm.GetSession();
await session.GetProgressObservable(ProgressDirection.Download, ProgressMode.ForCurrentlyOutstandingWork)
.CombineLatest(session.GetProgressObservable(ProgressDirection.Upload, ProgressMode.ForCurrentlyOutstandingWork))
.Where(progress => progress.Second.TransferredBytes >= progress.First.TransferableBytes)
.FirstAsync();
However, this is brute force and works on the consequence of the action rather than the source.
So, what would be the best way to force-sync realm without blocking the progress notifications?