-
Notifications
You must be signed in to change notification settings - Fork 49
Description
The OpenFeature API features a global singleton. Though this has advantages (ease-of-use, available everywhere without pollute the call stack, facilitation of transparent 3rd party integrations) it also causes issues. A couple examples:
- can break tests, particularly in languages like Java, where tests mutating the singleton can trample on each-other
- micro-frontends, which combine multiple codebases which each might maniplate the singleton
- server-side programs comprised of multiple submodules, each setting their own provider
- DI frameworks and IoC containers, which inherently don't work well with singletons managed outside their scope
We'd like to explore means of "opting out" or working around the singleton.
OpenFeature Singleton Brainstorming Meeting
Find below resources from our Dec 18th meeting on this topic (LFX account required for some assets):
- Transcript + Recording: https://zoom.us/rec/share/OQUwHFumc1DXRumVxIpD1BKq_epVS9ajj00jJ-7Vt4oLQCLMrW3P7waEvVb_Nw7I.CxKvHOr4meTgZjEd
- AI Meeting Summary: https://zoom-lfx.platform.linuxfoundation.org/meeting/96839205440-1766073600000/summaries?password=db7e61a2-5aa4-4e19-ad42-c34799ce1397
Questions/comments
- In javascript, why did we bind the singleton to window - truely global - vs. binding to the module
- Todd says because we intentionally wanted to make the API object a true globalton
- Next.js - issues here because server-side rendered code is half-dynamic-context, half-static-context paradigm
- If you can have multiple API objects floating around, what's the value in distinguishing between client and API
- We could still keep separate interfaces that are backed by the same object instances, even if we did this
Solutions
Option A
Expose ability to create non-singleton instances of the API object
- Benefits
- Simple solution
- Potential to allow us to remove "domains" concept
- Drawbacks
- Could be some gotchas
- Bit of a fear of unknown-unknowns.
- Some deep research on where we assume a globalton would be needed
- ? bugs around shutdown lifecycle
- Bit of a fear of unknown-unknowns.
- Confusing footgun - new user might stumble into newing up when they should use the singleton
- Could we mitigate this by not exposing the ctor but instead exposing OpenFeature.advanced_use_only_new_instance() or whatever
- Matt proposes OpenFeature.isolated()
- Jonathan proposes hiding it in a different class
- Could we mitigate this by not exposing the ctor but instead exposing OpenFeature.advanced_use_only_new_instance() or whatever
- We would need to ensure that a specific provider instance cannot be bound to multiple API instances
- Event lifecycle etc.
- If we replaced domains with this then it could make end-user code more complex/boilerplate-y
- Could be some gotchas
Option B
Add methods to the singleton that would give you an isolated scope - sort of like "domains" in the client?
- Drawbacks
- Adds a lot of surface area to the api
Option C
JS-specific solution: bind the singleton at module scope, rather than on window
Option D
Extended API so that you can specify a provider when you create a client
This is what .NET impl does already for DI
- Benefits
- Seems to be working well in .NET so far (dynamic context only)
- Drawbacks
- Need to expose more on API surface area in order to support context management in "user land"
- On client, and possibly also on provider (:scream:)
- Opening up the option means we have to support it everywhere, which means the value of the API class sort of evaporates
- Need to expose more on API surface area in order to support context management in "user land"
Actions
PoC some of the options and present back findings
- @MattIPv4 offers to PoC Option A
- @jonathannorris offers to PoC Option A where we have a separate class or factory function or whatever, to make the footgun less discoverable
- @lukas-reining wants to PoC ensuring that a provider instance can only be bound to a single API instance (if we went down the Option A path)
- @cupofcat offers to prototype options in Go, starting mid Jan