Internal
Public Access
Backfill data missed by devices with a pre-tag-sync token
/api/sync/ only returns rows changed since a device's last sync token. Any device that synced before tag/time-entry syncing existed already has a token from that era; pre-existing tags untouched since then were never "changed since" that token and so were permanently invisible to that device, even after tag syncing shipped. Adds a sync_format_version check that ignores the stored token and forces exactly one full resync per device when it detects an old-format token, backfilling anything that was missed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
3fbab2b831
commit
373bfe6a6e
@@ -7,6 +7,15 @@
|
||||
|
||||
const BACKGROUND_SYNC_MIN_INTERVAL_MS = 2 * 60 * 1000;
|
||||
|
||||
// Bump this whenever a previously-untracked entity type starts being synced
|
||||
// (e.g. tags/time_entries were added after tasks-only syncing already
|
||||
// shipped). /api/sync/ only returns rows changed since a device's last sync
|
||||
// token, so any device with an old token would otherwise never receive
|
||||
// pre-existing rows of the newly-tracked type - they were never "changed
|
||||
// since" a token issued before that type existed at all. Forces exactly one
|
||||
// full resync (by clearing the stored token) per bump, per device.
|
||||
const SYNC_FORMAT_VERSION = 2;
|
||||
|
||||
function getCsrfToken() {
|
||||
const el = document.querySelector('[name=csrfmiddlewaretoken]');
|
||||
return el ? el.value : null;
|
||||
@@ -103,7 +112,9 @@ async function runBackgroundSync() {
|
||||
}
|
||||
|
||||
const deviceId = await ensureDeviceId();
|
||||
const lastSyncToken = await getMeta('last_sync_token');
|
||||
const syncFormatVersion = await getMeta('sync_format_version');
|
||||
const forceFullResync = (syncFormatVersion || 1) < SYNC_FORMAT_VERSION;
|
||||
const lastSyncToken = forceFullResync ? null : await getMeta('last_sync_token');
|
||||
|
||||
const dirtyTasks = await getDirtyTasks();
|
||||
const dirtyTags = await getDirtyTags();
|
||||
@@ -154,8 +165,12 @@ async function runBackgroundSync() {
|
||||
|
||||
await setMeta('last_sync_token', data.sync_token);
|
||||
await setMeta('last_sync_at', new Date().toISOString());
|
||||
await setMeta('sync_format_version', SYNC_FORMAT_VERSION);
|
||||
|
||||
return hadPendingChanges;
|
||||
// A forced full resync just backfilled previously-missed data (e.g. tags
|
||||
// that existed before tag syncing shipped) - worth a refresh even if
|
||||
// nothing local was dirty, since the current page may be missing it too.
|
||||
return hadPendingChanges || forceFullResync;
|
||||
}
|
||||
|
||||
async function maybeBackgroundSync() {
|
||||
|
||||
Reference in New Issue
Block a user