Skip to content

Run the account's loop on its own thread so iCloud calls stop queueing behind fetches - #273

Open
lazzurs wants to merge 3 commits into
parawanderer:mainfrom
lazzurs:fix/126-drive-the-account-loop-from-its-own-thread
Open

lazzurs wants to merge 3 commits into
parawanderer:mainfrom
lazzurs:fix/126-drive-the-account-loop-from-its-own-thread

Conversation

@lazzurs

@lazzurs lazzurs commented Oct 20, 2026

Copy link
Copy Markdown

Fixes #126.

Problem

Every call into Python held PythonLock, because FindMy.py's sync AppleAccount enters its event loop per call with run_until_complete. A first import walks thousands of key indices inside a single fetch_location, so opening the iCloud screen during one meant waiting minutes.

Change

  • app/src/main/python/account_loop.py (new): attach(account) replaces _evt_loop with a stand-in that submits coroutines to the real loop, which runs forever on its own thread. Same loop, session and identity.
  • The account is still used by one operation at a time. request_pet (called when a keychain session opens) swaps the login state across a GSA round trip, so a report request running beside it would read a missing dsid. Ordinary calls hold the account's turn for their whole length; location fetches run inside interleaving() and take the turn once per fetch_raw_reports. An iCloud step therefore waits for at most one request.
  • main.py attaches on sign-in and restore, detaches in closeAccount, and wraps the two fetch call sites in interleaving(). An account dropped without being closed stops its thread via a finaliser.
  • attach degrades rather than raising: if the pinned FindMy.py ever stops exposing fetch_raw_reports or _evt_loop, the account still gets its thread (fetches then take whole turns) or is left as it was.
  • icloud_bridge.openSession refuses an account whose loop is not attached. The iCloud test double and OpeningARealICloudSessionTest attach their accounts.
  • PythonICloudService and FetchFromICloudActivity no longer take PythonLock. Location fetches still take it against each other.
  • Removed icloud_loading_waiting_for_location_check from all locales with scripts/add_strings.py --remove; that wait no longer exists.
  • AGENTS.md rule 21 documents the constraint.

Testing

🤖 Generated with Claude Code

Rob Lazzurs and others added 3 commits October 16, 2026 21:31
…g behind fetches

Every call into Python was serialised behind PythonLock because FindMy.py's sync
AppleAccount enters its event loop per call with run_until_complete. A first import
walks thousands of key indices inside a single fetch_location, so the iCloud screen
waited minutes for its turn (parawanderer#126).

account_loop.attach now swaps the account's _evt_loop for a stand-in that hands
coroutines to the real loop, running forever on a thread of its own. Same loop,
same session, same identity.

The account is still used by one operation at a time: request_pet swaps the login
state out across a GSA round trip, so a report request running beside it would read
a missing dsid. Ordinary calls take the account's turn for their whole length; a
location fetch inside interleaving() takes it once per fetch_raw_reports, so an
iCloud step waits for one request rather than the whole walk.

PythonICloudService no longer takes PythonLock. Location fetches still do, against
each other. The "waiting for the location check" caption is gone with the wait it
described.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A failed sign-in or an abandoned code screen never reaches closeAccount. That used
to cost two sockets until the collector ran; with the loop on its own thread it
would also leave a thread idling forever. A finaliser on the account now lets
whatever is already on the loop finish - including the close FindMy.py's own
finaliser schedules - and then stops the thread.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…aise

The emulator suite's two iCloud bridge classes built accounts with a bare event
loop, which openSession now refuses. They attach it the way main does.

attach no longer assumes fetch_raw_reports exists or that the account can be
weakly referenced. Without the method the loop still gets its thread and a fetch
inside interleaving() takes one whole turn, as before; an exception there would
fail the restore and sign the user out.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
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.

iCloud calls queue behind a location fetch, because the shared loop is driven synchronously

1 participant