I’m wondering if its possible to setup Sync Gateway replications such that conflicts are allowed on pull but not on push.
My team has an offline app using Couchbase server as our primary database, clients’ local devices using pouchDB, and Sync Gateway to sync data between the pouchDB instances and Couchbase. As our app is designed with an offline-first approach, document conflicts will sometimes occur. We need a way to merge conflicting documents rather than choosing a winner, and so far we’ve come up with a good client side approach once the conflicting revision is synced to the device. The issue however is our current Sync Gateway setup allows us to push conflicting documents to Couchbase, potentially causing a loop of each individual client creating new document revisions to resolve the conflict. Ideally, the device which is causing the conflict shouldn’t be allowed to push until the conflict is resolved.
Currently, our Sync Gateway config file has ‘allow_conflicts=true’. I’ve tried updating this property to false, and the result is the sync failing (which is expected) but the conflicting revision is never pulled down to the device so our logic to resolve the conflict can’t execute. Our current conflict merging logic requires access to the two conflicting revision and the last non-conflicting revision. Due to this limitation, we can’t move the conflict merging code to sync gateway as I’ve see in the documentation that a custom conflict resolution function only has access to the two conflicting documents. What we need is a way to pull down conflicting document revisions to the client, but not be able to push back to Couchbase until the conflict is resolved on the client.
The usual way to achieve this is to set allow_conflicts=false like you’ve done, and then rely on clients pulling the conflict, resolving and pushing up the result.
Can you elaborate more on why this isn’t working for you? I’m not sure I understand why clients are unable to pull the conflicts?
Thanks for the reply. Our issue was we had live replication setup for PouchDB and the replication would push before pulling. We had code to cancel the sync whenever we got an error so we never got to the pulling phase. We’ve since refactored our replication code to do one-off pulls then pushes which fixed the issue.
However, we have a new issue which we haven’t been able to work around. Our current sync process is this:
Every 1 minute (when online) do a pull
After a successful pull, check for conflicts
If there’s conflicts, create a new merged revision and delete the conflicting rev
Push changes
The issue we’re seeing now is when deleting a document in pouchDB, a new revision is made. This causes us to get a 409 on push which we can never resolve.
Example:
User A and user B (and couchbase) have revision 1-a of some document.
While user A is offline, user B edits the document to create revision 2-a.
Revision 2-a is pushed to couchbase, where it then becomes rev 3-a due to an eventing function.
User A, still offline, creates revision 2-b.
User A comes online, pulls down revisions 2-a and 3-a.
User A’s device detects a conflict with 3-a and 2-b
User A’s device created a new merged revision 4-a, while creating 2-c when deleting 2-b (the conflicting rev).
User A does a push, 4-a gets successfully pushed to couchbase but we get a 409 for 2-c.
For every new revision user A creates, we always get the conflict for 2-c (still 2-a) in couchbase
So even though our new merged winning revision makes it up and is visible to other users, user A will always get a 409 for that deleted revision whenever they edit the document. This is when allow_conflicts=false.
Is this a scenario you’ve heard about before? And if so, and tips on how to resolve this issue?