Skip to content

Control and monitor replication

When you connect() to a cloud database SKDB creates a long lived network connection. The connection is used to push updates in either direction to keep mirrored data synchronized in real time.

If the device goes offline, your app will continue to function as all of the data is local. Of course, SKDB will not receive any data updates while offline. But when a connection is re-established, SKDB uses an efficient protocol to resynchronize the data, transmitting only what has changed.

Check if the connection is healthy

SKDB's connection to the cloud database will be kept alive for you until it is closed with skdb.closeConnection(). SKDB reconnects automatically if e.g. the device loses network connectivity.

You may want to understand whether your application is currently online and synchronizing in real time. You can check the current connection health using isConnectionHealthy(). With a connected client, the code looks like this:

const remoteDb = await skdb.connectedRemote();
console.log("Connection is healthy?", await remoteDb.isConnectionHealthy());
Connection is healthy? true

Understand if all local writes have synchronised

SKDB's replication protocol acknowledges updates. This allows you to be confident that data updates have been received and reliably stored in the cloud database.

You can check whether any updates have not yet been acknowledged using tablesAwaitingSync(). This could be useful if you wish to warn a user that their updates haven't yet been saved e.g. on closing a browser tab.

With a client mirroring a table:

const remoteDb = await skdb.connectedRemote();

await skdb.exec(
  "INSERT INTO mirror_demo_table (n, skdb_access) VALUES (1234, 'read-write')"
);
console.log(await remoteDb.tablesAwaitingSync());
Set(0) {}

Discover if updates are rejected by the cloud database

In rare scenarios the server may reject changes made to tables.

Rejected updates are most likely to occur if you try to modify data that violates a CHECK constraint that has been setup on the cloud database. You can mitigate this by also setting up constraints locally using reactive views.

Rejected updates can also happen in rare situations. For example, if you update a row while privacy rules are being concurrently changed that remove your access, your write may be rejected.

Rejected rows are sent back to the client and stored in a table that SKDB creates for you. This table is always named after the mirrored table with __skdb_mirror_feedback appended.

For example, if you mirror a table called example_table, SKDB will create example_table and also example_table__skdb_mirror_feedback.

example_table__skdb_mirror_feedback will have the same schema as example_table and you can query it like you would any table. You may wish to query with exec() if there are points in your application where it makes sense to check for and handle any rejected rows. Or you may wish to continually monitor for rejected updates by subscribing to the table with watch() or watchChanges().

Define how conflicting updates are handled

If two or more users are trying to concurrently update a row, we call this a 'conflict'.

SKDB offers two solutions for conflict and you control which is used by whether you have defined a primary key for the table.

SKDB will use fully automated resolution if a primary key is defined on a table. The primary key maintains the constraint that this row is globally unique, so SKDB must resolve conflicts: it cannot keep more than one version of the row otherwise the primary key constraint would be violated.

SKDB uses a 'last-write wins' policy for resolution when there is a primary key. The row that was written last is the one that is kept and 'beats' any other concurrent updates - those versions of the row are dropped. This policy is easy to reason about and works well in a wide variety of use cases. You should define a primary key and utilise this when it is acceptable, and this will make your queries a little simpler.

If you do not define a primary key, SKDB will not attempt any conflict resolution. All concurrently written versions of the row are kept, because they can be. These will be delivered and your application (or the user) can resolve the conflict using any policy that you like.

To resolve a conflict, you simply DELETE the conflicting rows and INSERT the resolved version.