Skip to content

chore: schedule FDv2 recovery orchestration after fallback TTL expires - #1857

Open
joker23 wants to merge 1 commit into
skz/SDK-2911/fdv1-fallback-fix-recovery-primitivesfrom
skz/SDK-2912/fdv1-fallback-fix-recovery-orchestration
Open

chore: schedule FDv2 recovery orchestration after fallback TTL expires#1857
joker23 wants to merge 1 commit into
skz/SDK-2911/fdv1-fallback-fix-recovery-primitivesfrom
skz/SDK-2912/fdv1-fallback-fix-recovery-orchestration

Conversation

@joker23

@joker23 joker23 commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Summary

Wires the FDv2-recovery primitives from the previous PR in this stack into FDv2DataSource's synchronizer run loop: after falling back to FDv1, a recovery condition races alongside the existing fallback/recovery conditions, using the server-supplied TTL (or a caller-configurable override, or a 1-hour default if absent -- a TTL of 0 means indefinite, no recovery scheduled).

On firing, SourceManager.fdv2Recovery() re-enables FDv2 and the loop naturally attempts a fresh FDv2 connection -- if the server still signals fallback on that attempt, fallback re-engages from the new result. Also guards against the FDv1 synchronizer's own results re-triggering the fallback machinery. Ships with regression tests covering TTL present/absent/zero and the no-re-trigger guard.


Note

Overview
After the SDK falls back to FDv1, FDv2DataSource now schedules a return to FDv2 by racing an FDv2 recovery timer alongside the existing fallback/recovery conditions. When the timer fires, SourceManager.fdv2Recovery() re-enables FDv2 synchronizers so the loop can try FDv2 again (a new server fallback directive can re-engage FDv1).

TTL resolution follows server fdv1FallbackTtlMs when present, then optional config fdv2RecoveryTimeoutMs, then DEFAULT_FDV2_RECOVERY_TIMEOUT_MS (1 hour). TTL = 0 means indefinite FDv1 with no recovery timer; missing TTL is not treated like zero.

handleFdv1Fallback no longer re-runs fallback when the active synchronizer is already the FDv1 fallback slot, so FDv1 results that still carry the fallback flag do not loop fallback machinery.

Regression tests cover TTL expiry recovery, indefinite TTL, absent TTL defaulting to recovery, and the FDv1 no-re-trigger guard (SDK-2617).

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

@joker23
joker23 marked this pull request as ready for review August 13, 2026 17:55
@joker23
joker23 requested a review from a team as a code owner August 13, 2026 17:55

@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.

Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.

Fix All in Cursor

❌ 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 50a8250. Configure here.

}
} finally {
conditions.close();
fdv2RecoveryCondition?.close();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

FDv1 failure cancels FDv2 recovery

Medium Severity

The FDv2 recovery timer is scoped to the FDv1 synchronizer inner loop and closed in finally on every exit. An FDv1 terminal_error (for example non-recoverable 4xx from FDv1PollingSynchronizer) blocks FDv1, cancels the scheduled recovery, and leaves no available synchronizers, so the SDK never retries FDv2 after the server-directed TTL.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 50a8250. Configure here.


it('uses a default recovery interval (not zero) when fdv1FallbackTtlMs is absent (regression: SDK-2617 §8.3.2)', async () => {
// §8.3.2: when x-ld-fd-fallback-ttl header is absent, the SDK MUST use a default
// retry interval of 1 hour. Absence must NOT suppress recovery (unlike TTL=0).

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Internal spec section in comments

Low Severity

The new test name and comment reference opaque internal section §8.3.2. That violates the rule against internal specification identifiers in code comments; the surrounding text already explains the required absent-TTL behavior without the section marker.

Fix in Cursor Fix in Web

Triggered by learned rule: Do not reference internal specification documents in code comments

Reviewed by Cursor Bugbot for commit 50a8250. Configure here.

@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 1 additional finding.

Open in Devin Review

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.

1 participant