Replication states gone wild

49 views
Skip to first unread message

Christoph Berlin

unread,
Oct 30, 2014, 4:12:52 PM10/30/14
to mobile-c...@googlegroups.com
Hi,

Yet again, I need to post another question and I hope that someone can shed light on the replication status logic. I am trying to build a very simple first sync logic in iOS doesn't prevents the app from advancing to the next screen until data has been sync at least ones. That seems very straight forward but something is not right and I don't understand what "it" is.

Following scenario:
  1. App launches
  2. Shows login view controller
  3. User logs in --> replication starts (continuous)  --> shows progress bar on login view controller --> once first sync is complete advance to next view controller
That works well in the event of success meaning that the replication finishes and done.

However if I test the failure scenario something odd happens. For this test I turn off the sync gateway so that there is no server available. Phone has network but no sync endpoint.
  1. Initially the pull replication status shows a correct value (1)
  2. But then the replication goes into active state and ends in the idle EVEN THOUGH the sync gateway is offline the whole time.

2014-10-30 13:03:45.539 OnePlan[15930:501055] Pull Status: 1

2014-10-30 13:03:45.539 OnePlan[15930:501055] Push Status: 3

2014-10-30 13:03:45.540 OnePlan[15930:501055] SYNC progress: 0 / 0

2014-10-30 13:03:45.540 OnePlan[15930:501055] Pull Status: 3

2014-10-30 13:03:45.540 OnePlan[15930:501055] Push Status: 3

2014-10-30 13:03:45.540 OnePlan[15930:501055] SYNC progress: 0 / 0

2014-10-30 13:03:57.553 OnePlan[15930:501055] Pull Status: 2

2014-10-30 13:03:57.553 OnePlan[15930:501055] Push Status: 3

2014-10-30 13:03:57.553 OnePlan[15930:501055] SYNC progress: 0 / 0

2014-10-30 13:03:57.553 OnePlan[15930:501055] Pull Status: 2

2014-10-30 13:03:57.554 OnePlan[15930:501055] Push Status: 2


I would expect that the status stays OFFLINE (1) the whole time unless I am missing something - if that is the case could someone tell me what I miss? How would I implement a function that makes sure that the app doesn't continue without the successful sync.

-(void)replicationProgress:(NSNotification *)notification

{

    NSLog(@"Pull Status: %u", app.user.syncManager.pull.status);

    NSLog(@"Push Status: %u", app.user.syncManager.push.status);

    

    if (app.user.syncManager.pull.status == kCBLReplicationActive || app.user.syncManager.push.status == kCBLReplicationActive)

    {

        // Sync is active -- aggregate the progress of both replications and compute a fraction:

        unsigned completed = app.user.syncManager.pull.completedChangesCount + app.user.syncManager.push.completedChangesCount;

        unsigned total = app.user.syncManager.pull.changesCount + app.user.syncManager.push.changesCount;

        NSLog(@"SYNC progress: %u / %u", completed, total);

        // Update the progress bar, avoiding divide-by-zero exceptions:

        self.progressBar.hidden = NO;

        self.progressBar.progress = (completed / (float) MAX(total, 1u));

    }

    else if (app.user.syncManager.pull.status == kCBLReplicationOffline || app.user.syncManager.push.status == kCBLReplicationOffline)

    {

        self.progressBar.hidden = YES;

        self.progressBarView.hidden = YES;

        self.failureView.hidden = NO;


            NSError *error = app.user.syncManager.pull.lastError ? app.user.syncManager.pull.lastError : app.user.syncManager.push.lastError;

            if (error != self.syncError)

            {

                self.syncError = error;

                if (error)

                {

                    self.failureLabel.text = [error.userInfo objectForKey:@"NSLocalizedDescription"];


                }

            }

      

    }

    else if (app.user.syncManager.pull.status == kCBLReplicationIdle || app.user.syncManager.push.status == kCBLReplicationIdle)

    {

        [app.user setInitialSyncStatus:YES];

        [self initiateApp];


    }

}


From the documentation:

  • Stopped: A one-shot replication goes into this state after all documents have been transferred or a fatal error occurs. (Continuous replications never stop.)
  • Offline: The remote server is not reachable. Most often this happens because there's no network connection, but it can also occur if the server's inside an intranet or home network but the device isn't. (The replication will monitor the network state and will try to connect when the server becomes reachable.)
  • Idle: Indicates that a continuous replication has "caught up" and transferred all documents, but is monitoring the source database for future changes.
  • Active: The replication is actively working, either transferring documents or determining what needs to be transferred.
 

By the way after having confidence issues about my own code I copied the replication function above from someone else knowing that it works...but my issue seems to be much deeper.

Thanks as always Christoph 

Jens Alfke

unread,
Oct 30, 2014, 4:23:35 PM10/30/14
to mobile-c...@googlegroups.com
On Oct 30, 2014, at 1:12 PM, Christoph Berlin <hoptoawe...@gmail.com> wrote:

I would expect that the status stays OFFLINE (1) the whole time unless I am missing something

The Offline state means the client is offline, i.e. there is no network interface capable of reaching the server.

- if that is the case could someone tell me what I miss? How would I implement a function that makes sure that the app doesn't continue without the successful sync.

Use a non-continuous replication and wait for it to reach the Stopped state; then check for errors.

Slightly off-topic, but it's a better user experience if the app doesn't block until the first sync is complete. If you've written your UI code to respond to database changes, then the app can usually start up right away with minimal/no data, and then gradually fill in as the data arrives. Or if there's some subset of the data that's mandatory before you can run, you could put those documents in a special channel and initially sync with just that channel, then unblock the UI and start the full sync.

—Jens

Christoph Berlin

unread,
Oct 30, 2014, 4:38:30 PM10/30/14
to mobile-c...@googlegroups.com
Thanks Jens, much appreciate it. I agree with your concern about the bad user experience but as you noticed there is a mandatory need to sync a subset first and then continue. Without that there is a risk of creating a conflict in the logic.

I will try your suggestion regarding the non-continious replication however I still find the replication states confusing. Why would the real status show IDLE even though no replication has been completed? Furthermore the lastError throws an error initially ("server could not be contacted") but subsequent notifications show lastError=nil. 
Reply all
Reply to author
Forward
0 new messages