Skip to content

fix: keep Keystore work off the SDK init thread - #937

Draft
mahmoud-elmorabea wants to merge 12 commits into
mainfrom
mbl-2619-async-userid-save
Draft

mahmoud-elmorabea wants to merge 12 commits into
mainfrom
mbl-2619-async-userid-save

Conversation

@mahmoud-elmorabea

Copy link
Copy Markdown
Contributor

Moves the Keystore work at SDK init off the caller's thread, so an identified cold start can't ANR on a slow or stalled Keystore, while modules still get the userId only after it is saved encrypted.

🤖 Generated with Claude Code

mahmoud-elmorabea and others added 8 commits October 19, 2026 16:19
Init encrypted the persisted userId on the caller's thread, so a slow or
stalled Keystore could ANR an identified cold start. The save now runs in
the background and UserChangedEvent is published once it lands, so every
module still finds the userId on disk when notified. A version counter
orders it against identify and clearIdentify; a same-user identify skips
the Keystore and publishes after the pending write. In-app polling waits
for an identity instead of fetching without a user token.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The restore decrypted the cached location on the caller's thread during
initialize(). It now runs on the location scope; identify context, the
UserChangedEvent handler and getLastKnownLocation wait for it off main.
A restore that lands after a newer fix or a sign-out leaves state alone.

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

These scopes block on disk and Keystore calls. On Default, which has as
many threads as the device has cores (2 on low-end devices), a slow
Keystore in geofence or location work stalled event delivery for every
module, including the push and in-app metrics carried by the bus.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When foreground polling was skipped for lack of identity, the
identification-change path and the UserChangedEvent fetch both started
polling, sending two fetches. The identification-change path now leaves
the start to the identity fetch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The bus forwarded with tryEmit, which fails once the slowest subscriber
is a full replay buffer behind, losing the event for every subscriber,
metrics included. emit suspends the forwarder instead; the unlimited
channel holds what is published meanwhile.

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

resetContext cleared the persisted location after releasing its lock, so
a restore could still read the signed-out user's location. The identify
handler now waits for the restore in its own coroutine, not in the bus
collector.

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

github-actions Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Sample app builds 📱

Below you will find the list of the latest versions of the sample apps. It's recommended to always download the latest builds of the sample apps to accurately test the pull request.


  • java_layout: mbl-2619-async-userid-save (1792435533)
  • kotlin_compose: mbl-2619-async-userid-save (1792435533)

Commit e495b5f · CI run

@codecov

codecov Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.71429% with 16 lines in your changes missing coverage. Please review.
✅ Project coverage is 74.58%. Comparing base (b5cf24d) to head (e495b5f).
⚠️ Report is 69 commits behind head on main.

Files with missing lines Patch % Lines
...main/kotlin/io/customer/location/ModuleLocation.kt 0.00% 7 Missing ⚠️
...lin/io/customer/sdk/core/di/AndroidSDKComponent.kt 0.00% 2 Missing and 1 partial ⚠️
...tlin/io/customer/sdk/data/store/SecureUserStore.kt 94.33% 2 Missing and 1 partial ⚠️
...ain/kotlin/io/customer/location/LocationTracker.kt 93.54% 0 Missing and 2 partials ⚠️
...otlin/io/customer/location/LocationServicesImpl.kt 0.00% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main     #937      +/-   ##
============================================
+ Coverage     69.07%   74.58%   +5.51%     
- Complexity      838     2412    +1574     
============================================
  Files           149      282     +133     
  Lines          4601    13429    +8828     
  Branches        628     2297    +1669     
============================================
+ Hits           3178    10016    +6838     
- Misses         1189     2606    +1417     
- Partials        234      807     +573     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions

Copy link
Copy Markdown

Build available to test
Version: mbl-2619-async-userid-save-SNAPSHOT
Repository: https://central.sonatype.com/repository/maven-snapshots/

@github-actions

github-actions Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

📏 SDK Binary Size Comparison Report

Module Last Recorded Size Current Size Change in Size
core 49.52 KB 52.27 KB ⬆️ +2.75KB
datapipelines 42.70 KB 43.32 KB ⬆️ +0.62KB
messagingpush 75.18 KB 75.18 KB ✅ No Change
messaginginapp 165.14 KB 165.06 KB ⬇️ -0.08KB
messaginginbox 61.19 KB 61.19 KB ✅ No Change
tracking-migration 22.89 KB 22.89 KB ✅ No Change
location 20.40 KB 23.07 KB ⬆️ +2.67KB
geofence 225.77 KB 225.77 KB ✅ No Change

mahmoud-elmorabea and others added 4 commits October 19, 2026 17:26
…e on Error

Modules built against the one-argument saveUserId keep linking when an
app mixes module versions. A background write whose encryption throws an
Error now takes the same plaintext fallback PreferenceCrypto uses for
exceptions, so the write lands and its callbacks are never stranded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Readers waited up to 30 s again on every call while a stalled restore was
running: each identify and each geofence anchor read. The 30 s now runs
from the start of the restore, shared by all readers.

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

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A background init write still inside the Keystore when clearInstance resets the
SDK could land afterwards and store the old user. Reset now invalidates the
pending write and its callbacks and stops the store's writer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.

1 participant