Skip to content

fix: Make the FDv1 fallback TTL-based and never indefinite - #354

Open
beekld wants to merge 3 commits into
mainfrom
devin/1792430210-fdv1-fallback-ttl
Open

beekld wants to merge 3 commits into
mainfrom
devin/1792430210-fdv1-fallback-ttl

Conversation

@beekld

@beekld beekld commented Oct 19, 2026 •

Copy link
Copy Markdown

Requirements

  • I have added test coverage for new or changed functionality
  • I have followed the repository's pull request submission guidelines
  • I have validated my changes against all supported platform versions

Related issues

SDK-2984 (part of SDK-2935). Implements the SDK-2527 spec change (sdk-specs#251, DATASYSTEM v2 1.6 / CSFDV2 8.3). Reference: FDv1FallbackDirective::DefaultTtl / FromServiceTtl in cpp-sdks, cpp-sdks#631.

Describe the solution you've provided

Before this change, a TTL of 0 meant "fall back indefinitely". The header and goodbye.protocolFallbackTTL TTLs were used without validation, the 1 hour default had no jitter, and FDv2 was never retried after the FDv1 fallback synchronizer was engaged.

  • resolveFallbackTtl (fallback_directive.dart): a TTL in (0, 1h] is used as-is. A missing, malformed, zero, negative, or > 1h TTL becomes 1h - uniform[0, 1800]s. This covers both the x-ld-fd-fallback-ttl header and goodbye.protocolFallbackTTL, which already reach the orchestrator as FDv2SourceResult.fdv1FallbackTtl.
  • Every directive goes through FDv2DataSourceOrchestrator._processDirective, whether or not an FDv1 tier is configured. It resolves the TTL, calls SourceManager.engageFdv1Fallback(), and schedules recovery. engageFdv1Fallback() blocks the FDv2 synchronizers and enables the FDv1 slot if there is one. With no FDv1 slot, nothing is available, so the synchronizer loop waits for recovery.
  • When the TTL elapses, SourceManager.restoreFdv2Synchronizers() makes the FDv2 slots available again and blocks FDv1. The active FDv1 run then ends (recover), so FDv1 is closed before the FDv2 synchronizer is created and the two never run together. If the FDv1 tier fails first, the loop waits for the timer instead of halting.
  • Initializers still run only once, in order. A directive from an initializer ends the initializer phase, and the remaining initializers don't run. When no FDv1 tier exists to complete initialization, any data the initializers already delivered completes it.
  • Removed _DirectiveAction.deferRetry and _pendingRetryDelay; the no-tier case now uses the same path as the FDv1 tier.
  • Updated comments that described Duration.zero as indefinite.

Describe alternatives you've considered

I kept the raw TTL as Duration? through the protocol and source layers and resolved it once in the orchestrator. Validating it in each parser would have meant changing every parser; this way the parsers are unchanged and the rule lives in one place.

Additional context

  • Deliberately unchanged: contract tests. The existing harness has no fallback-TTL coverage, so only unit tests were added.
  • fallbackTtlResolver is injectable on the orchestrator so tests can scale the TTLs down and keep real waits short.

Link to Devin session: https://app.devin.ai/sessions/f4e0848a068c4648b778346105ba7792
Open in Devin Desktop: https://app.devin.ai/desktop/session/f4e0848a068c4648b778346105ba7792?variant=devin
Requested by: @beekld

Co-Authored-By: Bee Klimt <bklimt@launchdarkly.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

@beekld
beekld marked this pull request as ready for review October 19, 2026 20:21
@beekld
beekld requested a review from a team as a code owner October 19, 2026 20:21
Comment thread packages/common_client/lib/src/data_sources/fdv2/orchestrator.dart Outdated
Co-Authored-By: Bee Klimt <bklimt@launchdarkly.com>
Comment thread packages/common_client/lib/src/data_sources/fdv2/orchestrator.dart Outdated
Comment thread packages/common_client/lib/src/data_sources/fdv2/orchestrator.dart Outdated
… directive

Co-Authored-By: Bee Klimt <bklimt@launchdarkly.com>

This branch has not been deployed

No deployments
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