This is old and out-dated. Please see https://doc.replicache.dev/strategies/overview instead.
The Last-Modified Strategy is one of the easiest diff strategies to implement. It's also the strategy that comes to mind first for most developers when attempting to implement the pull endpoint.
This strategy cannot be implemented correctly on most servers due to unreliable clocks. Thus, we do not recommend it for production systems. It's presented here because it's frequently useful for early development, kicking the tires with Replicache, and as a basis for comparison to other strategies.
LastModified
field to each entity in your backend database if one doesn't already exist. You may already have one — many developers include it as a matter of course in all entities.LastModified
field each time an entity is changed. If possible, use a database trigger or similar to ensure the update to LastModfied
is always performed.IsDeleted
field and set it to true when deleting an item rather than actually deleting it. Take this field into account when reading data.null
:
IsDeleted=False
clear
op followed by put
ops for each read entitydel
ops for each entity where IsDeleted=True
, and put
ops for other entitiesLastModified
field in the requesting client's current client viewThis strategy requires a monotonically increasing clock for correctness, which is impossible to implement in most servers. Modern backend systems run on multiple physical application servers. Time can skew between these servers. Even on a single computer, time can jump forward or backward for a variety of reasons.
If this strategy observes time jump forward, nothing bad happens. However, if time jumps backward, then updates written to backend in that window can fail to sync to clients permanently.
The most straightforward solution to this problem is to enforce clock monotonicity. This is the The Global Version Strategy.
Soft Deletes are annoying to maintain. All queries to the database need to be aware of the IsDeleted
column and filter appropriately. There are other ways to track deletes however, see below.
Imagine you are syncing a set of documents, each of which is an entity in your DB with a LastModified
column. The selection of documents a user syncs is controlled by what they have access to. If the set of documents a user has access to changes, pull needs to reflect that, but that won't be captured in the LastModified
column because the document itself didn't change — only whether the user had access to it did.
To correctly handle this kind of change, you also need to track changes to the selection itself — either using the LastModified
pattern again or some other pattern on the relevant entities. If the selection has changes since the last pull, then the results of the new and old selection must be compared. And any new or changed docs must be sent, and any removed docs must be deleted.
There are alternative mechanisms to implement Soft Deletes. For example, you can maintain a separate Deleted
collection/table in the database. This removes the special case for writing queries at the cost of extra schema complexity in the database.
A different way to detect deletes is to store all known entity keys in the Replicache cookie. Then during pull, you can compare keys that were present last time with keys that are present now, and delete any that have been removed. This reduces server-side complexity at the cost of increasing request and response bandwidth during pull.
The Replidraw Sample uses The Last-Modified Strategy. See: https://github.com/rocicorp/replidraw/blob/master/backend/rds.ts#L104.