fix: Close FDv1 fallback and FDv2 recovery correctness gaps - #1875
Conversation
|
@launchdarkly/js-sdk-common size report |
|
@launchdarkly/js-client-sdk size report |
|
@launchdarkly/browser size report |
|
@launchdarkly/js-client-sdk-common size report |
8a0e71d to
698aa3f
Compare
2b280eb to
29566d1
Compare
276e94f to
18ce666
Compare
e2afce4 to
bee9b26
Compare
aac69f6 to
8c8b2bc
Compare
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 8c8b2bc. Configure here.
ba8623e to
36ba320
Compare
36ba320 to
a7a5773
Compare
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit a7a5773. Configure here.
Summary
Four fixes found reviewing the recovery-timer PR in this stack, before they shipped:
interruptedor a changeSet now still triggers fallback afterinitFallbackTimeoutMs(default 10s), complementing the existing interrupted-based leg.'none'-payload changeSet incorrectly marking the data system initialized, and addshasExistingDataso a post-connection-mode-switch'none'response on an already-initialized system doesn't churn through synchronizers looking for data that was never going to come.SourceManagerleft the active source open when every synchronizer slot was blocked.Note
Overview
Tightens FDv2 data-source orchestration around fallback conditions, FDv1 directives, and what counts as “initialized.”
Uninitialized fallback (10s leg): Before the data system has ever received real data, synchronizer fallback now includes an init-fallback timer (
createInitFallbackCondition, default 10s) that fires even when the source never reportsinterrupted—so a hung primary can still move to the next synchronizer. Real changeSets cancel it;nonepayloads do not.getConditionstakes aninitializedflag andinitFallbackTimeoutMs;FDv2DataSourcewireshasExistingDataso connection-mode rebuilds skip this leg.Initialization semantics: Synchronizer-phase handling no longer calls
markInitialized()ontype: 'none'changeSets unlesshasExistingDatais set (manager passes priorinitializedon rebuild). That stops empty poll/304 responses from falsely completingstart()or disarming the init-fallback leg.FDv1 fallback without an FDv1 slot:
handleFdv1Fallbacknow always halts the current run viasourceManager.fdv1Fallback()when synchronizers exist (setsINTERRUPTEDif no FDv1 slot), instead of ignoring the directive. Recovery TTL is scheduled only once per engagement—repeated directives from a still-running FDv2 source no longer reset the deadline and starve return to FDv2.Resource cleanup:
SourceManagercloses the active synchronizer when every slot is blocked, so transports are not left running during recovery.Tests cover the new conditions, orchestration paths, and a dedicated
FDv1FallbackRecovery.test.ts.Reviewed by Cursor Bugbot for commit a7a5773. Bugbot is set up for automated code reviews on this repo. Configure here.