Skip to content

Conversation

@luxscious
Copy link
Contributor

@luxscious luxscious commented Dec 11, 2025

  • Updated sse_state() to accept Optional[Start] and guard against duplicate logs
  • Updated sse_message() to call sse_state(None) as fallback when receiving
    Event messages before Start events
  • add error handling for our internal state if an sse connection is lost

This ensures _sse_connected is correctly set regardless of whether the SSE
server sends Start events, Comment events, or Event messages first.

@luxscious luxscious requested a review from a team as a code owner December 11, 2025 18:28
Copilot AI review requested due to automatic review settings December 11, 2025 18:28
@luxscious luxscious marked this pull request as draft December 11, 2025 18:29
@luxscious luxscious force-pushed the fix-reduce-logging-frequency branch from 38e6a23 to ed5bf3c Compare December 11, 2025 18:29
@luxscious luxscious marked this pull request as ready for review December 11, 2025 18:30
Copy link

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 fixes SSE (Server-Sent Events) connection state handling to ensure the client correctly establishes connection status even when the SSE server sends events in unexpected orders (e.g., Comment or Event messages before Start events).

Key changes:

  • Modified sse_state() to accept Optional[Start] parameter and prevent duplicate connection logs
  • Updated sse_message() to call sse_state(None) as a fallback when events arrive before Start
  • Added Comment event handling in SSE manager to trigger connection state update
  • Increased default config polling interval from 1s to 30s (reasonable when SSE provides real-time updates)

Reviewed changes

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

File Description
devcycle_python_sdk/options.py Increased default config_polling_interval_ms from 1000 to 30000ms to reduce polling frequency when SSE real-time updates are available
devcycle_python_sdk/managers/sse_manager.py Added handling for Comment events to trigger SSE connection state initialization
devcycle_python_sdk/managers/config_manager.py Updated sse_state() signature to Optional[Start] and modified sse_message() to ensure connection state is set regardless of event order

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

Comment on lines 147 to 151
def sse_state(self, state: Optional[ld_eventsource.actions.Start]):
# Prevents duplicate logs when Comment events call this repeatedly
if not self._sse_connected:
self._sse_connected = True
logger.info("DevCycle: Connected to SSE stream")
Copy link

Copilot AI Dec 11, 2025

Choose a reason for hiding this comment

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

The new behavior introduced in sse_state() and sse_message() (handling Comment events and calling sse_state with None) lacks test coverage. Consider adding tests that verify the SSE connection state is correctly set when receiving Comment events before Start events, and when receiving Event messages before Start events.

Copilot uses AI. Check for mistakes.
@luxscious luxscious requested a review from jsalaber December 11, 2025 20:05
self._local_bucketing.store_config(json_config)
if not self._options.disable_realtime_updates:
if self._sse_manager is None:
if self._sse_manager is None or not self._sse_manager.client.is_connected():
Copy link
Contributor

Choose a reason for hiding this comment

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

does this mean you create a new SSEManager when the client isn't connected? wouldn't it be better to do some sort of reconnection strategy?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yea if this becomes an issue i think we should revisit this. gonna merge this for now --> Its a pre-emptive solution to an anticipated problem.

Copilot AI review requested due to automatic review settings December 11, 2025 21:34
@luxscious luxscious enabled auto-merge (squash) December 11, 2025 21:35
@luxscious luxscious merged commit 34678e4 into main Dec 11, 2025
18 checks passed
@luxscious luxscious deleted the fix-reduce-logging-frequency branch December 11, 2025 21:37
Copy link

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 4 comments.


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

def sse_state(self, state: ld_eventsource.actions.Start):
self._sse_connected = True
logger.info("DevCycle: Connected to SSE stream")
def sse_state(self, state: Optional[ld_eventsource.actions.Start]):
Copy link

Copilot AI Dec 11, 2025

Choose a reason for hiding this comment

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

Type signature inconsistency detected. The SSEManager constructor expects handle_state to be of type Callable[[ld_eventsource.actions.Start], None] (line 15 in sse_manager.py), but the sse_state method signature has been changed to accept Optional[ld_eventsource.actions.Start]. The SSEManager type hints should be updated to reflect this change, using Optional[ld_eventsource.actions.Start] instead of just ld_eventsource.actions.Start.

Copilot uses AI. Check for mistakes.
Comment on lines +149 to +155
self._sse_connected = False
logger.debug(f"DevCycle: Received SSE error: {error}")

def sse_state(self, state: ld_eventsource.actions.Start):
self._sse_connected = True
logger.info("DevCycle: Connected to SSE stream")
def sse_state(self, state: Optional[ld_eventsource.actions.Start]):
if not self._sse_connected:
self._sse_connected = True
logger.info("DevCycle: Connected to SSE stream")
Copy link

Copilot AI Dec 11, 2025

Choose a reason for hiding this comment

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

Potential race condition with _sse_connected flag. This boolean flag is accessed and modified from multiple threads without synchronization: the main polling thread (line 128 in run()) and the SSE event handling thread (via sse_message, sse_error, and sse_state callbacks). Consider using a threading.Lock to protect access to _sse_connected, or use a thread-safe alternative like threading.Event.

Copilot uses AI. Check for mistakes.
if not self._options.disable_realtime_updates:
if self._sse_manager is None:
if (
self._sse_manager is None
Copy link

Copilot AI Dec 11, 2025

Choose a reason for hiding this comment

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

Potential AttributeError when accessing self._sse_manager.client.is_connected(). The SSEManager's client attribute is initialized to None in the constructor and only gets assigned when the update() method is called. This check could raise an AttributeError if the SSEManager exists but update() hasn't been called yet. Consider adding a None check for the client before calling is_connected().

Suggested change
self._sse_manager is None
self._sse_manager is None
or self._sse_manager.client is None

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants