From 988aec15e7076de97d069d44f08ad93107800bc9 Mon Sep 17 00:00:00 2001 From: Mark Hammond Date: Fri, 7 Aug 2026 23:53:01 +1000 Subject: [PATCH] sync-manager no longer queues syncs. There's no need or use-case for syncs queuing up. Any "immediate" requests are time-sensitive, and the chance of a conflict is small. --- CHANGELOG.md | 4 +++ components/sync_manager/src/error.rs | 2 ++ components/sync_manager/src/manager.rs | 39 ++++++++++++++++++++- components/sync_manager/src/syncmanager.udl | 1 + 4 files changed, 45 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 72d3a94a623..f876e4d29fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,10 @@ - Verify signature of imported data when `.get()` is called with `sync_if_empty: true` ([#7518](https://github.com/mozilla/application-services/pull/7518)) - Do not quote `_since` values with the v2 API ([#7523](https://github.com/mozilla/application-services/pull/7523)) +### Sync Manager + +- `SyncManager::sync()` now fails immediately with a new `SyncManagerError::Busy` when a sync is already in progress, instead of blocking until it finishes. + # v154.0 (_2026-07-20_) ## ✨ What's Changed ✨ diff --git a/components/sync_manager/src/error.rs b/components/sync_manager/src/error.rs index c42c9ca321f..e40ef58059a 100644 --- a/components/sync_manager/src/error.rs +++ b/components/sync_manager/src/error.rs @@ -10,6 +10,8 @@ pub enum SyncManagerError { UnknownEngine(String), #[error("Manager was compiled without support for {0:?}")] UnsupportedFeature(String), + #[error("Another sync is already in progress")] + Busy, // Used for things like 'failed to decode the provided sync key because it's // completely the wrong format', etc. #[error("Sync error: {0}")] diff --git a/components/sync_manager/src/manager.rs b/components/sync_manager/src/manager.rs index 5dddb794e73..15c5f4a9c2f 100644 --- a/components/sync_manager/src/manager.rs +++ b/components/sync_manager/src/manager.rs @@ -83,9 +83,14 @@ impl SyncManager { } /// Perform a sync. See [SyncParams] and [SyncResult] for details on how this works + /// + /// Fails with [SyncManagerError::Busy] if a sync is already in progress. pub fn sync(&self, params: SyncParams) -> Result { breadcrumb!("SyncManager::sync started"); - let mut state = self.mem_cached_state.lock(); + let Some(mut state) = self.mem_cached_state.try_lock() else { + breadcrumb!("SyncManager::sync is already in progress, bailing out early"); + return Err(SyncManagerError::Busy); + }; let engines = self.calc_engines_to_sync(¶ms.engines)?; let next_sync_after = state.as_ref().and_then(|mcs| mcs.get_next_sync_after()); let result = if !backoff_in_effect(next_sync_after, ¶ms) { @@ -312,6 +317,7 @@ impl CommandProcessor for SyncClient { #[cfg(test)] mod test { use super::*; + use crate::types::{DeviceSettings, SyncAuthInfo}; #[test] fn test_engine_id_sanity() { @@ -319,4 +325,35 @@ mod test { assert_eq!(engine_id, SyncEngineId::try_from(engine_id.name()).unwrap()); } } + + fn dummy_sync_params() -> SyncParams { + SyncParams { + reason: SyncReason::Scheduled, + engines: SyncEngineSelection::All, + enabled_changes: HashMap::new(), + local_encryption_keys: HashMap::new(), + auth_info: SyncAuthInfo { + kid: "kid".to_string(), + fxa_access_token: "token".to_string(), + sync_key: "sync-key".to_string(), + tokenserver_url: "https://example.com/token/1.0/sync/1.5".to_string(), + }, + persisted_state: None, + device_settings: DeviceSettings { + fxa_device_id: "device-id".to_string(), + name: "Test Device".to_string(), + kind: sync15::DeviceType::Mobile, + }, + } + } + + #[test] + fn test_sync_is_busy_while_a_sync_is_in_progress() { + let manager = SyncManager::new(); + let _in_progress = manager.mem_cached_state.lock(); + assert!(matches!( + manager.sync(dummy_sync_params()), + Err(SyncManagerError::Busy) + )); + } } diff --git a/components/sync_manager/src/syncmanager.udl b/components/sync_manager/src/syncmanager.udl index e3ee2d4be18..ad94cdd1e38 100644 --- a/components/sync_manager/src/syncmanager.udl +++ b/components/sync_manager/src/syncmanager.udl @@ -11,6 +11,7 @@ namespace syncmanager { }; enum SyncManagerError { "UnknownEngine", "UnsupportedFeature", + "Busy", "Sync15Error", "UrlParseError", "InterruptedError",