Provider Lanes Need Account Scope
Provider lanes need account scope
When a local daemon wraps a remote provider, "background" and "foreground"
are not enough. The useful boundary is often the provider account.
A sync loop, a manual sync, and an archive mutation may enter through different
commands, but they all touch the same upstream account state. If they run
through the provider at the same time, they can race. If one gets stuck, the
others can wait forever. If the lock is global, a broken account can punish a
healthy one.
The rule
Serialize provider work at the smallest provider-truth boundary.
For email, that boundary is the account. A background sync for personal and
an archive mutation for personal should share a lane. A broken consulting
account should not block personal.
The shape
- One lane per provider account, not one lane for the whole daemon.
- Background sync, manual sync, and provider-backed mutations use the same lane.
- Provider calls have timeouts, so a stuck network operation releases the lane.
- Runtime status records whether the operation completed, failed, or timed out.
- Post-sync fanout does not live in the lane. Semantic ingest, contact refresh,
relationship updates, rules, and analytics can queue elsewhere.
The lane protects provider truth. It is not a general-purpose background-work
queue.
Mxr example
In Mxr v0.5.61, AppState::acquire_provider_operation creates a
per-account tokio::sync::Mutex. The background sync loop, manual mxr sync,
and mail mutations all acquire it before provider work.
The important details are boring and load-bearing:
- background sync and manual sync time out after 10 minutes
- each provider mutation call times out after 60 seconds
- Gmail HTTP requests time out after 60 seconds
sync_in_progressis cleared on timeout- different accounts have different provider locks
That fixed the shape where opening mxr could start sync, stale provider work
could wedge the account, and later archive/read mutations appeared to work
locally before provider truth brought the messages back.
2026-06-24 validation found the late edge worth remembering: snooze restore is
provider work too. It may be triggered by time instead of a fresh user command,
but it still mutates upstream account state and must use the same account lane.
Where this generalizes
Any local-first client with remote providers hits this eventually: mail,
calendars, music, issue trackers, cloud storage, CRM sync, anything with a
local cache and upstream mutations.
The question is not "should I add a lock?" The better question is "what remote
truth is this operation allowed to monopolize?" Scope the lane there, put a
timeout around it, and keep unrelated accounts or workspaces out of the blast
radius.
Code grounding
Validated against Mxr v0.5.61:
crates/daemon/src/state.rsownsacquire_provider_operation.crates/daemon/src/loops.rsuses it for background sync.crates/daemon/src/handler/diagnostics/mod.rsuses it for manual sync.crates/daemon/src/handler/mutations.rsuses it for provider mutations.crates/provider-gmail/src/client.rssets the Gmail HTTP timeout.