Lessons learned from building a sync-engine and reactivity system with SQLite
Итоги постройки синхронизатора и реактивной системы на SQLite
Первый опыт: PGlite + Electric
- PostgreSQL в WASM + Electric даёт точную синхронизацию и LISTEN-реактивность.
- Недостатки: Electric ещё молод, старт до минуты без компакции; PGlite в single-user-режиме течёт памятью и тормозит при росте БД.
Переосмысление задачи
- SQLite-WASM стал зрелым; моё приложение однопользовательское и почти всегда онлайн.
- Значит, достаточно простого собственного решения.
Минимальный синхронизатор
- При первом запуске клиент вытягивает всё по
updated_at
. - Каждые 2–3 с опрашивает сервер за записями новее этой метки и делает upsert.
- Локально при каждом UPDATE ставится флаг
modified = 1
; фоновый процесс отправляет изменения. - Для текстов можно добавить CRDT (Yjs) на случай конфликтов.
Для отслеживания изменений используется триггер, который игнорируется во время синхронизации через таблицуsync_control
.
Реактивность на SQLite
- SQLite не умеет LISTEN, но:
- Триггер пишет в лог-таблицу пару «таблица + id».
- Broadcast Channel API рассылает это в другие вкладки/воркеры.
- UI подписывается на канал и перечитывает нужные строки.
- Использую wa-sqlite: стабильно, без сбоев с момента установки.
Комментарии (35)
- PGlite и Electric стали отправной точкой, но их ограничения подтолкнули Electric к созданию Tanstack DB — «sync-native» JS-хранилища без привязки к бэкенду.
- Участники советуют готовые решения: Evolu (SQLite + e2e-шифрование), SQLite-Sync, CouchDB, а также CRDT- и Lamport-подходы для разрешения конфликтов.
- Некоторые отказались от SQLite в браузере, хватило простых индексов и событий; другие делятся опытом собственных движков (Thymer, Synchrotron, Reflect).
- Ключевые вопросы: одновременные правки, офлайн, write-heavy нагрузка и надёжная консистентность без распределённых транзакций.
- Общий вывод: для продакшена лучше взять проверенный sync-движок, чем изобретать собственный, но выбор зависит от конкретных ограничений приложения.