Skip to content

docs: add ADR for SSE bulk evaluation change notifications#63

Merged
jonathannorris merged 26 commits intomainfrom
feature/adr-0008-sse-bulk-evaluation
Mar 16, 2026
Merged

docs: add ADR for SSE bulk evaluation change notifications#63
jonathannorris merged 26 commits intomainfrom
feature/adr-0008-sse-bulk-evaluation

Conversation

@jonathannorris
Copy link
Member

@jonathannorris jonathannorris commented Feb 20, 2026

This PR

This PR adds ADR-0008 (#62) to propose Server-Sent Events (SSE) for bulk evaluation change notifications in OFREP.

  • Adds an optional refreshConnections array to bulk evaluation responses, with a type discriminator to support future push mechanisms beyond SSE.
  • Defines notification-only SSE behavior (refetchEvaluation) and provider lifecycle guidance (reconnect, fallback, coalescing).
  • Specifies SSE-trigger metadata transport via query params (sseEtag, sseLastModified) only for requests triggered directly by SSE messages.

Notes

Includes open questions on query params vs custom headers, replay guarantees (Last-Event-ID), and security expectations for tokenized SSE URLs.

Signed-off-by: Norris <jonathan.norris@dynatrace.com>
@jonathannorris jonathannorris requested a review from a team as a code owner February 20, 2026 16:24
@jonathannorris jonathannorris requested review from Copilot and removed request for a team February 20, 2026 16:24
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @jonathannorris, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a new Architectural Decision Record (ADR) to integrate Server-Sent Events (SSE) into the OFREP specification. The primary goal is to enable real-time flag updates and reduce server load by moving away from exclusive polling for change detection. The ADR defines how SSE endpoints will be communicated, the format of notification events, and the expected behavior for providers to manage these connections and re-fetch evaluations efficiently.

Highlights

  • New Architectural Decision Record (ADR): Added ADR-0008, which proposes the use of Server-Sent Events (SSE) to provide real-time change notifications for bulk flag evaluations in OFREP, addressing limitations of the current polling mechanism.
  • SSE Integration into OFREP Response Schema: Introduced an optional 'sse' array to the bulk evaluation response schema, allowing servers to provide SSE endpoint URLs for clients to connect to for change notifications.
  • Notification-Only SSE Mechanism: Defined SSE as a notification-only mechanism, where events like 'refetchEvaluation' signal the provider to re-fetch the bulk evaluation via the existing endpoint, rather than streaming full evaluation payloads.
  • SSE Metadata Transport: Specified that SSE-triggered re-fetch requests should include 'sseEtag' and 'sseLastModified' as query parameters, which are distinct from standard HTTP conditional request headers and are used for server-side cache validation.
  • Provider Behavior Guidelines: Outlined detailed guidelines for provider implementations, covering SSE connection management, reconnection strategies, handling of inactivity delays, fallback mechanisms, and coalescing of re-fetch requests.
Changelog
  • service/adrs/0008-sse-for-bulk-evaluation-changes.md
    • Added a new Architectural Decision Record (ADR-0008) proposing Server-Sent Events (SSE) for bulk evaluation change notifications.
    • Defined the response schema for including SSE connection URLs in bulk evaluation responses.
    • Specified the SSE event format and how metadata like etags and last modified timestamps should be transported.
    • Provided detailed guidelines for provider behavior regarding SSE connection lifecycle, reconnection, and fallback.
    • Included OpenAPI schema additions for the new 'sse' field and related query parameters.
Activity
  • No human activity has been recorded on this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This PR introduces ADR-0008, proposing Server-Sent Events (SSE) for bulk evaluation change notifications in OFREP. The document outlines the motivation, decision, response schema, event format, provider behavior, OpenAPI schema additions, consequences, open questions, and implementation notes. The changes are well-documented and address a significant limitation of the current polling-only approach. The ADR is comprehensive and considers various aspects of SSE integration, including potential complexities and risks. The open questions section is particularly valuable for guiding future discussions and refinements.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds ADR-0008 to propose Server-Sent Events (SSE) as a standardized mechanism for real-time flag change notifications in OFREP, addressing the polling limitations explicitly acknowledged in ADR-0005. The ADR follows the established pattern of building on vendor survey feedback and maintaining backward compatibility.

Changes:

  • Introduces optional SSE connection endpoints in bulk evaluation responses for real-time change notifications
  • Defines a notification-only pattern where SSE events trigger re-fetches rather than streaming full payloads
  • Specifies SSE-specific metadata transport via query parameters (sseEtag, sseLastModified) for SSE-triggered requests

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Member

@askpt askpt left a comment

Choose a reason for hiding this comment

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

Added a couple of comments for discussion.

Signed-off-by: Norris <jonathan.norris@dynatrace.com>
…iminator

Signed-off-by: Norris <jonathan.norris@dynatrace.com>
Signed-off-by: Norris <jonathan.norris@dynatrace.com>
Signed-off-by: Norris <jonathan.norris@dynatrace.com>
Signed-off-by: Norris <jonathan.norris@dynatrace.com>
@jonathannorris jonathannorris force-pushed the feature/adr-0008-sse-bulk-evaluation branch from 0f4ec8c to 94b1fc6 Compare February 27, 2026 19:24
Signed-off-by: Norris <jonathan.norris@dynatrace.com>
Signed-off-by: Norris <jonathan.norris@dynatrace.com>
Signed-off-by: Norris <jonathan.norris@dynatrace.com>
…events

Signed-off-by: Norris <jonathan.norris@dynatrace.com>
Signed-off-by: Norris <jonathan.norris@dynatrace.com>
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

jonathannorris and others added 5 commits March 5, 2026 23:18
Signed-off-by: Norris <jonathan.norris@dynatrace.com>
… query param rationale

Signed-off-by: Norris <jonathan.norris@dynatrace.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Jonathan Norris <jonathan@taplytics.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Jonathan Norris <jonathan@taplytics.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Jonathan Norris <jonathan@taplytics.com>
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Signed-off-by: Norris <jonathan.norris@dynatrace.com>
"refreshConnections": [
{
"type": "sse",
"url": "https://sse.example.com/event-stream?channels=env_abc123_v1",

Choose a reason for hiding this comment

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

The URL should be split between hostname and path properties.

This allows for systems that need to override the endpoint without having to hackily substring and replace. Generally required by larger/proxied users.

Copy link
Member Author

Choose a reason for hiding this comment

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

I think keeping url as a single opaque string is the right call here. The server fully controls the URLs it returns in the response, so if a proxied setup needs different endpoints the server can return the correct URLs directly. I don't think we should be modifying these URLs in the provider layer.

Copy link
Member

Choose a reason for hiding this comment

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

I think keeping url as a single opaque string is the right call here.

I think so for the same reason.

Choose a reason for hiding this comment

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

A proxied setup will need to be able to re-write the URL; while keeping the path and auth/channel specifics it will need to be able to re-write the hostname and protocol.

Using a regex solution to do this in the proxy doesn't exactly seem the correct solution, and quite hacky.

Copy link
Member Author

Choose a reason for hiding this comment

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

Made an update here to support proxied/origin-rewrite setups without changing the default model.

url remains the default representation, but the ADR now also allows a structured endpoint form with origin + requestUri for implementations that need to override the origin cleanly while preserving the request target. The intent is that exactly one of url or endpoint is provided for an event stream entry.

Copy link
Member

Choose a reason for hiding this comment

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

I am not sure about this.
How would that work? How would a provider implementation use the origin + requestUri to support a proxied setup?
@JamieSinn could you elaborate on how you would imagine to use this?
I would like to avoid any extra options that are not necessary or giving a larger benefit.

Copy link
Member Author

Choose a reason for hiding this comment

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

This is something we're likely to use internally for server-side SSE connections at Dynatrace.

In our previous proxy setup at DevCycle, we effectively re-broadcast SSE messages from the proxy to internal SDKs/providers. In that model, the provider needs to connect to the local proxy origin, while preserving the path/query/channel-specific parts of the original SSE endpoint. Keeping this as a single opaque url makes that override logic pretty awkward and usually turns into string replacement.

Copy link
Member

@lukas-reining lukas-reining Mar 16, 2026

Choose a reason for hiding this comment

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

This is something we're likely to use internally for server-side SSE connections at Dynatrace.

Yesh I guessed so.

In that model, the provider needs to connect to the local proxy origin, while preserving the path/query/channel-specific parts of the original SSE endpoint. Keeping this as a single opaque url makes that override logic pretty awkward and usually turns into string replacement.

I am not convinced of that. In my view adding special parameters for a non-standard case that can trivially be replaced by leaving the splitting of the URL to the implementer of that proxy logic.

JS Example:

const urlString = 'https://example.com:8080/path/to/page?param1=value1&param2=value2#hash';
const url = new URL(urlString);

const origin = url.origin;
const pathAndParams = url.pathname + url.search + url.hash; 

Choose a reason for hiding this comment

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

Yep - happy to expand on it.

With DevCycle - we had to split this between hostname and path due to the way that our downstream SDK proxy needed to split the endpoints and rewrite them based on the host request parameters that were incoming.
You can see some of this implementation here:
https://github.com/DevCycleHQ/sdk-proxy/blob/main/http_endpoints.go#L247
https://github.com/DevCycleHQ/sdk-proxy/blob/main/http_endpoints.go#L199

If we were to implement the url concept and the SDK proxy were to operate in cloud mode (which it can, and quite a few customers do use it in) - then there is no way to re-write the url property without putting the breaking nature of the path/upstream origin on the SDK proxy implementation.

This is definitely an ease of use request for the proxy use case - but I don't really see the harm in the additional option to have your hostname/endpoint path if the default is the full URL.

@toddbaert toddbaert self-requested a review March 13, 2026 13:43
Copy link
Member

@toddbaert toddbaert left a comment

Choose a reason for hiding this comment

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

I have mostly nits, small additions, and naming improvement suggestions. Overall I think this is a great addition.

I do agree with @lukas-reining 's point here: #63 (comment)

… server-side providers

Signed-off-by: Norris <jonathan.norris@dynatrace.com>
Signed-off-by: Norris <jonathan.norris@dynatrace.com>
…y param answer

Signed-off-by: Norris <jonathan.norris@dynatrace.com>
Signed-off-by: Norris <jonathan.norris@dynatrace.com>
Signed-off-by: Jonathan Norris <jonathan.norris@dynatrace.com>
Signed-off-by: Jonathan Norris <jonathan.norris@dynatrace.com>
@jonathannorris
Copy link
Member Author

@lukas-reining / @thomaspoignant any further questions or approvals before I merge this?

Copy link
Member

@lukas-reining lukas-reining left a comment

Choose a reason for hiding this comment

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

Approval from me, I would just like to have sorted out the proxy url idea before merging.
Thanks again @jonathannorris, I know this took a lot of time :)

@jonathannorris jonathannorris merged commit ee7c27b into main Mar 16, 2026
4 checks passed
@jonathannorris jonathannorris deleted the feature/adr-0008-sse-bulk-evaluation branch March 16, 2026 19:30
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.

8 participants