Repository navigation
feat: Apply RETRY to FDv2 synchronizer orchestration - #252
Merged
Merged
Conversation
beekld
force-pushed
the
bklimt/SDK-3402/retry-parking
branch
from
November 6, 2026 00:49
0cf207f to
8aa8c77
Compare
beekld
marked this pull request as ready for review
November 6, 2026 00:54
beekld
force-pushed
the
bklimt/SDK-3402/retry-parking
branch
from
November 6, 2026 17:37
f78d65f to
0dafa42
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 0dafa42. Configure here.
beekld
force-pushed
the
bklimt/SDK-3402/retry-parking
branch
from
November 10, 2026 21:42
0dafa42 to
a700bff
Compare
tanderson-ld
approved these changes
Nov 12, 2026
beekld
added a commit
that referenced
this pull request
Nov 12, 2026
## Summary The FDv2 synchronizer loop measured its deadlines against the wall clock. When the system clock stepped backwards, every pending deadline was delayed by the size of the step. If every synchronizer was parked for 5 minutes and the clock stepped back an hour, no synchronizer ran for 65 minutes. These deadlines now use `MonotonicTime`, a small value class over `System.nanoTime()`, so changes to the system clock don't move them. Stacked on #252. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Overview** > FDv2 synchronizer orchestration previously scheduled **recovery**, **fallback**, **park/unpark**, and **FDv1 fallback TTL** deadlines using wall-clock `Instant`. A backward system clock step could postpone those deadlines and keep sources parked or on FDv1 longer than intended. > > This PR introduces **`MonotonicTime`** (backed by `System.nanoTime()`) and wires it through `FDv2DataSource`, `SourceManager`, and `SynchronizerFactoryWithState` for all internal wait/deadline logic (`awaitUntil`, `earliest`, parking, fallback end times). **`MonotonicTimeTest`** covers comparison and duration math across nanosecond counter overflow. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit d8cd1e1. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
beekld
pushed a commit
that referenced
this pull request
Nov 12, 2026
🤖 I have created a release *beep* *boop* --- ## [7.18.0](launchdarkly-java-server-sdk-7.17.5...launchdarkly-java-server-sdk-7.18.0) (2026-11-12) ### Features * Apply RETRY to FDv2 synchronizer orchestration ([#252](#252)) ([6a4aac5](6a4aac5)) ### Bug Fixes * Include the big segments status on evaluation reasons when a flag fails to evaluate ([#258](#258)) ([ce08ae8](ce08ae8)) * Make TestData valueForAll return its value when targeting is off ([#251](#251)) ([db17ab9](db17ab9)) * Measure synchronizer deadlines with a monotonic clock ([#253](#253)) ([3c7da2c](3c7da2c)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Overview** > This **Release Please** PR cuts **launchdarkly-java-server-sdk 7.18.0** by bumping version metadata only: `.release-please-manifest.json`, `lib/sdk/server/gradle.properties`, and `Version.SDK_VERSION` move from **7.17.5** to **7.18.0**. > > `CHANGELOG.md` gains a **7.18.0** section that records what ships in this artifact (already merged elsewhere): **RETRY** on FDv2 synchronizer orchestration; big-segments status on evaluation reasons when evaluation fails; `TestData` `valueForAll` honoring its value when targeting is off; synchronizer deadlines measured with a monotonic clock. This diff does not contain those implementation changes. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit aa18674. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
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.

Summary
Applies the RETRY behavior to FDv2 synchronizer orchestration in the server SDK. A synchronizer that fails is parked and retried later, instead of being blocked for good.
Parking
next(), a failure to build, or shutting down on its own. The park delay starts at 5 minutes, doubles with each failure up to 1 hour, and has jitter. After a park, the next synchronizer starts after a failover delay of 0.5-1 seconds.Directed fallback
Conditions removed
Conditionsclass andFDv2DataSourceConditionsare removed. They weren't compatible with the new parking and FDv1 fallback timers, so the synchronizer loop is simplified to check all of its timers each time it wakes.Not included
Retry-After.Note
Overview
Replaces the old condition/timer model (
FDv2DataSourceConditions,FDv2DataSource.Conditions) with a single synchronizer loop that wakes on results or deadlines (fallback, recovery, unpark, FDv1 TTL). Failed synchronizers are parked with exponential backoff (5 min → 1 h, jitter) instead of being blocked for the process lifetime; terminal errors and build failures park the source rather than permanently blocking it.Adds
AsyncLatchsoclose()and timed waits can raceCompletableFuture.anyOfwithout leaking completion nodes on long-lived streams.FDv1 fallback is time-bounded (default 1 h, jitter):
SourceManagertracks end time, blocks FDv2 sources during fallback, and returns when TTL expires. Server directives extend TTL or switch to FDv1 without halting the whole data system when no FDv1 synchronizer exists (reports INTERRUPTED and waits for TTL).Reset threshold is propagated via
FDv2SourceResult.resetThresholdMet— polling (2 successes), streaming (60 s healthy), FDv1 adapter (2 VALID) — and resets park counts. HTTP/transport classification (FailureClass) turns unexpected errors into terminal results in polling, streaming, and the FDv1 synchronizer adapter.close()releases the latch, shuts down sources, and joins the run thread (5 s cap) before reporting OFF.Reviewed by Cursor Bugbot for commit 94f7478. Bugbot is set up for automated code reviews on this repo. Configure here.