I’ve got a weird error in syncing that occurs during application shutdown.
Its a little complex to describe, but here goes…
I have an iPad and Mac running my software, syncing to a remote server.
Both have have the same document opened. Both have Change Listeners on queries that monitor that document.
All is good. I make some changes to the document on the iOS side, but don’t save yet.
Then I shut the iPad app down (swipe up to show all apps, swipe up on my app). The following sequence occurs on the iOS side, which all looks good as far as I can tell:
- App delegate gets the OnResignActivation
- Document manager is asked to save its current state (which it does) using db.Save(doc)
- App then runs a “WaitForSyncIdle”, where it waits for 250ms, then waits until the sync status is idle.
- App stops sync
- App completes shutdown - AppDelegate.WillTerminate.
The weird thing happens on the Mac side. About 1 second after iOS does a save the Mac does the following:
- App receives the document changed notification
- App loads the document using db.GetDocument()
The problem is that it receives an old copy of the document - in this case about 50 seconds old and missing some changes.
I then restart the iOS app. Its copy of the document is the latest, it seems to resync and things usually fix themselves up.
A slight variation on this is where the mac does not receive the notification about the change (i’m guessing the iOS side shuts down before the sync can happen). Then I restart the iOS app, and the following happens in quick succession:
- Mac receives notification about document change. Gets an old copy of the document.
- Mac receives another notification about document change. Gets a new copy of the document.
So it seems that having a sync pending or in progress during app shutdown creates something strange with old and new document versions.
This makes me believe that I am not shutting the sync engine down properly, or my “WaitForSyncIdle” is faulty.
Here is how I start the sync engine:
var auth = new BasicAuthenticator(id, secure_server_password);
var collection = database.GetCollection("_default");
var collection_configuration = new CollectionConfiguration()
{
ConflictResolver = new SyncConflictResolver()
};
var sync_config = new ReplicatorConfiguration(target)
{
ReplicatorType = ReplicatorType.PushAndPull,
Continuous = true,
Authenticator = auth,
};
sync_config.AddCollection(collection, collection_configuration);
replicator = new Replicator(sync_config);
listenerToken = replicator.AddChangeListener(SyncStatusUpdate);
replicator.Start();
And here is now I stop it:
if (replicator == null)
return;
try
{
replicator.Stop();
// replicator doesn't actually stop immediately. We will wait for a few ms if wait_ms is passed in > 0
if (wait_ms > 0)
{
var wait_until = DateTimeOffset.Now.AddMilliseconds(wait_ms);
while (currentSyncStatus != SyncStatus.NotStarted && wait_until > DateTimeOffset.Now)
Thread.Sleep(100);
}
replicator.RemoveChangeListener(listenerToken);
}
catch (Exception e)
{
log.Error(e, "Failed to stop sync agent");
}
replicator = null;
My stop function is called as follows:
WaitForSyncIdle(250); // wait an initial 250ms, then wait for idle state.
StopSyncAgent(250); // stop sync agent, waiting 250ms for it to complete.
Is there some extra work I need to do when stopping replication during application shutdown that is needed to stop the extra document sync with an old copy of the document?
Many thanks.
Paul.