Replications stops syncing after restart

I’m still a bit new to Couchbase and iOS, but I’m running into a problem restarting my replications that I’m having trouble with. Here are a few notes about the flow.

The backend is using custom authentication.

When the user logs in, a new session is created in the sync gateway and those session details are returned to the iOS device. The app then uses those credentials to set up a push and pull replication. The options are replications arent’ much and are as follows:

let pull = self.database.createPullReplication(self.remoteDBURL);
pull.continuous = true;
pull.headers["uuid"] = "device-1";
pull.setCookieNamed(sessionName, withValue: sessionId, path: "/", expirationDate: cookieExpirationDate, secure: false);
pull.start();
self._pull = pull;
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(DataService.replicationChanged(_:)), name: kCBLReplicationChangeNotification, object: self._pull);

This works great and all the proper documents are synced to the device. Currently I have the backend created cookies that only last for about 5 minutes so I can test the refreshing of cookies. So, during the first few minutes, any docs I add to the channel that the app gets, the app receives the doc and all is good.

About halfway into the life of the token, the backend is set up to return with a 401 error telling the app to use it’s token to get a new token. So, I have this in the replication change listener:

@objc public func replicationChanged(n: NSNotification) {
    let replication = n.object as! CBLReplication;

    let error = replication.lastError;
    if (error != nil) {
        print("last error is NOT nil");
        print("last error = \(error)");

        switch error!.code {
        case 401:
            self.updateReplicationSession();
        default:
            break;
        }
  }

}
Then, the updateReplication function looks like this:

… make http call to getNewToken url using the ‘old’ or ‘soon to be expired’ token. *The server is successfully returning this new session.

self._pull.setCookieNamed(newSessionName, withValue: newSessionId, path: "/", expirationDate: newExpirationDate, secure: false);

self._pull.restart();
...

It is at this time that the syncing stops working. No errors are thrown that I can see of other than once I received a CFNetwork Internal error. I can see on the server logs that the replication sends in the new session once… then everything just seems to hang for the replication. Any new docs to a channel that it gets and it doesn’t get them. I don’t see anything in the Sync Gateway logs indicating what the problem is. However, I’m still pretty new to this… so there may be something.

I’m using sync gateway v 1.3 and CBL ios 1.3. I was using version 1.2.1 and was having this problem… hoping ugrading to 1.3 would magically fix it. It didn’t, but I’m not sure I should go back to 1.2.1.

I’m completely stumped on this. I’ve searched high and low and often seem to find an answer that fits the bill… but it still doesn’t work.

I’ve tried delaying the updating of the session in order for all calls from replication to ‘fail’ first. I’ve tried just calling start() on the replication thinking that maybe the 401 killed the replication and restart() isn’t going to do anything. I’ve called stop()… then waited a bit and called start(). Not sure what to do next.

Any help is appreciated guys! Is it possible the local DB on the phone and the sync gateway have a unresolvable rev problem?

This post seems to address a similar problem. https://forums.couchbase.com/t/correct-way-to-restart-a-replication/7193

Can you check logs and see if you get the Replication not restarting message?

Thanks for your response. I resolved this a few days ago and forgot to post answer. It took a while to find out about the custom properties for a replication, but once I did I shut websockets off:

rep.customProperties = ["websocket": false];

This made the problem go away. I just have a make shift node backend going on right now with no consideration for websockets. Since this backend is a middleman between mobile device and sync gateway, it was not properly shutting down or starting the web socket back up. Either way, turning it off fixed the issue.

Any time you have some kind of gateway in between CBL and SG — even something common like nginx, but especially something weird or custom — you really should call it out in the initial post. There are many problems that these gateways can introduce; not just WebSocket problems but also timeouts, problems with chunk encoding. etc. If we know about this ahead of time it can save a lot of time troubleshooting.

I mentioned that I was using custom authentication, but I agree with you. That didn’t really get that point across. Good advice, thanks.