Skip to content

feat: base provider state on CDN fetches only, not SSE connection state - #44

Merged
toddbaert merged 12 commits into
mainfrom
draft/sse-independent-staleness
Nov 4, 2026
Merged

toddbaert merged 12 commits into
mainfrom
draft/sse-independent-staleness

Conversation

@toddbaert

@toddbaert toddbaert commented Oct 19, 2026 •

Copy link
Copy Markdown
Collaborator

Simplifies SSE, as described here, and update e2e accordingly.

TLDR: if SSE is connected, we poll slow - if SSE is not connected, we poll fast, regardless of the SSE connection being disabled by config or disconnect by accident; only failed polls impact provider state

Related:

Comment thread .gitmodules Resolved
@toddbaert
toddbaert marked this pull request as ready for review October 20, 2026 17:51

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

Still trying to understand the exact flow of the sse connection within the providers, I found 2 spots where we are somewhat 'loosing' conditions with the code removal. I'm not confident that they are really issues, but might be worth looking at again :)

Comment on lines +825 to 827
Thread.sleep(100); // let the interval switch settle
fetches.set(0);
Thread.sleep(300);

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.

[q/nit] should those timings be constants to make it clear what they wait for? 100 & 300 seem to be reused intentionally


// header and value are null when the step has no "with ... header ..." suffix
@Given("^an initialized, READY provider serving the \"([^\"]*)\" flag configuration(?: with \"([^\"]*)\" header \"([^\"]*)\")?$")
@Given("^an initialized, READY provider serving the \"([^\"]*)\" flag configuration(?: with \"([^\"]*)\" header (\"[^\"]*\"|'[^']*'))?$")

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.

[q/nity-nit] this is independent from the sse state stuff, right?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

yes, this is an unrelated change in the testbed, enforcing that etag values are quoted (that's just part of HTTP semantics)

Comment on lines -632 to -635
if (sseConnected.get()) {
log.warn("poll failed (SSE healthy, staying READY): {}", reason);
return;
}

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.

[q] removing this part, will result in an immediate stale state if onFetchFailure is called, right? So, we are much more sensitive to issues of the CDN than we were before, when additionally checking for a healthy sse. We do have the http retry, however, calculating 120ms for MAX_TOTAL_BACKOFF_MS and MAX_ATTEMPTS being 2, the cdn cannot have a very long hiccup.
In your experience is this something we should give more time with by increasing the max retries or adding some grace time?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Good catch!

I think we can fix this with one small addition to my simplification: after a failed fetch, poll at 10s until a fetch succeeds... so pollingManager.setInterval(pollIntervalDisconnected) on failure, and restoring pollIntervalConnected on success if SSE is connected.

So whether SSE is connected or not, a failed fetch drops us to the fast cadence. If it's a blip, we recover within ~10s and don't go to a spurious ERROR over. I'm OK with quick STALE transitions; those are just being truthful, and even our internal provider does this due to gRPC stream timeouts.

I'd rather not add more retries per fetch (a fetch has to stay under the 10s poll interval) or more grace time (it would only delay a correct signal).

@toddbaert toddbaert Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Opened:

Overall, the simplification is still much better, it avoids the entire debounce construct and multiple paths for STALE/ERROR - we just leverage an existing construct (poll aggressiveness) to fix your finding.

The new test in the test harness PR failed until I made the fix I proposed above.

Again, nice find! Let me know if you think this covers it.

log.info("SSE connected; poll interval switched to {}", pollIntervalConnected);
pm.setInterval(pollIntervalConnected);
// catch up on anything announced while the stream was down; never dropped
pm.requestOutOfBandFetch(null);

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.

[q] similar to the other comment: we loose the (!wasConnected) condition for this catch up fetch. What if there is a short sse hiccup, it reconnects immediately, then it will send this fetch unnecessarily, right, because we dont check anymore?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

main also fires the catch-up after a short hiccup (hadPendingDisconnect is true when the stream reopens during the "debounce")...

But I think your other point here is valid: #44 (comment)

Copilot AI 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.

🟡 Changes recommended

SSE reconnection can override fast recovery polling during CDN throttling, delaying recovery until the ten-minute polling tick.

2 open issues
What changed in this PR

This PR makes provider staleness depend on CDN fetch outcomes rather than SSE connection state, while retaining SSE-based polling intervals and reconnect catch-up fetches.

Changes:

  • Removes SSE disconnect debouncing and disconnect-driven state transitions.
  • Accelerates polling after CDN failures and restores the connected interval after successful fetches.
  • Updates unit tests and end-to-end steps for the revised behavior.
File Description
src/​test/​java/​com/​dynatrace/​openfeature/​ProviderTestSupport.java Removes the obsolete disconnect-debounce constant.
src/​test/​java/​com/​dynatrace/​openfeature/​e2e/​E2eStepDefinitions.java Updates SSE steps, header parsing, and event-absence assertions.
src/​test/​java/​com/​dynatrace/​openfeature/​DynatraceProviderTest.java Revises staleness, reconnect, and polling-cadence tests.
src/​main/​java/​com/​dynatrace/​openfeature/​DynatraceProvider.java Bases staleness and recovery polling on CDN fetch outcomes.

Review effort: Balanced

Copilot AI balanced review requested due to automatic review settings October 27, 2026 14:46

Copilot AI 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.

🔵 Needs a closer look

An initialization race can overwrite fast recovery polling with the connected interval after a failed SSE catch-up fetch.

1 open issue
1 previously missed issue

In code that hasn't changed since last review

Medium severity Prevent stale SSE recovery from using the connected polling interval

src/​main/​java/​com/​dynatrace/​openfeature/​DynatraceProvider.java:557

If an SSE catch-up fetch fails after pollingManager.start() but before initialization adopts the connected cadence (lines 337–340), that handoff can overwrite this fast interval even though the provider is now STALE. Recovery then waits for the 10-minute connected interval, beyond the grace period. Synchronize the initialization handoff with these callbacks and select the connected interval only while READY.

1 resolved since last review

Review effort: Balanced

Copilot AI balanced review requested due to automatic review settings October 27, 2026 15:18

Copilot AI 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.

🟢 Approval recommended

The reviewed changes address the prior recovery-cadence concern, and no unresolved blocking issues were identified.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

Copilot AI balanced review requested due to automatic review settings October 27, 2026 18:06

Copilot AI 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.

🟢 Approval recommended

Static review found no unresolved blocking issues in the state transitions, polling behavior, or test adaptations; tests were not executed.

No open issues 🎉

Review effort: Balanced

Copilot AI 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.

🟢 Approval recommended

No active review issues are reported for the update to CDN-fetch-driven staleness.

No open issues 🎉

Review effort: Balanced

Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
@toddbaert
toddbaert force-pushed the draft/sse-independent-staleness branch from b8c3835 to cd94c61 Compare November 2, 2026 19:59
Copilot AI balanced review requested due to automatic review settings November 2, 2026 19:59

Copilot AI 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.

🟢 Approval recommended

There are no active review issues for the changes to CDN-driven staleness and SSE-controlled polling.

No open issues 🎉

Review effort: Balanced

@toddbaert toddbaert changed the title feat: base staleness on CDN fetches only, not SSE state feat: base provider state on CDN fetches only, not SSE connection state Nov 3, 2026
@toddbaert
toddbaert merged commit dd3b485 into main Nov 4, 2026
16 checks passed
@toddbaert
toddbaert deleted the draft/sse-independent-staleness branch November 4, 2026 21:39
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.

4 participants