Uh oh!
There was an error while loading. Please reload this page.
fix: thread safety issues - #614
Conversation
Signed-off-by: Lea Konvalinka <lea.konvalinka@dynatrace.com>
Signed-off-by: Lea Konvalinka <lea.konvalinka@dynatrace.com>
Signed-off-by: Lea Konvalinka <lea.konvalinka@dynatrace.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@## main #614 +/- ##
==========================================
+ Coverage 98.34% 98.36% +0.02%
==========================================
Files 45 45 Lines 2483 2514 +31 ==========================================
+ Hits 2442 2473 +31
Misses 41 41
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (4)
💤 Files with no reviewable changes (2)
📝 WalkthroughWalkthroughThis PR adds thread-safety locks around hook list mutations and the transaction context propagator, simplifies the provider ChangesShared-state hardening
Estimated code review effort: 3 (Moderate) | ~25 minutes Related PRs: None identified. Suggested labels: bug, enhancement, tests Suggested reviewers: None identified. 🐇 A poem from the CodeRabbitA rabbit locks the burrow tight, 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Signed-off-by: Lea Konvalinka <lea.konvalinka@dynatrace.com>
0c9eb51 to
5d11dbcCompareThere was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
openfeature/provider/_registry.py (1)
99-105: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick winAvoid clearing event handlers while holding the registry lock.
clear_event_handlers()acquires_client_lock; concurrently, handler dispatch holds_client_lockwhile resolvingclient.provider, which now acquiresProviderRegistry._lock. This creates a registry-lock → client-lock path here and a client-lock → registry-lock path during dispatch, soclear_providers()can deadlock with provider event dispatch.🔒 Proposed fix
def clear_providers(self) -> None: self.shutdown() with self._lock: self._providers.clear() self._default_provider = NoOpProvider() self._provider_status = { self._default_provider: ProviderStatus.READY, } - clear_event_handlers()++ clear_event_handlers()🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@openfeature/provider/_registry.py` around lines 99 - 105, clear_providers() is calling clear_event_handlers() while still holding ProviderRegistry._lock, which creates a lock-order cycle with event dispatch. Move the clear_event_handlers() call out of the locked section in ProviderRegistry.clear_providers(), keeping only provider state updates under the lock and then clearing handlers after the lock is released. Use the ProviderRegistry._lock, clear_providers(), and clear_event_handlers() symbols to update the flow so the registry lock is never held when acquiring the client/event-handler lock.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@openfeature/transaction_context/__init__.py`:
- Around line 26-50: The transaction-context helpers can self-deadlock because
_propagator_lock is a non-reentrant Lock while get_transaction_context and
set_transaction_context invoke user-provided TransactionContextPropagator
methods under that lock. Update the locking strategy in
openfeature/transaction_context/__init__.py so re-entrant calls from custom
propagators do not block the same thread, for example by switching
_propagator_lock to an RLock and keeping the existing serialization around
set_transaction_context_propagator, get_transaction_context, and
set_transaction_context.
---
Outside diff comments:
In `@openfeature/provider/_registry.py`:
- Around line 99-105: clear_providers() is calling clear_event_handlers() while
still holding ProviderRegistry._lock, which creates a lock-order cycle with
event dispatch. Move the clear_event_handlers() call out of the locked section
in ProviderRegistry.clear_providers(), keeping only provider state updates under
the lock and then clearing handlers after the lock is released. Use the
ProviderRegistry._lock, clear_providers(), and clear_event_handlers() symbols to
update the flow so the registry lock is never held when acquiring the
client/event-handler lock.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 8e01e6e3-2b84-4dab-a926-10ec95fae6b5
📒 Files selected for processing (8)
openfeature/_event_support.pyopenfeature/api.pyopenfeature/client.pyopenfeature/hook/__init__.pyopenfeature/provider/__init__.pyopenfeature/provider/_registry.pyopenfeature/transaction_context/__init__.pytests/test_client.py
💤 Files with no reviewable changes (1)
- openfeature/api.py
Uh oh!
There was an error while loading. Please reload this page.
Signed-off-by: Lea Konvalinka <lea.konvalinka@dynatrace.com>
7f14e05 to
22d9583Compareaepfli
commented
Jun 25, 2026
I am curious, can we add a tool to detect this like vmlens in java? In the sense of automated testing? |
Uh oh!
There was an error while loading. Please reload this page.
gruebel
left a comment
There was a problem hiding this comment.
thanks 🍻 overall it looks pretty good and adds more thread safety especially when using free-threaded CPython
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Signed-off-by: Lea Konvalinka <lea.konvalinka@dynatrace.com>
leakonvalinka
commented
Jun 29, 2026
@aepfli I don't think so, unfortunetly. I did try to write a few tests and also have Claude write some with |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
gruebel
commented
Jul 7, 2026
@leakonvalinka let me know, if you need some help to finish up the last parts. I don't want you to be stuck with this PR for much longer, sorry! |
Signed-off-by: Lea Konvalinka <lea.konvalinka@dynatrace.com>
leakonvalinka
commented
Jul 8, 2026
@gruebel Thank you! I implemented the remaining feedback, if you notice something else feel free to just change it if you want. |
gruebel
left a comment
There was a problem hiding this comment.
thanks for contribution 🍻 i'll wait till end of week, if there are no other objections
Uh oh!
There was an error while loading. Please reload this page.
This PR
Related Issues
#96
Notes