Skip to content

Commit b9fcb4c

Browse files
fix: Only record environment ID from successful responses
Co-Authored-By: rlamb@launchdarkly.com <4955475+kinyoklion@users.noreply.github.com>
1 parent d2bf632 commit b9fcb4c

5 files changed

Lines changed: 12 additions & 20 deletions

File tree

ldclient/impl/datasource/streaming.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,6 @@ def run(self):
9494
log.info("StreamingUpdateProcessor initialized ok.")
9595
self._ready.set()
9696
elif isinstance(action, Fault):
97-
record_environment_id(self._data_source_update_sink, action.headers)
98-
9997
# If the SSE client detects the stream has closed, then it will emit a fault with no-error. We can
10098
# ignore this since we want the connection to continue.
10199
if action.error is None:

ldclient/impl/datasystem/fdv2.py

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,7 @@
2121
from ldclient.impl.listeners import Listeners
2222
from ldclient.impl.repeating_task import RepeatingTask
2323
from ldclient.impl.rwlock import ReadWriteLock
24-
from ldclient.impl.util import (
25-
_LD_ENVID_HEADER,
26-
_LD_FD_FALLBACK_HEADER,
27-
_Fail,
28-
log
29-
)
24+
from ldclient.impl.util import _LD_FD_FALLBACK_HEADER, _Fail, log
3025
from ldclient.interfaces import (
3126
DataSourceErrorInfo,
3227
DataSourceErrorKind,
@@ -222,8 +217,6 @@ def _run_initializers(self, set_on_ready: Event) -> bool:
222217

223218
if isinstance(basis_result, _Fail):
224219
log.warning("Initializer %s failed: %s", initializer.name, basis_result.error)
225-
if basis_result.headers is not None:
226-
self._record_environment_id(basis_result.headers.get(_LD_ENVID_HEADER))
227220
# An error response can still carry the FDv1 fallback directive.
228221
if basis_result.headers is not None and \
229222
basis_result.headers.get(_LD_FD_FALLBACK_HEADER) == 'true':
@@ -422,7 +415,8 @@ def reader(self: 'FDv2'):
422415
if self._stop_event.is_set():
423416
return ConditionDirective.FALLBACK
424417

425-
self._record_environment_id(update.environment_id)
418+
if update.state == DataSourceState.VALID:
419+
self._record_environment_id(update.environment_id)
426420

427421
# Handle the update
428422
if update.change_set is not None:
@@ -509,7 +503,7 @@ def _persistent_store_outage_recovery(self, data_store_status: DataStoreStatus):
509503
log.error("Failed to reinitialize data store", exc_info=err)
510504

511505
def _record_environment_id(self, environment_id: Optional[str]):
512-
if environment_id is None:
506+
if not isinstance(environment_id, str) or environment_id == '':
513507
return
514508

515509
with self._lock.write():

ldclient/testing/impl/datasource/test_polling_processor.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ def test_records_environment_id_from_polling_headers():
165165
sink = DataSourceUpdateSinkImpl(store, Listeners(), Listeners())
166166
config._data_source_update_sink = sink
167167
setup_processor(config)
168-
ready.wait()
168+
assert ready.wait(2)
169169

170170
assert sink.environment_id == 'env-abc-123'
171171

@@ -177,6 +177,6 @@ def test_environment_id_is_none_when_requester_provides_no_headers():
177177
sink = DataSourceUpdateSinkImpl(store, Listeners(), Listeners())
178178
config._data_source_update_sink = sink
179179
setup_processor(config)
180-
ready.wait()
180+
assert ready.wait(2)
181181

182182
assert sink.environment_id is None

ldclient/testing/impl/datasource/test_streaming.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,7 @@ def test_environment_id_is_none_when_not_provided():
472472
assert sink.environment_id is None
473473

474474

475-
def test_records_environment_id_from_error_response_headers():
475+
def test_does_not_record_environment_id_from_error_response_headers():
476476
store = InMemoryFeatureStore()
477477
ready = Event()
478478

@@ -487,7 +487,7 @@ def test_records_environment_id_from_error_response_headers():
487487
with StreamingUpdateProcessor(config, store, ready, None) as sp:
488488
sp.start()
489489
ready.wait(start_wait)
490-
assert sink.environment_id == 'env-from-error'
490+
assert sink.environment_id is None
491491

492492

493493
def expect_item(store, kind, item):

ldclient/testing/impl/datasystem/test_fdv2_datasystem.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -786,7 +786,7 @@ def test_environment_id_from_initializer_basis():
786786
fdv2.stop()
787787

788788

789-
def test_environment_id_from_initializer_error_headers():
789+
def test_environment_id_is_not_recorded_from_initializer_error_headers():
790790
init = _StaticInitializer(
791791
"failing-initializer",
792792
_Fail(error="boom", exception=None, headers={_LD_ENVID_HEADER: 'env-from-error'}),
@@ -801,7 +801,7 @@ def test_environment_id_from_initializer_error_headers():
801801
fdv2.start(set_on_ready)
802802
assert set_on_ready.wait(1), "Data system did not become ready in time"
803803

804-
assert fdv2.environment_id == 'env-from-error'
804+
assert fdv2.environment_id is None
805805
fdv2.stop()
806806

807807

@@ -826,13 +826,13 @@ def test_environment_id_from_synchronizer_update():
826826
fdv2.stop()
827827

828828

829-
def test_environment_id_is_retained_when_updates_omit_it():
829+
def test_environment_id_is_not_recorded_from_non_valid_updates():
830830
sync_mock: Synchronizer = Mock()
831831
sync_mock.name = "envid-sync"
832832
sync_mock.stop = Mock()
833833
sync_mock.sync.return_value = iter([
834834
Update(state=DataSourceState.VALID, environment_id="env-from-sync"),
835-
Update(state=DataSourceState.INTERRUPTED),
835+
Update(state=DataSourceState.INTERRUPTED, environment_id="env-from-interrupted"),
836836
])
837837

838838
fdv2 = FDv2(

0 commit comments

Comments
 (0)