Skip to content

Commit e69a17e

Browse files
committed
refactor: keep shutdown synchronization minimal
1 parent 68864cc commit e69a17e

2 files changed

Lines changed: 18 additions & 38 deletions

File tree

‎featbit_openfeature/provider.py‎

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,7 @@ def __init__(self, client: FBClient, initialization_timeout: float = 15.0):
6262
self._initialization_timeout = initialization_timeout
6363
self._context_converter = EvaluationContextConverter()
6464
self._details_converter = ResolutionDetailsConverter()
65-
# Listener registration and event emission can synchronously re-enter
66-
# provider lifecycle methods through user callbacks.
67-
self._lifecycle_lock = threading.RLock()
65+
self._lifecycle_lock = threading.Lock()
6866
self._shutdown_started = False
6967
self._flag_change_listener: _FlagChangeListener | None = None
7068
self._status_listener_registered = False
@@ -295,12 +293,9 @@ def _register_listeners(self) -> None:
295293

296294
def _emit_configuration_changed(self, flag_key: str) -> None:
297295
try:
298-
with self._lifecycle_lock:
299-
if self._shutdown_started:
300-
return
301-
self.emit_provider_configuration_changed(
302-
ProviderEventDetails(flags_changed=[flag_key])
303-
)
296+
self.emit_provider_configuration_changed(
297+
ProviderEventDetails(flags_changed=[flag_key])
298+
)
304299
except Exception:
305300
logger.exception("Failed to emit OpenFeature configuration change event")
306301

@@ -309,19 +304,19 @@ def _handle_data_update_status(self, state: State) -> None:
309304
with self._lifecycle_lock:
310305
if self._shutdown_started:
311306
return
312-
if state.state_type == StateType.OK:
313-
self.emit_provider_ready(ProviderEventDetails())
314-
elif state.state_type == StateType.INTERRUPTED:
315-
self.emit_provider_stale(
316-
ProviderEventDetails(message=self._state_message(state))
317-
)
318-
elif state.state_type == StateType.OFF:
319-
self.emit_provider_error(
320-
ProviderEventDetails(
321-
error_code=ErrorCode.PROVIDER_FATAL,
322-
message=self._state_message(state),
323-
)
307+
if state.state_type == StateType.OK:
308+
self.emit_provider_ready(ProviderEventDetails())
309+
elif state.state_type == StateType.INTERRUPTED:
310+
self.emit_provider_stale(
311+
ProviderEventDetails(message=self._state_message(state))
312+
)
313+
elif state.state_type == StateType.OFF:
314+
self.emit_provider_error(
315+
ProviderEventDetails(
316+
error_code=ErrorCode.PROVIDER_FATAL,
317+
message=self._state_message(state),
324318
)
319+
)
325320
except Exception:
326321
logger.exception("Failed to emit OpenFeature provider status event")
327322

‎tests/test_provider.py‎

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
from concurrent.futures import ThreadPoolExecutor
2-
from threading import Event, Thread
32
from unittest.mock import Mock
43

54
import pytest
@@ -258,30 +257,16 @@ def test_shutdown_never_exposes_client_stop_failure():
258257
client.stop.assert_called_once_with()
259258

260259

261-
def test_shutdown_prevents_concurrent_listener_registration_and_events():
260+
def test_shutdown_prevents_listener_registration_and_status_events():
262261
client = make_client()
263262
provider = FeatBitProvider(client)
264263
emitter = Mock()
265264
provider.attach(emitter)
266-
stop_entered = Event()
267-
release_stop = Event()
268-
269-
def blocking_stop():
270-
stop_entered.set()
271-
release_stop.wait(timeout=2)
272-
273-
client.stop.side_effect = blocking_stop
274-
shutdown_thread = Thread(target=provider.shutdown)
275-
shutdown_thread.start()
276-
assert stop_entered.wait(timeout=2)
265+
provider.shutdown()
277266

278267
provider._register_listeners()
279268
provider._handle_data_update_status(State.ok_state())
280-
provider._emit_configuration_changed("checkout")
281269

282-
release_stop.set()
283-
shutdown_thread.join(timeout=2)
284-
assert not shutdown_thread.is_alive()
285270
client.update_status_provider.add_listener.assert_not_called()
286271
client.flag_tracker.add_flag_changed_listener.assert_not_called()
287272
emitter.assert_not_called()

0 commit comments

Comments
 (0)