-
Notifications
You must be signed in to change notification settings - Fork 43
fix: thread safety issues #614
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
793123b
d1e88b7
67b5fc4
5d11dbc
22d9583
027a326
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,3 +1,5 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| import threading | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| from openfeature.evaluation_context import EvaluationContext | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| from openfeature.transaction_context.context_var_transaction_context_propagator import ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ContextVarsTransactionContextPropagator, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -21,25 +23,28 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||
| _evaluation_transaction_context_propagator: TransactionContextPropagator = ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| NoOpTransactionContextPropagator() | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| _propagator_lock = threading.RLock() | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| def set_transaction_context_propagator( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| transaction_context_propagator: TransactionContextPropagator, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) -> None: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| global _evaluation_transaction_context_propagator | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| _evaluation_transaction_context_propagator = transaction_context_propagator | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| with _propagator_lock: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| _evaluation_transaction_context_propagator = transaction_context_propagator | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| def clear_transaction_context_propagator() -> None: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| set_transaction_context_propagator(NoOpTransactionContextPropagator()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| def get_transaction_context() -> EvaluationContext: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| return _evaluation_transaction_context_propagator.get_transaction_context() | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| with _propagator_lock: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not sure about this one here, if this is really needed or not
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here, I tried to ask Claude but the answer was sometimes yes and sometimes no 😅 |
||||||||||||||||||||||||||||||||||||||||||||||||||||
| propagator = _evaluation_transaction_context_propagator | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| return propagator.get_transaction_context() | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| def set_transaction_context(evaluation_context: EvaluationContext) -> None: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| global _evaluation_transaction_context_propagator | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| _evaluation_transaction_context_propagator.set_transaction_context( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| evaluation_context | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| with _propagator_lock: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| propagator = _evaluation_transaction_context_propagator | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| propagator.set_transaction_context(evaluation_context) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
41
to
+50
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We're holding Holding it through the call serializes all transaction-context access across threads, and might be problematic especially if somebody was doing a lot in a custom propagator.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is this change needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
because of what was pointed out in the original issue:
"
AbstractProvider._on_emit(provider/__init__.py) -emit()doesif hasattr(self, "_on_emit"): self._on_emit(...)which is a TOCTOU;detach()during shutdown can delete_on_emitwhile a background thread is between the check and the call"