From 8a8a5d598ebc2c51800641a65862fd905cd1267a Mon Sep 17 00:00:00 2001 From: Jason Volk Date: Tue, 5 Aug 2025 09:28:02 +0000 Subject: [PATCH] Fix sync loop watcher ABA. Signed-off-by: Jason Volk --- src/api/client/sync/v3.rs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/api/client/sync/v3.rs b/src/api/client/sync/v3.rs index 1dd9c2d1..e16d0c6b 100644 --- a/src/api/client/sync/v3.rs +++ b/src/api/client/sync/v3.rs @@ -156,10 +156,12 @@ pub(crate) async fn sync_events_route( .checked_add(Duration::from_millis(timeout)) .expect("configuration must limit maximum timeout"); - let mut next_batch = services.globals.current_count(); loop { // Listen for activity let watchers = services.sync.watch(sender_user, sender_device); + let next_batch = services.globals.wait_pending().await?; + + debug_assert!(since <= next_batch, "next_batch is monotonic"); if since < next_batch || body.body.full_state { // Check for activity let response = build_sync_events(&services, &body, since, next_batch).await?; @@ -176,7 +178,8 @@ pub(crate) async fn sync_events_route( // Wait for activity if time::timeout_at(stop_at, watchers).await.is_err() { - break; + trace!(next_batch, "empty response"); + return Ok(sync_events::v3::Response::new(next_batch.to_string())); } trace!( @@ -184,16 +187,9 @@ pub(crate) async fn sync_events_route( last_batch = ?next_batch, count = ?services.globals.pending_count(), stop_at = ?stop_at, - "waited for watchers" + "notified by watcher" ); - - // Synchronize activity - next_batch = services.globals.wait_pending().await?; - debug_assert!(since <= next_batch, "next_batch is monotonic"); } - - trace!(next_batch, "empty response"); - return Ok(sync_events::v3::Response::new(next_batch.to_string())); } #[tracing::instrument(