From ed5bf3c920c7709bff920041cbaa3b1962dd8a68 Mon Sep 17 00:00:00 2001 From: Gabriella Gerges Date: Thu, 11 Dec 2025 14:16:46 -0400 Subject: [PATCH 1/3] fix: handle SSE connection state when start events are not received --- devcycle_python_sdk/managers/config_manager.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/devcycle_python_sdk/managers/config_manager.py b/devcycle_python_sdk/managers/config_manager.py index 43f6310..85ff769 100644 --- a/devcycle_python_sdk/managers/config_manager.py +++ b/devcycle_python_sdk/managers/config_manager.py @@ -128,9 +128,8 @@ def run(self): time.sleep(self._options.config_polling_interval_ms / 1000.0) def sse_message(self, message: ld_eventsource.actions.Event): - if self._sse_connected is False: - self._sse_connected = True - logger.info("DevCycle: Connected to SSE stream") + if not self._sse_connected: + self.sse_state(None) logger.info(f"DevCycle: Received message: {message.data}") sse_message = json.loads(message.data) dvc_data = json.loads(sse_message.get("data")) @@ -145,9 +144,11 @@ def sse_message(self, message: ld_eventsource.actions.Event): def sse_error(self, error: ld_eventsource.actions.Fault): 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]): + # 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") def close(self): self._polling_enabled = False From 48ccde07af9f82a4c0b86f80d0f66bf027f8fc76 Mon Sep 17 00:00:00 2001 From: Gabriella Gerges Date: Thu, 11 Dec 2025 16:00:19 -0400 Subject: [PATCH 2/3] fix: add error handling for a lost sse conenction --- devcycle_python_sdk/managers/config_manager.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/devcycle_python_sdk/managers/config_manager.py b/devcycle_python_sdk/managers/config_manager.py index 85ff769..cf4068e 100644 --- a/devcycle_python_sdk/managers/config_manager.py +++ b/devcycle_python_sdk/managers/config_manager.py @@ -82,7 +82,7 @@ def _get_config(self, last_modified: Optional[float] = None): json_config = json.dumps(self._config) 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(): self._sse_manager = SSEManager( self.sse_state, self.sse_error, @@ -128,6 +128,7 @@ def run(self): time.sleep(self._options.config_polling_interval_ms / 1000.0) def sse_message(self, message: ld_eventsource.actions.Event): + # Received a message from the SSE stream but our sse_connected is False, so we need to set it to True if not self._sse_connected: self.sse_state(None) logger.info(f"DevCycle: Received message: {message.data}") @@ -142,10 +143,10 @@ def sse_message(self, message: ld_eventsource.actions.Event): self._get_config(dvc_data["lastModified"] / 1000.0) def sse_error(self, error: ld_eventsource.actions.Fault): + self._sse_connected = False logger.debug(f"DevCycle: Received SSE error: {error}") 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") From 0e3f67eb79163338d7669582b3902a79ed6eeb06 Mon Sep 17 00:00:00 2001 From: Gabriella Gerges Date: Thu, 11 Dec 2025 17:34:21 -0400 Subject: [PATCH 3/3] formatting --- devcycle_python_sdk/managers/config_manager.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/devcycle_python_sdk/managers/config_manager.py b/devcycle_python_sdk/managers/config_manager.py index cf4068e..d688620 100644 --- a/devcycle_python_sdk/managers/config_manager.py +++ b/devcycle_python_sdk/managers/config_manager.py @@ -82,7 +82,10 @@ def _get_config(self, last_modified: Optional[float] = None): json_config = json.dumps(self._config) self._local_bucketing.store_config(json_config) if not self._options.disable_realtime_updates: - if self._sse_manager is None or not self._sse_manager.client.is_connected(): + if ( + self._sse_manager is None + or not self._sse_manager.client.is_connected() + ): self._sse_manager = SSEManager( self.sse_state, self.sse_error,