-
Notifications
You must be signed in to change notification settings - Fork 14
feat!: add provider eventing, remove setProvider timeout #207
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?
feat!: add provider eventing, remove setProvider timeout #207
Conversation
Summary of ChangesHello @sameerank, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request addresses a critical issue where the Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
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.
Code Review
This pull request is a significant and well-executed enhancement that introduces a provider eventing system, aligning the Ruby SDK more closely with the OpenFeature specification. The core improvement is fixing set_provider_and_wait to correctly block until a provider is ready, which is achieved through a robust, thread-safe event mechanism using EventEmitter, ProviderStateRegistry, and new provider interfaces (EventHandler, StateHandler). The changes are thoughtfully designed to be backward-compatible, and the comprehensive new test suite, including specification compliance tests, is excellent.
My feedback focuses on a few areas to further improve robustness and maintainability: refining exception handling to be more specific, enhancing debuggability by preserving original error information in event payloads, and cleaning up a small amount of unused code.
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.
Code Review
This pull request is a fantastic and significant improvement. It correctly implements the provider eventing system as specified by OpenFeature, fixing the broken behavior of set_provider_and_wait. The introduction of EventEmitter, EventHandler, and state management is well-structured and thread-safe. The changes are also backward compatible, which is a huge plus. The test coverage for the new asynchronous logic is thorough. I've found a few minor but important issues related to overly broad exception handling (rescue => e) and a small redundancy in event payload creation, which I've commented on. Once these are addressed, this PR will be in excellent shape.
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.
Code Review
This is an excellent pull request that introduces a provider eventing system, aligning the Ruby SDK more closely with the OpenFeature specification. The implementation correctly fixes the behavior of set_provider_and_wait and makes set_provider non-blocking, which is a great improvement for providers requiring asynchronous initialization. The code is well-structured, with clear separation of concerns into new modules and classes for eventing and state management. The test coverage is comprehensive and thoughtful, especially the tests for backward compatibility and specification compliance.
I have identified a few areas for improvement, primarily focusing on enhancing thread safety and encapsulation. Specifically, I've pointed out a potential race condition in the error handling of set_provider_and_wait and suggested a way to improve how the logger is managed. These changes will make the implementation more robust in concurrent environments. Overall, this is a very strong contribution.
- Add ProviderEvent module with event type constants (PROVIDER_READY, etc.) - Add ProviderState module with state constants (NOT_READY, READY, ERROR, etc.) - Implement EventEmitter class for thread-safe pub-sub event handling - Add EventToStateMapper for mapping events to provider states - Include comprehensive test coverage for all components This introduces the event infrastructure needed for OpenFeature spec-compliant provider lifecycle management. The implementation is additive only, maintaining full backward compatibility with existing provider behavior. Signed-off-by: Sameeran Kunche <sameeran.kunche@datadoghq.com>
Add mixins and classes to support provider lifecycle management: - StateHandler: Basic provider lifecycle interface with init/shutdown - EventHandler: Event emission capability for providers - ContextAwareStateHandler: Timeout support for initialization - ProviderStateRegistry: Thread-safe provider state tracking - EventAwareNoOpProvider: Example implementation demonstrating interfaces These interfaces enable providers to emit lifecycle events and support both synchronous and asynchronous initialization patterns while maintaining backward compatibility with existing providers. Signed-off-by: Sameeran Kunche <sameeran.kunche@datadoghq.com>
- Fix context_aware_state_handler_spec to expect both positional and keyword arguments - Add newlines to end of provider files for consistency - Add arm64-darwin-24 platform support to Gemfile.lock Signed-off-by: Sameeran Kunche <sameeran.kunche@datadoghq.com>
…ycle Refactor provider lifecycle to be truly asynchronous: - set_provider now returns immediately and initializes providers in background - set_provider_and_wait uses event system to block until initialization completes - Providers emit PROVIDER_READY/PROVIDER_ERROR events on initialization - Event handlers enable non-blocking application startup patterns - Maintains backward compatibility with existing providers The implementation follows OpenFeature specification requirements: - setProvider is non-blocking (returns immediately) - setProviderAndWait blocks until provider is ready or errors - Provider state transitions are tracked via events - Failed initialization properly restores previous provider state Added comprehensive test coverage for async behavior, error handling, event emission, and backward compatibility scenarios. Signed-off-by: Sameeran Kunche <sameeran.kunche@datadoghq.com>
…fecycle Add specification tests for requirements implemented in this branch: - Requirement 1.1.2.4: set_provider_and_wait blocking behavior - Requirement 2.4.2.1: Provider initialization error handling - Requirement 5.x: Provider lifecycle events and handlers The tests follow Ruby SDK's existing pattern of using RSpec contexts to organize tests by specification requirements. This provides clear traceability between implementation and specification compliance. Also exposed add_handler/remove_handler methods on the SDK API to support event specification tests. Signed-off-by: Sameeran Kunche <sameeran.kunche@datadoghq.com>
- Remove verbose method documentation from event_emitter.rb - Remove detailed parameter descriptions from provider modules - Remove implementation comments from configuration.rb - Keep only essential comments explaining non-obvious behavior - Maintain brief class/module descriptions where helpful Follows minimalist Ruby documentation style used throughout the codebase Signed-off-by: Sameeran Kunche <sameeran.kunche@datadoghq.com>
- Replace bare rescue with rescue StandardError in configuration.rb - Add ProviderInitializationFailure class for structured error details - Pass error codes and messages in events (not full exceptions) - Add configurable logger support to Configuration and EventEmitter - Remove unused state_from_error and fatal_error? methods These changes address all issues identified by the Gemini code review bot while maintaining alignment with other OpenFeature SDKs (Go and Java). Signed-off-by: Sameeran Kunche <sameeran.kunche@datadoghq.com>
…l value - ContextAwareStateHandler was just a placeholder that only included StateHandler - Other SDKs (Go, Java) don't expose timeout methods on provider interfaces - Timeouts are controlled at the API level (set_provider_and_wait), not provider level - Providers can implement their own internal timeout logic if needed - Also removed unused state_from_error tests that were causing failures Signed-off-by: Sameeran Kunche <sameeran.kunche@datadoghq.com>
- Replace overly broad 'rescue => e' with 'rescue StandardError => e' in 3 files to avoid catching system-level exceptions like Interrupt and SystemExit - Remove redundant provider merge in event_handler.rb since provider is already passed as first argument to dispatch_event - Update tests to match the simplified event dispatching Signed-off-by: Sameeran Kunche <sameeran.kunche@datadoghq.com>
- Fix race conditions in set_provider_and_wait by adding revert_provider_if_current method that only reverts if the current provider matches the one being set - Improve encapsulation by adding attr_writer :logger to EventEmitter instead of using instance_variable_set - Add logging for provider shutdown errors for better debugging visibility - Update test coverage in PR description to 98.73% (468/474 LOC) Signed-off-by: Sameeran Kunche <sameeran.kunche@datadoghq.com>
d5d4c34 to
6eefe78
Compare
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.
Code Review
This is an excellent and comprehensive pull request that addresses a critical issue with set_provider_and_wait and brings the Ruby SDK much closer to the OpenFeature specification for provider eventing. The introduction of an asynchronous, event-driven provider lifecycle is a significant improvement.
I'm impressed by the thoroughness of the implementation, including:
- Thread-safe event emitter and state management.
- Correct handling of asynchronous initialization and error conditions.
- Thoughtful approach to backward compatibility, allowing old providers to function without modification.
- Extensive test coverage, including tests for concurrency, which gives high confidence in these complex changes.
I have one suggestion regarding the creation of the event dispatcher in Configuration#set_provider to improve code clarity and maintainability.
Overall, this is a high-quality contribution that significantly enhances the SDK's functionality and robustness.
- Replace dynamic Object creation with singleton methods with a proper private inner class - Improves code clarity, maintainability, and performance - Follows Ruby idioms for encapsulation - Suggested by Gemini code review Signed-off-by: Sameeran Kunche <sameeran.kunche@datadoghq.com>
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.
Code Review
This pull request introduces a comprehensive provider eventing system, which is a significant and well-executed feature. It successfully fixes the behavior of set_provider_and_wait to be truly blocking and aligns the SDK with the OpenFeature specification for provider events. The implementation includes a thread-safe event emitter, new provider mixins for lifecycle management, and asynchronous provider initialization, all supported by a thorough test suite. I've identified a couple of critical scoping issues that would cause runtime errors and a minor opportunity for code cleanup. Overall, this is an excellent contribution to the SDK.
…tests - Remove EventAwareNoOpProvider as it doesn't exist in other OpenFeature SDKs - Rename provider_backward_compatibility_spec.rb to provider_compatibility_spec.rb - Reorganize tests into three logical sections: - Providers Without Event Capabilities - Mixed Provider Usage - Provider Interface Detection - Update all references and imports accordingly - Maintain 99.13% test coverage Signed-off-by: Sameeran Kunche <sameeran.kunche@datadoghq.com>
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.
Code Review
This is a fantastic pull request that brings the Ruby SDK much closer to the OpenFeature specification for provider events and lifecycle. The implementation of an async set_provider and a truly blocking set_provider_and_wait using a thread-safe event system is well-executed. The code is clean, modular, and impressively well-tested, covering backward compatibility, thread safety, and specification requirements.
I've found two potential race conditions with high severity that should be addressed:
- In
Configuration#set_provider_and_wait, there's a race condition that could lead to incorrect provider state restoration on initialization failure. - In
Provider::EventHandler#emit_event, a race condition could lead to aNoMethodErrorif a provider is detached concurrently.
After addressing these concurrency issues, this PR will be a very strong and valuable addition to the SDK. Great work on the thoroughness and quality of this change.
- Fix race condition in set_provider_and_wait where stale provider could be restored - Modified set_provider to return the old provider atomically - set_provider_and_wait now uses the atomically-retrieved old provider - Fix race condition in EventHandler#emit_event - Store @event_dispatcher in local variable before check and use - Prevents NoMethodError if detach is called between check and method call These changes ensure thread-safe operation under concurrent access patterns. Signed-off-by: Sameeran Kunche <sameeran.kunche@datadoghq.com>
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.
Code Review
This is an excellent and comprehensive implementation of the provider eventing system, aligning the Ruby SDK more closely with the OpenFeature specification. The changes are well-structured, thread-safe, and maintain backward compatibility. The introduction of EventEmitter, StateHandler, and EventHandler provides a solid foundation for asynchronous providers. The new test suites are thorough and cover many edge cases, which is great to see.
I've found one critical issue related to handling nil providers during shutdown and have one suggestion to improve the maintainability of the new test files. Overall, this is a very strong contribution.
Critical fixes: - Fix NoMethodError when old_provider is nil during shutdown - Use safe navigation operators (&.) for nil provider handling - Add test coverage for setting provider to domain with no previous provider API improvements: - Refactor API class to follow OpenFeature SDK patterns - Replace long def_delegators list with explicit methods - Add clear_all_handlers method for improved test cleanup - Align with Go SDK's individual function approach vs bulk delegation All tests passing with 98.74% coverage maintained. Signed-off-by: Sameeran Kunche <sameeran.kunche@datadoghq.com>
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.
Code Review
This pull request introduces a comprehensive event handling and provider state management system to the OpenFeature SDK. The set_provider method is now asynchronous, initializing providers in a separate thread, while a new set_provider_and_wait method provides blocking initialization with timeout and error handling, including reverting to the previous provider on failure. This is achieved through new EventEmitter and ProviderStateRegistry classes, along with EventHandler and StateHandler mixins for providers to implement event emission and lifecycle methods. The API now exposes methods for managing event handlers and configuring the logger. Review comments suggest enhancing error and warning messages in Configuration by including the provider's class name for improved debugging, and raise a concern about the fragility of relying on init method arity for argument handling.
Address Gemini code review feedback:
Error message improvements:
- Include provider class names in all error messages for better debugging
- 'Provider #{provider.class.name} initialization failed: #{message}'
- 'Provider #{provider.class.name} initialization timed out after #{timeout} seconds'
Init parameter handling improvements:
- Replace fragile arity check with robust try/fallback approach
- Always attempt init(evaluation_context) first (OpenFeature standard)
- Fallback to init() only for legacy providers with 0-arity methods
- Properly handle edge cases like providers expecting 2+ parameters
- Update InMemoryProvider to accept optional evaluation_context parameter
This ensures backward compatibility while aligning with OpenFeature spec
and providing clear error messages for debugging multi-provider scenarios.
Signed-off-by: Sameeran Kunche <sameeran.kunche@datadoghq.com>
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.
Code Review
This is a substantial and well-executed feature addition. It correctly implements the provider eventing system according to the OpenFeature specification, which fixes the behavior of set_provider_and_wait. The use of Thread for async initialization, Queue for synchronization, and Mutex for protecting shared state is well-handled. The new modules and classes (EventEmitter, EventHandler, ProviderStateRegistry, etc.) are well-structured and promote good design patterns. Backward compatibility for existing providers is also thoughtfully implemented. The test coverage is excellent, with new unit tests, async-specific tests, and specification compliance tests. I have a couple of suggestions for minor refactoring to improve robustness and simplify the code, but overall this is a high-quality contribution.
- Replace fragile error message matching with robust method parameter inspection - Simplify EventToStateMapper by removing EventDetails class and working with hashes directly - Standardize on symbol keys for event details since they are generated internally - Remove unnecessary string key support to reduce complexity Signed-off-by: Sameeran Kunche <sameeran.kunche@datadoghq.com>
65ee77b to
2611c40
Compare
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.
Code Review
This is an excellent pull request that implements a comprehensive provider eventing system, correctly fixing the behavior of set_provider_and_wait. The changes are well-structured, thoroughly tested, and align with the OpenFeature specification. The use of background threads for initialization, Queue for synchronization, and careful handling of backward compatibility are all well-executed. My feedback is minor, focusing on improving consistency by using defined constants instead of string literals in a couple of places.
* Add client-level event handler methods (add_handler/remove_handler) to Client class * Implement domain-scoped client handlers using client-instance-based storage pattern * Restructure event dispatch with unified run_handlers_for_provider approach * Add immediate handler execution (Requirement 5.3.3) for handlers added to ready providers * Create extract_provider_name helper to DRY up provider name extraction logic * Update event details format for consistency across SDKs * Achieve full OpenFeature specification compliance for all 9 event requirements Signed-off-by: Sameeran Kunche <sameeran.kunche@datadoghq.com>
2460bda to
bfb771d
Compare
- Replace run_immediate_handler_for_api and run_immediate_handler with single unified method - Update method signature to require explicit client parameter (nil for API-level) - Fix test isolation by clearing provider state in client event handler tests - Update test expectations to account for immediate handler execution - Remove unused default parameters from helper methods Signed-off-by: Sameeran Kunche <sameeran.kunche@datadoghq.com>
4e492cc to
31ddc6f
Compare
|
|
||
| if event_type == status_to_event[provider_state] | ||
| provider_name = extract_provider_name(provider) | ||
| event_details = {provider_name: provider_name} |
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.
I concede that it is odd to have a hash with just one attribute, but when I look through the SDKs provider_name seems to be the only consistent attribute in all of them. E.g.
export type CommonEventDetails = {
readonly providerName: string;
/**
* @deprecated alias of "domain", use domain instead
*/
readonly clientName?: string;
readonly domain?: string;
};
type EventDetails struct {
ProviderName string
ProviderEventDetails
}
class EventDetails(ProviderEventDetails):
provider_name: str = ""
flags_changed: typing.Optional[list[str]] = None
message: typing.Optional[str] = None
error_code: typing.Optional[ErrorCode] = None
metadata: dict[str, typing.Union[bool, str, int, float]] = field(
default_factory=dict
)
And this is the only one marked as "required" in the spec https://openfeature.dev/specification/types#event-details
So I'm thinking it's okay to keep this minimal for now and add the others later
- Mark client handler methods as @api private - Move clear_all_handlers to private section - Remove clear_all_handlers from public API - Align global handler immediate execution with JS SDK pattern Signed-off-by: Sameeran Kunche <sameeran.kunche@datadoghq.com>
|
|
||
| def add_handler(event_type, handler) | ||
| @event_emitter.add_handler(event_type, handler) | ||
| run_immediate_handler(event_type, handler, nil) |
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.
The SDKs vary in how they interpreted Requirement 5.3.3 for the immediate invocation of the handler
Handlers attached after the provider is already in the associated state, MUST run immediately.
The python-sdk only runs the handler on the default provider-client.
def add_global_handler(event: ProviderEvent, handler: EventHandler) -> None:
with _global_lock:
_global_handlers[event].append(handler)
from openfeature.api import get_client # noqa: PLC0415
_run_immediate_handler(get_client(), event, handler)
e.emitOnRegistration(defaultDomain, e.defaultProviderReference, t, c)
These are effectively treating the following the two scenarios as the same at the time of adding a global handler
from openfeature import api; client = api.get_client(); client.add_handler(...from openfeature import api; api.add_handler(...
But later, events from any provider can trigger the global handler even if they didn't at the time of adding the global handler.
The js-client takes a different approach and checks all the providers.
[...new Map([[undefined, this._defaultProvider]]), ...this._domainScopedProviders].forEach((keyProviderTuple) => {
I went with the js-client's approach because it makes more sense to me, to not have two ways of doing the same thing, and also it feels more consistent for an API-level handler to behave "global" in scope both at the time of being added, and later when domain-scoped providers trigger the global handler
ea4675f to
c5a117b
Compare
…terns - Add timecop gem (v0.9.10) for time manipulation in race condition tests - Replace set_provider + sleep patterns with set_provider_and_wait for synchronous initialization - Replace arbitrary sleeps with condition-based waiting (sleep(0.001) until condition) - Remove unnecessary comments and fix linting issues - Maintain fast test execution while ensuring reliable synchronization Signed-off-by: Sameeran Kunche <sameeran.kunche@datadoghq.com>
c5a117b to
4bc1557
Compare
- Move attach/detach to private section as internal SDK methods - Update Configuration to use send() for private method calls - Remove from specification tests (not required by OpenFeature) - Update unit tests to use send() for testing private methods Signed-off-by: Sameeran Kunche <sameeran.kunche@datadoghq.com>
- Move mutex acquisition inside set_provider_internal for better encapsulation - Minimize synchronize block duration by moving provider init outside mutex - Capture evaluation context before mutex to prevent race conditions - Improve concurrency by not blocking other operations during provider init Signed-off-by: Sameeran Kunche <sameeran.kunche@datadoghq.com>
…ability - Remove EventHandler check when emitting SDK lifecycle events - Add tests to prevent regression per OpenFeature spec section 5.3 Signed-off-by: Sameeran Kunche <sameeran.kunche@datadoghq.com>
…Requirement 5.3.5 Per OpenFeature spec Requirement 5.3.5, PROVIDER_CONFIGURATION_CHANGED events should not cause provider state transitions. Updated EventToStateMapper to return nil (no state change) for these events and unknown events, matching Java/JS SDK behavior. Signed-off-by: Sameeran Kunche <sameeran.kunche@datadoghq.com>
Move shutdown call outside synchronize block to minimize mutex hold time and add safety check to prevent race condition when setting same provider instance concurrently. Signed-off-by: Sameeran Kunche <sameeran.kunche@datadoghq.com>
| end | ||
|
|
||
| # Shutdown old provider outside mutex to avoid blocking other operations | ||
| # Only shutdown if it's a different provider to prevent race condition |
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.
The race condition scenario is multiple threads setting the same provider instance concurrently:
- Thread A:
set_provider(provider_x) - Thread B:
set_provider(provider_x)<-- same provider
What would happen without the old_provider != provider check:
- Thread A captures
old_provider = nil, because@providers = {}and setsprovider_x - Thread B captures
old_provider = provider_x, setsprovider_x(same provider) - Thread A skips shutdown because no
old_provider✅ (correct) - Thread B calls
provider_x.shutdown()❌ This is a problem because it shuts down the active provider
Tested with
| it "does not call shutdown on same provider instance when set multiple times concurrently" do |
Signed-off-by: Sameeran Kunche <sameeran.kunche@datadoghq.com>
spec/specification/events_spec.rb
Outdated
| provider1 = OpenFeature::SDK::Provider::InMemoryProvider.new | ||
| OpenFeature::SDK.set_provider_and_wait(provider1) | ||
|
|
||
| # Should be 3: 1 immediate (NoOpProvider READY) + 1 from InMemoryProvider lifecycle + 1 additional due to SDK always emitting events |
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.
The updated reset method invokes @event_dispatcher.clear_all_handlers which also clears the SDK-level handlers, which were set in other tests that do OpenFeature::SDK.add_handler
With the updated reset method, we no longer need to account for + 1 additional due to SDK because that was cleared too
- Rename Provider::EventHandler to Provider::EventEmitter for clarity - Rename SDK::EventEmitter to SDK::EventDispatcher to reflect pub-sub role - Remove ProviderEventDispatcher wrapper, use direct configuration reference - Update all tests and documentation to use new naming conventions Signed-off-by: Sameeran Kunche <sameeran.kunche@datadoghq.com>
688b0f7 to
e222491
Compare
- Change from PROVIDER_FATAL to GENERAL for initialization exceptions - Aligns with cross-SDK behavior for generic initialization errors - Update tests to expect GENERAL error code Signed-off-by: Sameeran Kunche <sameeran.kunche@datadoghq.com>
- Move test for client handler isolation to events_spec.rb for better requirement traceability - Simplify test with minimal provider and deterministic assertions Signed-off-by: Sameeran Kunche <sameeran.kunche@datadoghq.com>
Signed-off-by: Sameeran Kunche <sameeran.kunche@datadoghq.com>
|
Hey thanks again. I will take a look at this again on Monday. |
This PR
Fixes the behavior of
set_provider_and_waitand implements eventing to trigger event handlers on changes to provider state.What was wrong?
Both
set_providerandset_provider_and_waitinitialize synchronously. By fixingset_providerto be non-blocking, it is also useful to have eventing, so the SDK can be used to trigger handlers according to background provider updates.The Ruby SDK was missing the provider lifecycle event system defined in the OpenFeature specification, which other SDKs use for monitoring provider state changes and enabling event-driven workflows.
What this PR does:
set_providernon-blocking - returns immediately and initializes in a background thread, enabling async operationPROVIDER_READY,PROVIDER_ERROR, etc.) as defined in the Events specification to enable event-driven workflowsNOT_READY,READY,ERROR,FATAL,STALE) as defined in the Provider Status specificationtimeoutparameter fromset_provider_and_waitto align with other OpenFeature SDKs (Go and Java don't support timeouts)Key changes:
Event System Foundation:
EventEmitter- thread-safe pub/sub for provider events (based on Go SDK's eventExecutor)ProviderEventconstants matching the Events specificationEventToStateMapperfor state transitions per Provider Status specificationProvider Interface (opt-in via mixin, based on Go SDK patterns):
EventHandler- event emission capabilities based on Go's EventHandlerProvider Initialization:
init()methods are expected to block until readyOpenFeature::SDK.set_provider(provider)- runs init in background thread (non-blocking API call)OpenFeature::SDK.set_provider_and_wait(provider)- runs init synchronously and blocks until complete (Req 1.1.2.4)Error Handling and Logging:
StandardErroronly, not all exceptions)ProviderInitializationErrorexception forset_provider_and_waitfailures with structured error details (provider,error_code,original_error){error_code:, message:}) similar to Java's ProviderEventDetailsconfig.logger = my_logger) - Note: Go SDK deprecated SetLogger, Java uses SLF4J facadeTesting:
Related Issues
Fixes #51
Notes
timeoutparameter inset_provider_and_waitFollow-up Tasks
Consider adding client-level event handlers (currently only API-level) as described in Req 5.2.1bfb771dHow to test