Протокол синхронизации в Dexie Cloud строится вокруг идеи двунаправленного обмена изменениями между локальной базой данных и удалённым хранилищем, при этом локальная база в Dexie.js рассматривается как первичный источник операций. Вместо классической модели «перезаписать состояние» используется модель журналируемых изменений (operation log / change feed), где каждое изменение представляется как событие с метаданными, позволяющими восстановить порядок, идентичность и контекст выполнения.
Основой протокола является разделение на три слоя: локальный журнал операций, транспортный слой синхронизации и удалённый журнал/состояние. Такое разделение позволяет минимизировать зависимость от сетевого соединения и обеспечить детерминированное разрешение конфликтов.
Каждая модификация данных в Dexie.js фиксируется в локальном журнале изменений. Этот журнал является источником истины до момента синхронизации и включает:
Важный аспект — неизменяемость записей журнала. Каждая операция не редактируется, а добавляется как новая запись. Это позволяет выполнять повторную отправку и восстановление состояния без потери семантики.
Локальный журнал также используется как механизм отката: при конфликте сервер может прислать альтернативную версию цепочки изменений, и клиент способен пересобрать состояние, переиграв операции.
Синхронизационный протокол опирается на концепцию ревизий (revision IDs). Каждая сущность в базе получает стабильный идентификатор и набор версий. Ревизия формируется на основе:
Ревизии образуют направленный граф изменений, но в большинстве сценариев сводятся к линейной цепочке. При расхождениях создаются ветви, которые затем разрешаются сервером или клиентом в зависимости от политики конфликтов.
Ключевым элементом является детерминированность генерации ревизий: одинаковый набор операций в одинаковом порядке приводит к одинаковому результату на разных устройствах.
Синхронизация в Dexie Cloud состоит из двух основных потоков: push (от клиента к серверу) и pull (от сервера к клиенту).
На этапе отправки клиент агрегирует локальные изменения из журнала и формирует пакет (mutation batch). Этот пакет включает:
Сервер проверяет применимость операций относительно текущего состояния. Если данные на сервере не изменились с момента базовой ревизии, изменения применяются напрямую. Если изменения уже произошли, запускается механизм конфликтного разрешения.
При получении изменений клиент запрашивает у сервера дельту изменений, начиная с последней известной ревизии. Сервер возвращает:
Клиент применяет полученные изменения поверх локального состояния, обеспечивая согласованность данных.
Протокол не передаёт полные состояния объектов при каждом изменении. Вместо этого используется дифференциальный подход: передаются только изменения полей. Это снижает объём трафика и ускоряет синхронизацию.
Существует два режима:
Выбор режима зависит от политики коллекции и структуры данных.
Локальная очередь операций в Dexie.js работает по принципу at-least-once delivery. Это означает, что каждая операция гарантированно будет доставлена минимум один раз, но может быть повторно отправлена при сбоях сети.
Для предотвращения дублирования на серверной стороне используются:
Таким образом достигается баланс между надёжностью и простотой протокола.
Конфликты возникают при одновременном изменении одной сущности на разных устройствах. Протокол предусматривает несколько стратегий:
Простейшая стратегия, при которой приоритет отдаётся операции с более поздней временной меткой. Несмотря на простоту, она может приводить к потере данных.
Сервер выполняет слияние изменений на уровне полей. Если два изменения затрагивают разные поля, они объединяются. При конфликте одного поля применяется серверная политика приоритета.
В сложных приложениях допускается подключение пользовательской функции разрешения конфликтов. Она получает:
и возвращает итоговое состояние.
Каждая синхронизационная операция рассматривается как транзакция, включающая несколько этапов:
Если любой этап не завершается успешно, транзакция остаётся в незавершённом состоянии и повторяется при следующей синхронизации.
Это обеспечивает устойчивость к обрывам соединения и перезапускам приложения.
Синхронизационный протокол учитывает эволюцию структуры данных. Каждая операция содержит версию схемы, что позволяет:
При несовпадении версий применяется слой адаптации, который преобразует данные в актуальный формат.
Для масштабируемости используется курсорная модель синхронизации. Вместо запроса «всех изменений» клиент хранит cursor — позицию в глобальном журнале сервера.
Сервер возвращает изменения, начиная с этого cursor, что позволяет:
Локальная база Dexie.js функционирует автономно, даже при отсутствии соединения. Все операции продолжают записываться в журнал, а синхронизация откладывается до восстановления связи.
При длительном оффлайне возможно накопление большого количества операций, поэтому протокол поддерживает:
Каждая операция после успешного применения на сервере получает acknowledgement (ACK), который включает:
Клиент использует ACK для очистки локального журнала и фиксации синхронизированного состояния.
Если ACK не получен, операция остаётся в очереди и будет повторно отправлена.
Система строится на модели eventual consistency, где локальные и серверные данные могут временно расходиться, но гарантированно сходятся после завершения обмена изменениями.
Достижение согласованности обеспечивается:
Для уменьшения нагрузки протокол использует:
Также применяется адаптивная частота синхронизации в зависимости от активности пользователя.
Хотя протокол ориентирован на данные, он включает механизмы защиты:
Каждая операция проверяется не только по структуре, но и по разрешениям текущего пользователя.
В совокупности протокол синхронизации формирует модель, где:
Такая архитектура позволяет строить распределённые приложения на базе Dexie Cloud без необходимости вручную управлять синхронизацией состояния и сетевой логикой.