Repository navigation
fix: [SDK-5314] JWT - drop the Identity Verification beta queues and limit cached queue - #1758
Merged
Merged
Conversation
nan-li
marked this pull request as ready for review
September 24, 2026 16:36
…cached queue blobs
Collaborator
|
Potential issues:
|
abdulraqeeb33
requested changes
Oct 5, 2026
abdulraqeeb33
left a comment
Contributor
There was a problem hiding this comment.
Two places removeValueForKey deletes a blob the rest of this helper would have kept.
- Unarchive
@catchruns for every caller, including the identity model store. Gate that remove onmaxBytes > 0. - The 4 MB write branch should return without removing, same as archive failure.
The beta cache test class sat between the note and RemoteDisableOptedInTests.
The queue reads are the ones that self-heal by deletion. An uncapped read is a model store or a cache that owns its key, so a blob that is not archived data or raises on decode is now logged and left in place unless maxBytes is set.
…alues A queue between the 1 MB read cap and the 4 MB write limit was saved, then dropped at the next launch. The write path now refuses the same 1 MB, and still removes the previous blob: a queue that large is the bloat the read cap drops, and an older blob left under the key would resend the Requests it held. The beta cache test writes its oversized archive directly, since the save path refuses it now.
A cached user with no onesignal_id has nothing left to create it once its queue is dropped as oversized or undecodable, or when a 5.3.0-beta build parked the Request under a key start() now removes. A login as the same user is a no-op, so the device stayed unreachable until a logout. The user executor now queues a Create User at start unless a Create User, Fetch Identity By Subscription or Identify User for that model is already queued. Under Identity Verification the Request parks and asks the app for a token; an anonymous cached user is left alone there, since it is never created.
Contributor
Author
|
fadi-george
approved these changes
Oct 6, 2026
abdulraqeeb33
requested changes
Oct 6, 2026
abdulraqeeb33
left a comment
Contributor
There was a problem hiding this comment.
Read-path gate is done. The write wipe stays.
One remaining: recovery reads live _user on the executor queue. Path 2/3 can publish a new user before their append, so this block can enqueue a second Create User. Snapshot the Path 1 user in init.
The recovery read the live user on the executor queue. Path 2 and 3 of start() set a new user before their own Request is appended, so a block that ran in between queued a second Create User on a fresh start, or one ahead of a legacy player's Fetch Identity By Subscription. The user is now captured in init, where it can only be the one Path 1 loaded, and the queue check still runs on the executor queue after the transfer migration so a migrated Create User is seen. Two tests pin the fresh-start and legacy-player paths.
abdulraqeeb33
approved these changes
Oct 6, 2026
abdulraqeeb33
left a comment
Contributor
There was a problem hiding this comment.
Done in 5498904. Recovery now takes the Path 1 user captured in init. Nil means Path 2/3, and it returns before any async work.
nan-li
added a commit
that referenced
this pull request
Oct 7, 2026
OneSignalUserManagerImpl.swift reached 1003 lines once #1758 landed on 5.8-main, over SwiftLint's 1000-line file_length error, so every PR against the branch failed the lint job. The helper moves to OneSignalUserManagerImpl+Jwt.swift with the rest of the Identity Verification surface and start() still calls it. No behavior change.
9 of 18 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
One Line Summary
Remove the 5.3.0-beta pending-auth queues at start, cap cached values, make UserDefaults archiving exception-safe, and re-create a cached user whose Create User was lost. SDK-5314.
Details
Motivation
Devices upgrading from the 5.3.0-beta line carry five
*_PENDING_QUEUE_KEYblobs that this branch never reads, and on affected devices those blobs and the regular queue keys are large. Archiving or writing an oversized queue is what crashes the beta today, and the UserDefaults helper here would crash the same way on an unarchivable or oversized value. A device whose only Create User sat in one of those blobs has anexternal_idand noonesignal_id, and nothing in the SDK would ever create it.Scope
OneSignalUserManagerImpl.start()removes the five beta pending keys before the executors read their caches. Their names return toOneSignalCommonDefines.hasOS_IV_BETA_*.OS_USER_DEFAULTS_MAX_VALUE_BYTES, the same limit the write side applies. A larger blob is removed and logged, not decoded. The one-time transfer-subscription migration read is left as is.OneSignalUserDefaultscatches exceptions from archiving and unarchiving instead of raising into the host app. A blob that is not archived data or cannot be decoded is logged and the default returned; a capped read also removes it, an uncapped read leaves it to the module that wrote it. A nil decode is treated like a missing key. A value that cannot be archived leaves the previous blob in place. A value whose archive is larger than 1 MB is not written and the key is removed: nothing the SDK caches is legitimately that large, and a previous blob left under the key would resend the Requests it held, which is the symptom this PR exists to stop. CFPreferences rejects values of 4 MB and more anyway.OSUserExecutorqueues a Create User at start for a cached user that has noonesignal_idwhen nothing queued will supply one. The beta parked the only copy of that Request under a key this PR removes, and an oversized or undecodable queue loses it too; without this the device stays unreachable, since aloginas the same user is a no-op. Under Identity Verification the Create User parks and asks the app for a token like any other; an anonymous cached user is left alone there, since it is never created. The recovery sees only the userstart()loaded from the cache, captured when the executor is created, so a user that a login or a legacy-player migration sets up during the same start is not re-created.Testing
Unit testing
Seven tests in
OneSignalCoreTestscover a real archive over the cap, a blob within the cap, an unreadable blob, an unarchivable value leaving the cached value in place, a value over the limit taking the previous blob with it, and blobs that are not archived data or cannot be decoded being removed only by a capped read. One test inOneSignalUserTestsseeds all five beta keys plus a real archive over the cap under the update key, written directly since the save path now refuses it, drivesstart(), and asserts the keys are gone and the queue is empty. Without the cap that archive decodes to strings, fails the cast and leaves the key as is, so the test fails.CachedUserWithoutAnIdTestscovers the re-created Create User: an identified and an anonymous cached user with the requirement off, no duplicate when the Create User is still queued, the token ask and the signed Create User with the requirement on, and an anonymous cached user left alone under it. A fresh start still sends exactly one Create User and a legacy-player start queues none.Manual testing
OneSignalCoreTestsandOneSignalUserTestsrun on an iPhone 17 Pro simulator (iOS 26.5), and the full Reduced test plan ran on this branch merged with 5.8-main at 630b355, 597 tests with no failures. The dev app from the first revision of this branch installed over 5.3.0-beta-03 state with 8 parked Requests: the two beta keys present on that device removed at start, no crash, Requests held until a token arrives. The bug-bash run of 5 October reproduced the lost Create User on that upgrade path (scenario 12.3 in the test doc); the re-created Create User is covered by unit tests only so far. Not run on a device.Affected code checklist
Checklist
Overview
Testing
Final pass
🤖 Generated with Claude Code