3838)
3939from ldclient .impl .http import HTTPFactory , _http_factory
4040from ldclient .impl .util import (
41+ _LD_ENVID_HEADER ,
42+ _LD_FD_FALLBACK_HEADER ,
4143 http_error_message ,
4244 is_http_error_recoverable ,
4345 log
5860
5961STREAMING_ENDPOINT = "/sdk/stream"
6062
61-
6263SseClientBuilder = Callable [[Config , SelectorStore ], SSEClient ]
6364
6465
@@ -154,29 +155,35 @@ def sync(self, ss: SelectorStore) -> Generator[Update, None, None]:
154155 if action .error is None :
155156 continue
156157
157- (update , should_continue ) = self ._handle_error (action .error )
158+ envid = action .headers .get (_LD_ENVID_HEADER ) if action .headers is not None else None
159+
160+ (update , should_continue ) = self ._handle_error (action .error , envid )
158161 if update is not None :
159162 yield update
160163
161164 if not should_continue :
162165 break
163166 continue
164167
168+ envid = None
165169 if isinstance (action , Start ) and action .headers is not None :
166- fallback = action .headers .get ('X-LD-FD-Fallback' ) == 'true'
170+ fallback = action .headers .get (_LD_FD_FALLBACK_HEADER ) == 'true'
171+ envid = action .headers .get (_LD_ENVID_HEADER )
172+
167173 if fallback :
168174 self ._record_stream_init (True )
169175 yield Update (
170176 state = DataSourceState .OFF ,
171- revert_to_fdv1 = True
177+ revert_to_fdv1 = True ,
178+ environment_id = envid ,
172179 )
173180 break
174181
175182 if not isinstance (action , Event ):
176183 continue
177184
178185 try :
179- update = self ._process_message (action , change_set_builder )
186+ update = self ._process_message (action , change_set_builder , envid )
180187 if update is not None :
181188 self ._record_stream_init (False )
182189 self ._connection_attempt_start_time = None
@@ -187,7 +194,7 @@ def sync(self, ss: SelectorStore) -> Generator[Update, None, None]:
187194 )
188195 self ._sse .interrupt ()
189196
190- (update , should_continue ) = self ._handle_error (e )
197+ (update , should_continue ) = self ._handle_error (e , envid )
191198 if update is not None :
192199 yield update
193200 if not should_continue :
@@ -204,7 +211,7 @@ def sync(self, ss: SelectorStore) -> Generator[Update, None, None]:
204211 DataSourceErrorKind .UNKNOWN , 0 , time (), str (e )
205212 ),
206213 revert_to_fdv1 = False ,
207- environment_id = None , # TODO(sdk-1410)
214+ environment_id = envid ,
208215 )
209216
210217 self ._sse .close ()
@@ -226,7 +233,7 @@ def _record_stream_init(self, failed: bool):
226233
227234 # pylint: disable=too-many-return-statements
228235 def _process_message (
229- self , msg : Event , change_set_builder : ChangeSetBuilder
236+ self , msg : Event , change_set_builder : ChangeSetBuilder , envid : Optional [ str ]
230237 ) -> Optional [Update ]:
231238 """
232239 Processes a single message from the SSE stream and returns an Update
@@ -247,7 +254,7 @@ def _process_message(
247254 change_set_builder .expect_changes ()
248255 return Update (
249256 state = DataSourceState .VALID ,
250- environment_id = None , # TODO(sdk-1410)
257+ environment_id = envid ,
251258 )
252259 return None
253260
@@ -293,13 +300,13 @@ def _process_message(
293300 return Update (
294301 state = DataSourceState .VALID ,
295302 change_set = change_set ,
296- environment_id = None , # TODO(sdk-1410)
303+ environment_id = envid ,
297304 )
298305
299306 log .info ("Unexpected event found in stream: %s" , msg .event )
300307 return None
301308
302- def _handle_error (self , error : Exception ) -> Tuple [Optional [Update ], bool ]:
309+ def _handle_error (self , error : Exception , envid : Optional [ str ] ) -> Tuple [Optional [Update ], bool ]:
303310 """
304311 This method handles errors that occur during the streaming process.
305312
@@ -328,7 +335,7 @@ def _handle_error(self, error: Exception) -> Tuple[Optional[Update], bool]:
328335 DataSourceErrorKind .INVALID_DATA , 0 , time (), str (error )
329336 ),
330337 revert_to_fdv1 = False ,
331- environment_id = None , # TODO(sdk-1410)
338+ environment_id = envid ,
332339 )
333340 return (update , True )
334341
@@ -344,11 +351,15 @@ def _handle_error(self, error: Exception) -> Tuple[Optional[Update], bool]:
344351 str (error ),
345352 )
346353
347- if error .headers is not None and error .headers .get ("X-LD-FD-Fallback" ) == 'true' :
354+ if envid is None and error .headers is not None :
355+ envid = error .headers .get (_LD_ENVID_HEADER )
356+
357+ if error .headers is not None and error .headers .get (_LD_FD_FALLBACK_HEADER ) == 'true' :
348358 update = Update (
349359 state = DataSourceState .OFF ,
350360 error = error_info ,
351- revert_to_fdv1 = True
361+ revert_to_fdv1 = True ,
362+ environment_id = envid ,
352363 )
353364 return (update , False )
354365
@@ -364,7 +375,7 @@ def _handle_error(self, error: Exception) -> Tuple[Optional[Update], bool]:
364375 ),
365376 error = error_info ,
366377 revert_to_fdv1 = False ,
367- environment_id = None , # TODO(sdk-1410)
378+ environment_id = envid ,
368379 )
369380
370381 if not is_recoverable :
@@ -386,7 +397,7 @@ def _handle_error(self, error: Exception) -> Tuple[Optional[Update], bool]:
386397 DataSourceErrorKind .UNKNOWN , 0 , time (), str (error )
387398 ),
388399 revert_to_fdv1 = False ,
389- environment_id = None , # TODO(sdk-1410)
400+ environment_id = envid ,
390401 )
391402 # no stacktrace here because, for a typical connection error, it'll
392403 # just be a lengthy tour of urllib3 internals
@@ -411,5 +422,4 @@ def __init__(self, config: Config):
411422
412423 def build (self ) -> StreamingDataSource :
413424 """Builds a StreamingDataSource instance with the configured parameters."""
414- # TODO(fdv2): Add in the other controls here.
415425 return StreamingDataSource (self ._config )
0 commit comments