Skip to content

feat: Thread FDv1 fallback TTL through polling and streaming data sources#1806

Open
joker23 wants to merge 10 commits into
mainfrom
skz/SDK-2687/fdv1-fallback-fix-fallback-ttl-source-threading
Open

feat: Thread FDv1 fallback TTL through polling and streaming data sources#1806
joker23 wants to merge 10 commits into
mainfrom
skz/SDK-2687/fdv1-fallback-fix-fallback-ttl-source-threading

Conversation

@joker23

@joker23 joker23 commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

This commit will add in fallback TTL reading support as well as allow RN native event source read headers.

NOTE: while working this PR, I found a lot of gaps in the RN eventsource. Internally tracked in ticket 2721 in sdk project.


Note

Medium Risk
Changes how FDv2 sources signal and time FDv1 fallback (including goodbye vs terminal_error), which affects orchestrator source switching; scope is large but heavily tested.

Overview
Adds a shared FallbackDirective model and header/event parsers so FDv2 polling and streaming can carry fdv1Fallback plus fdv1FallbackTtlMs (from x-ld-fd-fallback / x-ld-fd-fallback-ttl, or in-band protocolFallbackTTL on goodbye).

Result builders (changeSet, interrupted, terminalError, goodbye) now take a directive object instead of a bare boolean; call sites and tests are updated accordingly. Polling reads the directive on every response and, when fallback is set alongside a goodbye event, emits terminal_error so the orchestrator switches off FDv2 instead of treating it as a benign goodbye. Streaming defers open-header directives until the next queued result, merges them into errors/ping paths without mutating ping handler objects, and clears pending/committed fallback state on reconnect and close. Polling initializer keeps fallback + TTL when retries exhaust.

CI package size limit for @launchdarkly/js-client-sdk-common is raised to 41500 bytes.

Reviewed by Cursor Bugbot for commit 20081c8. Bugbot is set up for automated code reviews on this repo. Configure here.

@github-actions

github-actions Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

@launchdarkly/js-sdk-common size report
This is the brotli compressed size of the ESM build.
Compressed size: 26360 bytes
Compressed size limit: 29000
Uncompressed size: 129188 bytes

@github-actions

github-actions Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

@launchdarkly/js-client-sdk-common size report
This is the brotli compressed size of the ESM build.
Compressed size: 41238 bytes
Compressed size limit: 41500
Uncompressed size: 223057 bytes

@github-actions

github-actions Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

@launchdarkly/js-client-sdk size report
This is the brotli compressed size of the ESM build.
Compressed size: 32439 bytes
Compressed size limit: 34000
Uncompressed size: 115992 bytes

@github-actions

github-actions Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

@launchdarkly/browser size report
This is the brotli compressed size of the ESM build.
Compressed size: 180100 bytes
Compressed size limit: 200000
Uncompressed size: 833166 bytes

@joker23

joker23 commented Jul 16, 2026

Copy link
Copy Markdown
Contributor Author

@cursor review

cursor[bot]

This comment was marked as resolved.

@joker23
joker23 force-pushed the skz/SDK-2687/fdv1-fallback-fix-fallback-ttl-source-threading branch from e4fa9cb to 1400310 Compare July 17, 2026 14:01
@joker23

joker23 commented Jul 17, 2026

Copy link
Copy Markdown
Contributor Author

@cursor review

cursor[bot]

This comment was marked as resolved.

Comment thread packages/sdk/react-native/src/fromExternal/react-native-sse/EventSource.ts Outdated
Comment thread .github/workflows/sdk-client.yml Outdated
@joker23
joker23 force-pushed the skz/SDK-2687/fdv1-fallback-fix-fallback-ttl-source-threading branch from 46de8d4 to 6604149 Compare July 17, 2026 16:56
@joker23

joker23 commented Jul 17, 2026

Copy link
Copy Markdown
Contributor Author

@cursor review

cursor[bot]

This comment was marked as resolved.

@joker23

joker23 commented Jul 17, 2026

Copy link
Copy Markdown
Contributor Author

@cursor review

Comment thread packages/sdk/react-native/src/fromExternal/react-native-sse/EventSource.ts Outdated
cursor[bot]

This comment was marked as resolved.

Comment thread packages/sdk/react-native/src/fromExternal/react-native-sse/EventSource.ts Outdated
@joker23
joker23 force-pushed the skz/SDK-2687/fdv1-fallback-fix-fallback-ttl-source-threading branch from 29aefb7 to 73eeb30 Compare July 17, 2026 22:00
@joker23

joker23 commented Jul 20, 2026

Copy link
Copy Markdown
Contributor Author

@cursor review

cursor[bot]

This comment was marked as resolved.

@joker23

joker23 commented Jul 20, 2026

Copy link
Copy Markdown
Contributor Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ 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 c01baaa. Configure here.

terminalError,
} from './FDv2SourceResult';

function getFallback(headers: { get(name: string): string | null }): boolean {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

replacing with

export function readFallbackDirective(headers: {

@joker23
joker23 marked this pull request as ready for review July 20, 2026 16:55
@joker23
joker23 requested a review from a team as a code owner July 20, 2026 16:55

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 2 additional findings.

Open in Devin Review

Comment thread packages/shared/sdk-client/src/datasource/fdv2/PollingBase.ts Outdated
fdv1FallbackTtlMs = pendingFallbackTtlMs;
resultQueue.put(changeSet(action.payload, true, undefined, undefined, pendingFallbackTtlMs));
pendingFallback = false;
pendingFallbackTtlMs = undefined;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this section use resolveFallback?

case 'payload':
logConnectionResult(true);
resultQueue.put(changeSet(action.payload, fdv1Fallback));
if (pendingFallback) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this if check required? Is there a way to write it such that it just uses resolveFallback always?

fdv1Fallback = true;
resultQueue.put(terminalError(errorInfoFromUnknown(action.reason), true, ttlMs));
pendingFallback = false;
pendingFallbackTtlMs = undefined;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment here. I thought the purpose of the resolveFallback was to remove duplication of this routine of consuming the pending fallback and clearing values.

const fallback = resolveFallback();
if (!result.fdv1Fallback && fallback.fdv1Fallback) {
result.fdv1Fallback = true;
result.fdv1FallbackTtlMs = fallback.fdv1FallbackTtlMs;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is editing result appropriate? Seems like it shouldn't be mutated from a good practices standpoint.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something feels off about how many spots have if checks on pending fallback and logic for moving things around and masking values on top of others. It just seems very scattered and likely a subtle tweak will mess up the logic. Is there a way to make it such that all results that go into the queue conform to some type / interface and fallback can be applied to that thing unconditonally, sometimes a no-op but sometimes a real fallback apply occurs. The pending mechanism could be something that can only apply once and then turns itself into a no-op or something.

cursor[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

@joker23
joker23 force-pushed the skz/SDK-2687/fdv1-fallback-fix-fallback-ttl-source-threading branch from e95c2f2 to 005c842 Compare July 22, 2026 15:16
devin-ai-integration[bot]

This comment was marked as resolved.

This will allow us to resolve directives that should override the
fallback behavior such as goodbye or error
@joker23
joker23 force-pushed the skz/SDK-2687/fdv1-fallback-fix-fallback-ttl-source-threading branch from 005c842 to adfcb4d Compare July 22, 2026 16:07
devin-ai-integration[bot]

This comment was marked as resolved.

@joker23
joker23 requested a review from tanderson-ld July 22, 2026 16:35
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