Skip to content

Considering alternatives to the OpenFeature global singleton #359

@toddbaert

Description

@toddbaert

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):

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
    • 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
    • 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

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

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

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions