Skip to content

Gate the remote-interval poll on a root ETag check (#189) - #190

Merged
gnacho merged 1 commit into
mainfrom
feat/189-etag-gate
Aug 26, 2026
Merged

gnacho merged 1 commit into
mainfrom
feat/189-etag-gate

Conversation

@gnacho

@gnacho gnacho commented Aug 26, 2026

Copy link
Copy Markdown
Owner

Closes #189.

Problem

The periodic remote-interval poll ran a full nextcloudcmd reconciliation of every folder every N minutes regardless of whether anything changed, even after #183/#185 (which only apply when the server offers notify_push). On the large folders this is a full tree re-discovery (tens of thousands of progress events per cycle) - exactly what the user sees as "it keeps syncing even though no files changed". With remote_interval_minutes=10 and no push on the server, Fotos (~65k files), Mi Nube (~16k), Zbox (~11k) re-scan every cycle.

Fix (mirrors the official client)

The official client does a cheap ETag poll before deciding to reconcile: RequestEtagJob is a single PROPFIND with Depth: 0 asking only for <getetag/> (src/libsync/networkjobs.cpp), and Folder::etagRetrieved compares it against _lastEtag; the full sync runs only when the root ETag changed (folder.cpp:426).

Changes:

  • NextcloudApi::root_etag: a PROPFIND Depth:0 for <getetag/> on the folder root (new PROPFIND_ETAG_BODY), returning the trimmed ETag or None.
  • EtagProbe / ProductionEtagProbe (mirrors the HealthProbe pattern from Mark folder offline after N consecutive failed syncs regardless of error class #179), wired in production via with_etag_probe.
  • The engine tracks a per-folder etag_slot (shared Arc<Mutex<Option<String>>>). On a pure RemoteInterval run it reads the root ETag and, if unchanged from the last run, reports a clean SyncOutcome::Success without spawning nextcloudcmd. A changed ETag (or first run / unavailable ETag) reconciles as before.
  • Non-interval triggers (manual, inotify, startup, remote push, network-restored, resume, retry, recovery) always reconcile - etag_gate_applies only accepts a sole RemoteInterval.

Testing

691 tests (6 new), clippy clean, fmt applied.

New tests: root_etag_reads_the_etag_with_depth_zero, root_etag_absent_body_yields_none, parse_root_etag_returns_trimmed_text, unchanged_etag_skips_the_interval_run (asserts nextcloudcmd not spawned), changed_etag_reconciles_the_interval_run, manual_run_ignores_the_etag_gate.

@gnacho
gnacho merged commit 8097055 into main Aug 26, 2026
2 checks passed
@gnacho
gnacho deleted the feat/189-etag-gate branch August 26, 2026 19:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Gate the remote-interval poll on a root ETag check to avoid full re-scans when nothing changed

1 participant