Skip to content

Refresh conversations in the background so they are not stale when the app is opened - #6745

Draft
AndyScherzinger wants to merge 3 commits into
feat/noid/conversation-list-delta-syncfrom
feat/noid/conversation-list-background-sync
Draft

AndyScherzinger wants to merge 3 commits into
feat/noid/conversation-list-delta-syncfrom
feat/noid/conversation-list-background-sync

Conversation

@AndyScherzinger

@AndyScherzinger AndyScherzinger commented Sep 21, 2026

Copy link
Copy Markdown
Member

Stacked on #6744 — review that one first. This PR targets its branch, so its commits appear here until it merges.

A backgrounded app learns nothing about its conversations until a push arrives. Where push is disabled, unavailable, or simply does not turn up, the list, the unread counts and the cached messages stay as they were until the user opens the app. This adds the periodic background refresh iOS has had all along.

What it does

  • A suspend sync entry point on the repository that completes when the sync and its message catch-up are done. The existing getRooms launches into the repository's own scope and returns immediately, which is what the list wants and what a worker cannot use — WorkManager tears the process down the moment the worker returns.
  • ConversationsSyncWorker, a 15-minute periodic worker, syncing every configured account one after another rather than at once.
  • Stands down in battery saver and while the app is in the foreground, where the list refreshes itself.

What a reviewer should push back on

  • It bounds staleness, it does not deliver immediacy. WorkManager's period floor is 15 minutes and Doze defers further, so this is coarser than the iOS background refresh it mirrors.
  • No isOnline pre-check, deliberately — the connectivity flow is frozen in a process with no UI collector, which is what silently disabled the message prefetch before (fix(chat): make the push message prefetch actually run on a flaky connection #6727). Reachability is the work request's NetworkType.CONNECTED constraint.
  • All accounts per wake-up, uncapped. Marked with a ponytail: comment naming the ceiling. The delta sync from Ask the server only for the conversations that changed #6744 is what makes this affordable; cap the run and take the stalest accounts first if request volume ever shows it.

Not in this PR

  • The foreground refresh loop while the list is open — stacked on top of this branch.
  • The notification-existence check and offline-message resend that iOS also does on its background task.

🚧 TODO

  • Manual check: three accounts, confirm one wake-up does not burst requests
  • Overnight battery attribution run

🏁 Checklist

  • ⛑️ Tests (unit and/or integration) are included or not needed
  • 🔖 Capability is checked or not needed
  • 🔙 Backport requests are created or not needed: /backport to stable-xx.x
  • 📅 Milestone is set
  • 🌸 PR title is meaningful (if it should be in the changelog: is it meaningful to users?)

🤖 AI (if applicable)

  • The content of this PR was partly or fully generated using AI

getRooms launches into the repository's own scope and returns straight
away, which is what the conversation list wants and what a background
worker cannot use: WorkManager tears the process down the moment the
worker returns, and the sync would be cut off mid-request.

Add a suspend entry point that completes when the sync and the message
catch-up it triggers are done. The catch-up is launched detached on the
existing path and awaited on this one, so a worker cannot report success
for messages it never fetched.

It deliberately leaves the observed account alone. That selects what the
conversation list screen shows, and a worker walking several accounts in
one run must not move it.

Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
A backgrounded app learns nothing about its conversations until a push
arrives. Where push is disabled, unavailable or simply does not turn up,
that means the list, the unread counts and the cached messages stay as
they were until the user opens the app.

Add a periodic worker that runs the conversation list sync and its
message catch-up for every configured account. Accounts are synced one
after another rather than at once, because each fans out into its own
bounded set of message requests and running them together multiplies
that into a burst on a single wake-up.

It stands down in battery saver and while the app is in the foreground,
where the list refreshes itself, and leaves reachability to the work
request's network constraint - the connectivity flow is frozen in a
process with no UI collector, and pre-checking it there is what silently
disabled the message prefetch before.

WorkManager's period floor is 15 minutes and Doze defers it further, so
this bounds staleness rather than delivering immediacy. Scheduling keeps
an existing run instead of replacing it, so an app opened often still
reaches one.

The battery saver check would have been copied a third time here, so it
moves to a Context extension the repository and both workers share. The
worker's decision is kept apart from doWork, which reaches for the
application singleton to inject itself and can therefore not be driven
from a unit test.

Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
What is worth pinning down about a background worker is when it stands
down and how many accounts it touches when it does not: a guard that
quietly stops working is invisible until it turns up as battery drain or
request volume, long after the change that broke it.

Covers battery saver standing the run down without reading a single
account, every configured account being synced rather than only the
current one, a failed account asking for another attempt while its
neighbours still sync, the attempt cap ending the retries, and an
account lookup that throws being survivable.

Unit tests gain the WorkManager testing artifact, which was available to
instrumented tests only.

Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
@AndyScherzinger
AndyScherzinger force-pushed the feat/noid/conversation-list-delta-sync branch from bb53fe7 to c0b96dd Compare September 21, 2026 20:23
@AndyScherzinger
AndyScherzinger force-pushed the feat/noid/conversation-list-background-sync branch from abc0d72 to 7d19a5c Compare September 21, 2026 20:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant