feat: add Domains (formerly Clients) (#185)#231
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces domain-specific support to the Kotlin SDK, allowing providers and evaluation contexts to be isolated per domain while maintaining a global fallback mechanism. Key architectural changes include the addition of a ProviderRepository to manage DomainState and updates to OpenFeatureAPI and OpenFeatureClient to handle domain-specific logic. The review feedback highlights several critical issues regarding state isolation: specifically, ensuring that initialContext is bound to the correct domain, using domain-specific contexts during provider initialization and event tracking, and correctly propagating global context updates when no domain override exists. Additionally, there is a recommendation to handle dispatcher changes more dynamically within the domain state listener.
LoggingHook, Logger interface, and platform-specific LoggerFactory implementations are merged. PII filtering (#221) and full logging docs (#220) are still open. Domain binding (#231) is actively in development. Update status symbols from ❌ to⚠️ and rewrite the Logging and Domains sections to reflect current state.
Full logging stack (#233, #221, #220) is now merged — update Logging from⚠️ to ✅. Domain binding (#231) is actively in development — update Domains from ❌ to⚠️ and rewrite the section to reflect current state with a link to the OpenFeature Domains docs. Signed-off-by: Tyler Potter <tyler.john.potter@gmail.com>
|
Spec 3.2.2.4 requires the API to have a mechanism to manage (create and remove) evaluation context for an associated domain. There is no |
Signed-off-by: Marcin Stepien <marcin.stepien@fluxon.com>
Signed-off-by: Marcin Stepien <marcin.stepien@fluxon.com>
cache domain context merging to eliminate GC evaluation overhead Signed-off-by: Marcin Stepien <marcin.stepien@fluxon.com>
Signed-off-by: Marcin Stepien <marcin.stepien@fluxon.com>
Signed-off-by: Marcin Stepien <marcin.stepien@fluxon.com>
…#185) harden provider termination sequences against race conditions and event pollution (open-feature#185) Signed-off-by: Marcin Stepien <marcin.stepien@fluxon.com>
Spec 3.2.2.4 requires the API to have a mechanism to manage (create and remove) evaluation context for an associated domain. - Added ability to securely manage and clear evaluation contexts natively per domain. - Introduced `contextMutex` and `ioMutex` to fix global vs domain TOCTOU Deadlocks. - Ensured phantom background coroutines cancel properly on `shutdown()`. Signed-off-by: Marcin Stepien <marcin.stepien@fluxon.com>
Signed-off-by: Marcin Stepien <marcin.stepien@fluxon.com>
fixed with ca14dfa |
…n-feature#185) - Added `observeEvents()` and typed `observe<T>()` to the `Client` interface to natively route domain-bound provider events (resolves spec 5.2.1 & 5.2.7). Signed-off-by: Marcin Stepien <marcin.stepien@fluxon.com>
- 5.3.4.1: now emits `ProviderReconciling` prior to executing the provider's `onContextSet` function. - 5.3.4.2: now emits `ProviderContextChanged` if the provider's `onContextSet` function terminates normally. - 5.3.4.3: catches crashes within `onContextSet` and emits `ProviderError` instead of `ProviderContextChanged`. Signed-off-by: Marcin Stepien <marcin.stepien@fluxon.com>
open-feature#185) Spec 1.1.2.3: The provider mutator function MUST invoke the shutdown function on the previously registered provider once it's no longer being used to resolve flag values. Provider instances which are bound to multiple domains won't be shut down until the last binding is removed. - thread-safe attachProvider and detachProvider reference counting in ProviderRepository. - refactored DomainState teardown to decouple the FeatureProvider.shutdown() invocation from localized domain states. - ensured OpenFeatureAPI only invokes shutdown() when a provider's global domain reference count reaches zero. Signed-off-by: Marcin Stepien <marcin.stepien@fluxon.com>
- global reference counting and initialization mutexes in `ProviderRepository` to track shared provider lifecycles. - deduplicated `provider.initialize()` and `provider.shutdown()` calls so providers bound to multiple domains are only initialized once and shut down only when the last domain unbinds. - global status ledger that syncs background health transitions (e.g., `ProviderError` or `ProviderStale`) across all domains sharing the provider instance. - Specs 1.1.2.2: "Provider instances which are already active (because they have been bound to another domain or otherwise) need not be initialized again." - Specs 1.1.2.3: "Provider instances which are bound to multiple domains won't be shut down until the last binding is removed." Signed-off-by: Marcin Stepien <marcin.stepien@fluxon.com>
2026-04-22-23 PR Update: Multi-Domain Isolation, Lifecycle Management, and Specification ComplianceThis update brings core specification's requirements regarding isolated eventing, shared provider lifecycles, and evaluation context management. Provider Lifecycle & Deduplication
Domain-Isolated Eventing
Evaluation Context Management
Architecture Hardening & Tech Debt
|
Moved the `setProvider` and `setProviderAndWait` methods that take a `domain` parameter from the OpenFeatureAPI singleton to the Client interface. This improves API ergonomics by allowing developers to bind providers directly to a domain-scoped client instance, adhering to the design principle that getClient(domain) should be the sole place the domain string is required. The domain-parameterized routing methods on OpenFeatureAPI have been made internal to preserve a clean public API surface area. Signed-off-by: Marcin Stepien <marcin.stepien@fluxon.com>
Description
This PR introduces the Domains (formerly Named Clients) feature to the OpenFeature Kotlin SDK, ensuring full compliance with the OpenFeature Domains specification.
Domains allow logical binding of clients with specific providers, enabling the use of multiple providers in a single application. If no specific provider or context is bound to a given domain, the system gracefully falls back to the globally configured default provider and evaluation context.
Changes Made
domain: String?toClientMetadata. Concurrently deprecatednamein favor ofdomainto align with the wider OpenFeature schema and specification.OpenFeatureAPIwithdomain-parameterized methods (e.g.,setProvider(domain, provider),getProvider(domain),getProviderStatus(domain)).ProviderRepositoryandDomainStateto isolate lifecycle, observers, events, and execution flow tracking per domain in a thread-safe manner using atomic flow substitutions andMutex.EvaluationContexton a per-domain basissetEvaluationContext(domain, context). A domain client will first attempt to use its specific contextual state before defaulting back to the global execution context.OpenFeatureStatusto the individual domain correctly.ProviderRepositoryTestandDomainE2ETestto enforce atomic state concurrency, dynamically mapped fallback lifecycles, and strict hook/event propagation rules bounded to isolated domains.Related Issues
Closes #185
Testing
DomainE2ETest)ProviderRepositoryTest)Reviewer Focus
OpenFeatureAPIwhere missing domain contexts gracefully fallback to global contexts without breaking isolation.ProviderRepository(getStateFlow()) for potential leaks when updating providers rapidly.