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());
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());
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.