Skip to content

fix: Fall back from a silent FDv2 synchronizer during startup - #402

Draft
kinyoklion wants to merge 1 commit into
mainfrom
devin/1793986063-fdv2-startup-fallback
Draft

kinyoklion wants to merge 1 commit into
mainfrom
devin/1793986063-fdv2-startup-fallback

Conversation

@kinyoklion

Copy link
Copy Markdown
Member

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 (net8.0 only locally)

Related issues

The nightly server contract tests (sdk-server-nightly.yml) have failed on these 3 tests since they were enabled in #380:

  • streaming/fdv2/recoverable fallback to secondary synchronizer
  • streaming/fdv2/recoverable fallback with recovery
  • streaming/fdv2/permanent fallback with recovery

The first one was also hitting a harness bug, which is fixed in launchdarkly/sdk-test-harness#589 (merged). The Go SDK fixed the same SDK-side behavior in go-server-sdk #461.

Describe the solution you've provided

Two changes in the FDv2 data system:

  1. Startup fallback (FDv2DataSource.cs). A DataAppliedObserver is added to both the initializer and synchronizer composites, and it records whether any changeset has been applied. When there is more than one synchronizer, each synchronizer's ActionApplierTimedFallbackAndRecovery gets a hasDataBeenApplied predicate. If no data has been applied yet, it schedules a 10 second startup fallback (DisposeCurrent / GoToNext / StartCurrent). That timer is cancelled when the source applies data or reports Valid or Off. Before this change, a synchronizer that connected but stayed silent was only abandoned by the 2 minute Interrupted timer. The 2 minute interrupted fallback and the 5 minute recovery are unchanged.
  2. Streaming reports Valid (FDv2StreamingDataSource.cs). After a changeset is applied successfully, the streaming synchronizer now calls UpdateStatus(Valid), the same way the polling synchronizer and the Go streaming synchronizer do. Before this change, Valid was only produced by the outer DataSourceUpdatesImpl, so the synchronizer composite's action applier never saw it and never scheduled recovery to the primary synchronizer. That is why recoverable fallback with recovery still failed even after the startup fallback was added. It isn't reported when the changeset carries the FDv1 fallback directive, because the source shuts down right after.

Describe alternatives you've considered

  • Suppressing the 3 tests, like java-core does. Not done, because the behavior they check is real.
  • Deriving "has data" from the existing InitializationTracker states. A dedicated observer is simpler, and it doesn't depend on that tracker's state machine.

Additional context

Local validation (.NET 8.0.427, net8.0):

  • Server unit tests: 1661 passed. This includes 6 new StartupFallback* tests in FDv2DataSourceTest, plus updated FDv2StreamingDataSourceTest expectations for the new Valid status.
  • Contract tests with the same flags as the nightly FDv2 run (-status-timeout=360 -skip-from=test-supressions-fdv2.txt -enable-long-running-tests, persistence disabled), against a harness that includes sdk-test-harness#589: All tests passed, 5919 run, 11 skipped. The 3 tests above now pass.

Points for reviewers:

  • The startup timer is created when an applier is constructed, which happens each time a synchronizer becomes current. If the data system is disposed, the pending action is a no-op because CompositeSource ignores actions after disposal.
  • The startup fallback only applies while no data has been applied from any source. Once an initializer or synchronizer has delivered data, fallback works the same as before.

Link to Devin session: https://app.devin.ai/sessions/fe4a81e87871412a99d2eed85302fe33
Open in Devin Desktop: https://app.devin.ai/desktop/session/fe4a81e87871412a99d2eed85302fe33?variant=devin

Before any data has been applied, a synchronizer that provides no data
within 10 seconds is abandoned for the next synchronizer, rather than
waiting for the 2 minute interrupted fallback.

The FDv2 streaming synchronizer now reports Valid after it applies a
changeset, so the synchronizer composite can schedule recovery to the
primary synchronizer.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.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

@devin-ai-integration devin-ai-integration Bot added the devin-pr PR was created by Devin AI label Nov 6, 2026

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

devin-pr PR was created by Devin AI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant