Skip to content

[Fix] Prevent deadlocks when user manager runs its startup tasks #1559

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

nan-li
Copy link
Contributor

@nan-li nan-li commented May 12, 2025

Description

One Line Summary

Prevent deadlocks in the user module after making synchronization changes.

Details

Motivation

Scope

  • When the SDK is upgraded, an sdk version change is detected in the start() method which triggers the model > store > listener flow. Eventually, it was triggering the start() method again, resulting in a deadlock.
  • The changes made are that the model store minimize amount of locking needed (no reported issues for this but this change is made as an improvement)
  • The second set of changes are falling to more no-ops if there is no user instance to operate on, rather than triggering start() to generate a user instance. Currently, only the properties model and subscription model may have update enqueued at the end of the start() method to enqueue any changes such as timezone and app version for the user instance, which exists by this point. The other no-op refactors are for safety / improvement.

Testing

Unit testing

None

Manual testing

iPhone 13 on iOS 18.4.1
Tested version upgrade, timezone upgrade, other normal flows

Affected code checklist

  • Notifications
    • Display
    • Open
    • Push Processing
    • Confirm Deliveries
  • Outcomes
  • Sessions
  • In-App Messaging
  • REST API requests
  • Public API changes

Checklist

Overview

  • I have filled out all REQUIRED sections above
  • PR does one thing
  • Any Public API changes are explained in the PR details and conform to existing APIs

Testing

  • I have included test coverage for these changes, or explained why they are not needed
  • All automated tests pass, or I explained why that is not possible
  • I have personally tested this on my device, or explained why that is not possible

Final pass

  • Code is as readable as possible.
  • I have reviewed this PR myself, ensuring it meets each checklist item

This change is Reviewable

nan-li added 2 commits May 12, 2025 13:14
Only lock when reading and writing from the dictionary, to minimize amount of locking when unnecessary
*Calling the `user` property of the `OneSignalUserManagerImpl` will return a mock user, the user instance, or call start().
* In some methods, if there is no user instance, don't trigger a start() call, to prevent deadlocks if these methods are called by start() itself.
* Currently, only the properties model and subscription model may have update enqueued at the end of the start() method to enqueue any changes such as timezone and app version for the user instance, which exists by this point.
* The other refactors are for safety.
@nan-li nan-li requested a review from jinliu9508 May 13, 2025 19:19
@nan-li nan-li force-pushed the fix/user_module_deadlocks branch from 1329bd1 to 96abd8b Compare May 13, 2025 19:37
@nan-li nan-li requested review from jkasten2 and jinliu9508 May 15, 2025 19:04
@nan-li
Copy link
Contributor Author

nan-li commented May 15, 2025

Admittedly, these gotchas and details to watch out for are getting a bit gnarly. The user module can definitely benefit from some debt refactoring work.

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.

2 participants