0

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 (I've dropped the push replication for now while trying to debug this). The options on the replications aren't 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. Additionally, I set up a function to run every few seconds and print the status of the replication and it is stuck on ACTIVE.

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?

EDIT 1 The only way I can currently get it to work is to completely delete the local db in the replication changed function and restart it... then start a new replication... this works... unfortunately though, I then have to broadcast a notification so that any table view that may be up reloads the query. This causes a refresh animation in tableviews and isn't sustainable... but at least I can keep moving for now.

EDIT 2 I found how to enable better logging of the CBL on iOS and here's an error I keep seeing after a token refresh/ replication restart:

CBLWebSocketChangeTracker[0x7ff9bb53b5e0 iphone]: Connection error #8, retrying in 256.0 sec: PSWebSocketError[3, "Output stream end encountered"]

Thoughts?

EDIT 3 I changed things around a bit to get rid of the refreshing of tokens. I attempted to make it so when a user logs in from the iOS app, the backend creates a session with the sync gateway for that user and returns it. The app then starts a replication with that session. Then, after the 5 minutes (the ttl used when creating the session), the next time the app tries to sync, it will get a 401 and stop the replication and present the login screen. Then, when the user logs in again, a new session is created, etc...

I found 2 things:

-Anytime I added a doc to a channel that would sync with the app, when the app synced, the session expiration date would increase by about 20ish seconds. Is this normal behavior? The only way it would log the user out on the expired token is if I didn't add any docs for long enough.

-The restarted replication still gets stuck. Here are the logs for the sync gateway and xcode:

This is the last part of the sync gateway when the session is expired... which will send the 404 to the app.

2016-08-23T21:11:51.089-05:00 Changes+: Sending seq:163 from channel jmoore2
2016-08-23T21:11:51.089-05:00 Changes+: MultiChangesFeed sending &{Seq:163 ID:un:jmoore2_116 Deleted:false Removed:{} Doc:map[] Changes:[map[rev:1-e775ef6713dc39f6d52d35cefb396fe3]] Err:<nil> allRemoved:false branched:false}   (to jmoore2)
2016-08-23T21:11:51.089-05:00 Changes: MultiChangesFeed done   (to jmoore2)
2016-08-23T21:11:51.089-05:00 HTTP+: #212:     --> 200 OK  (0.0 ms)
2016-08-23T21:11:51.459-05:00 HTTP:  #216: GET /my_gateway/_session/3fa29222db286e8ec67a51e88b613ba4cd5cbf31  (ADMIN)
2016-08-23T21:11:51.459-05:00 HTTP: #216:     --> 404 missing  (0.2 ms)
2016-08-23T21:11:51.461-05:00 HTTP:  #217: GET /my_gateway/_session/3fa29222db286e8ec67a51e88b613ba4cd5cbf31  (ADMIN)
2016-08-23T21:11:51.461-05:00 HTTP: #217:     --> 404 missing  (0.2 ms)

Then, when the user logs back in, here are SG log for that:

2016-08-23T21:15:41.200-05:00 HTTP:  #223: GET /my_gateway/_session/1a6105eaf2c91de320a47422041c655dd3d5c279  (ADMIN)
2016-08-23T21:15:41.201-05:00 HTTP+: #223:     --> 200   (0.5 ms)
2016-08-23T21:15:41.203-05:00 HTTP:  #224: GET /my_gateway/_local/78c229762074a95c864f7fecc03ce88f0ef6c499  (as jmoore2)
2016-08-23T21:15:41.203-05:00 HTTP+: #224:     --> 200   (0.5 ms)
2016-08-23T21:15:41.371-05:00 Cache: Received #164 after 455ms ("user-login-info:jmoore2" / "48-ea0b2d9771fa2be1d76838f9e4d55081")
2016-08-23T21:15:41.371-05:00 Cache:     #164 ==> channel "*"
2016-08-23T21:15:41.371-05:00 Changes+: Notifying that “mdatabase” changed (keys="{*}") count=31

And the xcode log when restarting the replication immediately goes to this:

21:15:41.195‖ Sync: CBLRestPuller[http://mycomp.local:8080/iphone/]: Reachability state = <mycomp.local>:reachable (30002), suspended=0
21:15:41.205‖ Sync: CBLRestPuller[http://mycomp.local:8080/iphone/]: Server is Couchbase Sync Gateway/1.3.0
21:15:41.205‖ Sync: CBLRestPuller[http://mycomp.local:8080/iphone/]: Replicating from lastSequence=162
21:15:41.205‖ Sync: CBLRestPuller[http://mycomp.local:8080/iphone/] starting ChangeTracker: mode=3, since=162
21:15:41.207‖ ChangeTracker: CBLWebSocketChangeTracker[0x7f97d8698190 iphone]: Starting...
21:15:41.207‖ Sync: CBLWebSocketChangeTracker[0x7f97d8698190 iphone]: GET //mycomp.local:8080/iphone/_changes?feed=websocket
21:15:41.208‖ ChangeTracker: CBLWebSocketChangeTracker[0x7f97d8698190 iphone]: Started... <http://mycomp.local:8080/iphone/_changes?feed=websocket>
21:15:41.211‖ CBLWebSocketChangeTracker[0x7f97d8698190 iphone]: Connection error #1, retrying in 2.0 sec: PSWebSocketError[3, "Output stream end encountered"]

and also sometimes this error shows up:

2016-08-23 21:01:15.232 MyApp[52094:36001215] 52094: CFNetwork internal error (0xc01a:/BuildRoot/Library/Caches/com.apple.xbs/Sources/CFNetwork_Sim/CFNetwork-758.3.15/Loading/URLConnectionLoader.cpp:289)
a2345sooted
  • 569
  • 5
  • 20
  • You don't say which versions of couchbase lite and sync_gateway you are using. 1.3 has new support for OpenID. – combinatorial Aug 23 '16 at 15:18
  • updated versions and question overall with more detail... still having this issue – a2345sooted Aug 23 '16 at 20:06
  • does your sync function do anything especially related to checking the authenticated user? Have you looked at the sync gateway logs to see what's happening on that side (and have you enabled all the logging options e.g. "log": ["*"])? – combinatorial Aug 24 '16 at 00:53
  • no, currently the sync function is only adding roles to a user for a certain doc type. In the SG logs, the only error I see is a 409 for a document conflict, I'm still investigating what this doc is. But, in the admin console, I can see that the relevant document with session info is up to date and I see the sync:session is uptodate and I see the new session is successfully retrieved by the app and then set in the replication before restarting, or stopping/starting. – a2345sooted Aug 24 '16 at 01:24
  • I also see that the new cookie is in fact sent to the server by the replication after restarting... then it just hangs with the CBLWebSocketChangeTracker error I put in the original question as an edit at the bottom. I'll test it again and put up the final SG log statements when it starts hanging – a2345sooted Aug 24 '16 at 01:24
  • I added another edit at bottom of question with some logs of what's going on – a2345sooted Aug 24 '16 at 02:27
  • so, looks like it's a websocket issue and my servers between the app and the SG aren't set up to work with websockets currently. So, disabling websockets on the replications seems to do the trick. – a2345sooted Aug 24 '16 at 03:35

0 Answers0