iOS: wait for Fabric to settle before triggering immediate bundle reload - #29
Draft
ofalvai wants to merge 1 commit into
Draft
iOS: wait for Fabric to settle before triggering immediate bundle reload#29ofalvai wants to merge 1 commit into
ofalvai wants to merge 1 commit into
Conversation
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.
Why
Somewhat related to #28, but this is a different kind of race condition and crash.
The immediate update mode needs to reload the JS bundle at a point when the JS runtime and Fabric are already running. This leads to race conditions and crashes in certain cases.
Much more detailed LLM summary
The crash
EXC_BAD_ACCESS/SIGSEGV, intermittent, hit almost exclusively on CI (rarely reproduces locally). It happens right after anIMMEDIATE-mode install triggers a restart.Root cause
-[CodePush loadBundle]callsRCTTriggerReloadCommandListenersto tear down and rebuild theRCTInstance. Under the new architecture (RN 0.86), right after the JS bundle finishes evaluating, RN separately enqueues-[RCTFabricSurface start]on a background queue for that same instance. If the reload tears the instance down while that block is still in flight, it crashes inside RN's Fabric mounting layer.The window between "bundle finished evaluating" and "Fabric surface start block finishes" is normally sub-millisecond, so it rarely gets hit. Under load — CI simulators being the textbook case — it stretches to tens of milliseconds, which is enough to make the race land often enough to be a recurring CI failure, while staying hard to reproduce on a local machine.
localPackage.installcode paths usingInstallMode.IMMEDIATEare the ones exposed to this: they callrestartApp()from JS almost immediately after the new bundle starts running, right when this window is open.Note: I'm aware of at least one more race condition and crash, this PR is not supposed to fix all of them, follow-up PRs are coming.
What
Wait for Fabric and rendering to settle before reloading the bundle (
RCTTriggerReloadCommandListeners). This is achieved with a little state machine (I know,CodePush.mhas too many state machines already...) that parks the pending update until we get the signal or a 5-second timer fires (see code comments why this fallback is needed)Also, spotted that
_restartQueuewas incorrectly read:[_restartQueue valueForKey: @"@firstObject"]is not valid KVC syntax and was returning junk data (ask your Claude why, it's funny)