Couchbase Lite bi-directional sync is not working as expected

We are trying to create a proof of concept for our new android project that requires offline first capabilities. We are using free tier hosted by Couchbase.

Current behavior:
Local documents are getting uploaded and saved through Sync Gateway but it does not pull remote documents

Expected behavior:
Remote documents should also be pulled

Here’s my code:


@Module
@InstallIn(SingletonComponent::class)
object CouchTalkModule {
    @Provides
    @Singleton
    fun provideCouchbase(@ApplicationContext context: Context): Database {
        CouchbaseLite.init(context)

        val localDb = Database("couch_talk")

        val chatRoom = localDb.createCollection("chat_room")
        val chat = localDb.createCollection("chat").apply {
            createIndex(
                "createdAtIndex",
                IndexBuilder.valueIndex(ValueIndexItem.property("createdAt"))
            )
        }
        val user = localDb.createCollection("user").apply {
            createIndex(
                "emailIndex",
                IndexBuilder.valueIndex((ValueIndexItem.property("email")))
            )
        }

        val syncGatewayUrl = URI("wss://xxxxx:4984/couch_talk")

        val repl = Replicator(
            ReplicatorConfiguration(URLEndpoint(syncGatewayUrl))
                .addCollections(
                    listOf(
                        chatRoom,
                        chat,
                        user,
                    ),
                    null
                )
                .setType(ReplicatorType.PUSH_AND_PULL)
                .setContinuous(true)
                .setAutoPurgeEnabled(false)
                .setMaxAttempts(Int.MAX_VALUE)
                .setHeartbeat(150)
                .setMaxAttemptWaitTime(600)
                .setAuthenticator(BasicAuthenticator("xxxx", "xxxx".toCharArray()))
        )

        repl.addChangeListener { change ->
            Log.d("pocapp", "Replicator activity level is " + change.status.activityLevel)
        }

        repl.start()

        return localDb
    }
}
1 Like

This code looks pretty good to me. It looks a lot like the code that is working, in production, for hundreds of other people.

Perhaps, if you can provide a bit more information we’d be able to be of more assitance.

  • What version of CBL are you using?
  • What system are you running on?
  • What is the evidence that the documents are ton being pulled?
  • Do you have logs so that we can see what’s going on?

What version of CBL are you using?

com.couchbase.lite:couchbase-lite-android-ktx:3.2.1

What system are you running on?
Ubuntu Desktop 24.04
Android Studio Ladybug Feature Drop | 2024.2.2
Emulator: Medium Phone API 35 x86_64 (default settings)

What is the evidence that the documents are ton being pulled?
I have two devices A and B which created a total of 5 documents, these two devices are expecting 5 documents (including the logged in user), but each device only has the documents it created–so I think it’s able to push the changes but not pull remote data

Couchbase cloud showing 5 documents:

Here is Device A showing 3 documents instead of 5 (these 3 documents originated from Device A and documents from Device B is not showing here)
I am a new user, can’t upload two images, using alternatives to show image

Here’s the code for reference:

class UserRepository @Inject constructor(private val db: Database) : Repository<UserDto> {
    private val collection by lazy { db.getCollection("user")!! }

    override fun list(): List<UserDto> {
        val query = QueryBuilder.select(SelectResult.all())
            .from(DataSource.collection(collection))

        return query.execute().allResults().map {
            Json.decodeFromString<UserResultDto>(it.toJSON()).user
        }
    }
}

Do you have logs so that we can see what’s going on?

I am not sure but here’s the logs from Android Studio–I can’t seem to post the logs here because it gets hidden:

Not sure if related but I experienced a similar issue after restarting my free tier cluster and app service that were paused for inactivity. I know it was not my code at fault, because creating a new cluster and app service had everything up and running well again with the only client side change being the replicator endpoint url. Not a satisfactory solution ofc, just something to be aware of.

Hi Tudor, when you say restart it means I have to pause and resume my free tier Couchbase cluster or pause/resume my Sync Gateway?

Apologies for the misunderstanding.
What i meant was that in my scenario everything was working fine before my cluster and app services got automatically turned off for inactivity. After they were turned off automatically and i turned them back on manually, the sync no longer worked as expected and was in a similar state to what you are describing.
Nothing i tried fixed it, and i tried hard to figure it out. From code changes to manual restarts left nothing untouched. In the end the only thing that worked for me was deleting both by app service and cluster and creating new ones. The new endpoint worked once again as expected.
This confirms, at least to me, that the issue was never with my implementation but rather something going wrong Capella side.
I am not saying you should try the same thing or that it is even the exact same issue, just giving my account of a similar thing i encountered.

Not receiving documents in pull can be the result of a badly configured Sync Gateway as well. How did you configure your user and sync function there? Sync Gateway controls the read permissions for all users.

I created Sync Gateway with default config and linked the collections from my bucket and I have also created a user that has access to the said buckets:

I have also created app role “user_role” and assigned it to my user

The Sync Gateway channel function are also using default:

Hey Tudor, I’ve deleted my Couchbase cluster and its sync gateway and recreated everything again but the issue is still happening, though when I link my collections to the sync gateway it does get paused (but not the cluster)

I’ve resolved it, but gotta say, it was incredible hard just to make sync gateway work

Found the answer here:

I have modified my sync function like so:

function (doc, oldDoc, meta) {
  channel('user');
  // this one was actually needed, so for anyone who wants to work with sync gateway we have to actually dig a bit deeper :(
  access('my-user', 'user');
}

I can sympathize that it seems hard to understand, but perhaps this documentation can help you

Couchbase Lite doesn’t come with any kind of access control, so it is all handled on the Sync Gateway side.

It’s a very different model from the typical Unix-permissions or access control lists you might be familiar with.

The answer you got is actually overkill. The one thing you were missing from your previous config, as far as I can tell, was giving the user account(s) access to the channel. That can be done by editing the channel list in the account.

The solution you quoted does work, but it’s intended for more complex use cases where you want to grant access to channels dynamically, e.g. a chat app where user A can create a doc that grants user B access to a private chat.

Just chiming in to support the original poster. I had this same problem and wasted a lot of time before figuring out that I had to opt into channels and configure a bunch of permission nonsense on the server.

It might be nice to provide the opposite experience as an option: set up an App Service with a scope and a bucket and just give it blanket read/write to every collection therein, then allow the developer to opt-out various collections as required.

Right now the only option is: “sync exactly the collections I tell you to sync.”

What would be nice is: “sync every collection, including new ones that I add in the future, unless I explicitly tell you not to include one.”

1 Like