From afe1c7ea722f34fe0a514f9f106af3fa86e4dc57 Mon Sep 17 00:00:00 2001 From: Michael Beemer Date: Wed, 24 Jan 2024 08:49:14 -0500 Subject: [PATCH] feat: add domain as an openfeature concept (#229) Signed-off-by: Michael Beemer --- specification.json | 10 +-- specification/glossary.md | 7 ++- specification/sections/01-flag-evaluation.md | 63 ++++++++++++------- .../sections/03-evaluation-context.md | 12 ++-- specification/sections/05-events.md | 8 +-- 5 files changed, 61 insertions(+), 39 deletions(-) diff --git a/specification.json b/specification.json index db14ddc2..fcb882e7 100644 --- a/specification.json +++ b/specification.json @@ -38,7 +38,7 @@ { "id": "Requirement 1.1.3", "machine_id": "requirement_1_1_3", - "content": "The `API` MUST provide a function to bind a given `provider` to one or more client `name`s. If the client-name already has a bound provider, it is overwritten with the new mapping.", + "content": "The `API` MUST provide a function to bind a given `provider` to one or more clients using a `domain`. If the domain already has a bound provider, it is overwritten with the new mapping.", "RFC 2119 keyword": "MUST", "children": [] }, @@ -59,7 +59,7 @@ { "id": "Requirement 1.1.6", "machine_id": "requirement_1_1_6", - "content": "The `API` MUST provide a function for creating a `client` which accepts the following options: - name (optional): A logical string identifier for the client.", + "content": "The `API` MUST provide a function for creating a `client` which accepts the following options: - domain (optional): A logical string identifier for binding clients to provider.", "RFC 2119 keyword": "MUST", "children": [] }, @@ -80,7 +80,7 @@ { "id": "Requirement 1.2.2", "machine_id": "requirement_1_2_2", - "content": "The client interface MUST define a `metadata` member or accessor, containing an immutable `name` field or accessor of type string, which corresponds to the `name` value supplied during client creation.", + "content": "The client interface MUST define a `metadata` member or accessor, containing an immutable `domain` field or accessor of type string, which corresponds to the `domain` value supplied during client creation.", "RFC 2119 keyword": "MUST", "children": [] }, @@ -523,14 +523,14 @@ { "id": "Conditional Requirement 3.2.2.3", "machine_id": "conditional_requirement_3_2_2_3", - "content": "The API MUST have a method for setting `evaluation context` for a provider bound to a named client.", + "content": "The API MUST have a method for setting `evaluation context` for a `domain`.", "RFC 2119 keyword": "MUST", "children": [] }, { "id": "Conditional Requirement 3.2.2.4", "machine_id": "conditional_requirement_3_2_2_4", - "content": "The API MUST have a a mechanism to manage `evaluation context` for an associated name.", + "content": "The API MUST have a mechanism to manage `evaluation context` for an associated `domain`.", "RFC 2119 keyword": "MUST", "children": [] } diff --git a/specification/glossary.md b/specification/glossary.md index 3b903d39..7ac65701 100644 --- a/specification/glossary.md +++ b/specification/glossary.md @@ -4,7 +4,7 @@ description: A list of terms used within the OpenFeature specification. sidebar_position: 1 --- -# Glossary +# Glossary This document defines some terms that are used across this specification. @@ -28,6 +28,7 @@ This document defines some terms that are used across this specification. - [Evaluation API](#evaluation-api) - [Flag Management System](#flag-management-system) - [Provider](#provider) + - [Domain](#domain) - [Integration](#integration) - [Evaluation Context](#evaluation-context) - [Evaluating Flag Values](#evaluating-flag-values) @@ -107,7 +108,9 @@ A source-of-truth for flag values and rules. Flag management systems may include An SDK-compliant implementation which resolves flag values from a particular flag management system, allowing the use of the [Evaluation API](./sections/01-flag-evaluation.md#13-flag-evaluation) as an abstraction for the system in question. -Providers can be used in two ways. Client-specific providers are active for specific clients, based on their name. The default provider is used if there are no client-specific mappings setup. +### Domain + +An identifier which logically binds clients with providers, allowing for multiple providers to be used simultaneously within a single application. ### Integration diff --git a/specification/sections/01-flag-evaluation.md b/specification/sections/01-flag-evaluation.md index cb81a958..6a964fe7 100644 --- a/specification/sections/01-flag-evaluation.md +++ b/specification/sections/01-flag-evaluation.md @@ -31,28 +31,29 @@ It's important that multiple instances of the `API` not be active, so that state OpenFeature.setProvider(new MyProvider()); ``` -This provider is used if a client is not bound to a specific provider through its name. +The example above sets the default provider. +This provider is used if a client is not bound to a specific provider via a [domain](../glossary.md#domain). -See [provider](./02-providers.md), [creating clients](#creating-clients). +See [provider](./02-providers.md), [creating clients](#creating-clients) for details. #### Requirement 1.1.2.2 > The `provider mutator` function **MUST** invoke the `initialize` function on the newly registered provider before using it to resolve flag values. Application authors can await the newly set `provider's` readiness using the `PROVIDER_READY` event. -Provider instances which are already active (because they have been bound to other `names` or otherwise) need not be initialized again. +Provider instances which are already active (because they have been bound to another `domain` or otherwise) need not be initialized again. The `provider's` readiness can state can be determined from its `status` member/accessor. -See [event handlers and initialization](./05-events.md#event-handlers-and-initialization), [provider initialization](./02-providers.md#24-initialization). +See [event handlers and initialization](./05-events.md#event-handlers-and-initialization), [provider initialization](./02-providers.md#24-initialization), [domain](../glossary.md#domain) for details. #### Requirement 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. When a provider is no longer in use, it should be disposed of using its `shutdown` mechanism. -Provider instances which are bound to multiple names won't be shut down until the last binding is removed. +Provider instances which are bound to multiple `domains` won't be shut down until the last binding is removed. -see: [shutdown](./02-providers.md#25-shutdown), [setting a provider](#setting-a-provider) +see [shutdown](./02-providers.md#25-shutdown), [setting a provider](#setting-a-provider), [domain](../glossary.md#domain) for details. #### Requirement 1.1.2.4 @@ -61,28 +62,30 @@ see: [shutdown](./02-providers.md#25-shutdown), [setting a provider](#setting-a- This function not only sets the provider, but ensures that the provider is ready (or in error) before returning or settling. ```java -// default client +// default provider OpenFeatureAPI.getInstance().setProviderAndWait(myprovider); // this method blocks until the provider is ready or in error +// client uses the default provider Client client = OpenFeatureAPI.getInstance().getClient(); -// named client -OpenFeatureAPI.getInstance().setProviderAndWait('client-name', myprovider); // this method blocks until the provider is ready or in error -Client client = OpenFeatureAPI.getInstance().getClient('client-name'); +// provider associated with domain-1 +OpenFeatureAPI.getInstance().setProviderAndWait('domain-1', myprovider); // this method blocks until the provider is ready or in error +// client uses provider associated with the domain named 'domain-1' +Client client = OpenFeatureAPI.getInstance().getClient('domain-1'); ``` Though it's possible to use [events](./05-events.md) to await provider readiness, such functions can make things simpler for `application authors` and `integrators`. #### Requirement 1.1.3 -> The `API` **MUST** provide a function to bind a given `provider` to one or more client `name`s. If the client-name already has a bound provider, it is overwritten with the new mapping. +> The `API` **MUST** provide a function to bind a given `provider` to one or more clients using a `domain`. If the domain already has a bound provider, it is overwritten with the new mapping. ```java -OpenFeature.setProvider("client-name", new MyProvider()); +OpenFeature.setProvider("domain-1", new MyProvider()); ``` -Named clients can be associated with a particular provider by supplying a matching name when the provider is set. +Clients can be associated with a particular provider by supplying a matching `domain`` when the provider is set. -See [creating clients](#creating-clients). +See [creating clients](#creating-clients), [domain](../glossary.md#domain) for details. #### Requirement 1.1.4 @@ -104,7 +107,15 @@ See [hooks](./04-hooks.md) for details. OpenFeature.getProviderMetadata(); ``` -See [provider](./02-providers.md) for details. +It's possible to access provider metadata using a `domain`. +If a provider has not be registered under the requested domain, the default provider metadata is returned. + +```typescript +// example provider accessor +OpenFeature.getProviderMetadata("domain-1"); +``` + +See [provider](./02-providers.md), [domain](../glossary.md#domain) for details. ### Creating clients @@ -112,17 +123,22 @@ See [provider](./02-providers.md) for details. > The `API` **MUST** provide a function for creating a `client` which accepts the following options: > -> - name (optional): A logical string identifier for the client. +> - domain (optional): A logical string identifier for binding clients to provider. ```java // example client creation and retrieval -OpenFeature.getClient("my-named-client"); +OpenFeature.getClient(); ``` -The name is a logical identifier for the client which may be associated with a particular provider by the application integrator. -If a client name is not bound to a particular provider, the client is associated with the default provider. +It's possible to create a client that is associated with a `domain`. +The client will use a provider in the same `domain` if one exists, otherwise, the default provide is used. -See [setting a provider](#setting-a-provider) for details. +```java +// example client creation and retrieval using a domain +OpenFeature.getClient("domain-1"); +``` + +See [setting a provider](#setting-a-provider), [domain](../glossary.md#domain) for details. #### Requirement 1.1.7 @@ -145,12 +161,15 @@ See [hooks](./04-hooks.md) for details. #### Requirement 1.2.2 -> The client interface **MUST** define a `metadata` member or accessor, containing an immutable `name` field or accessor of type string, which corresponds to the `name` value supplied during client creation. +> The client interface **MUST** define a `metadata` member or accessor, containing an immutable `domain` field or accessor of type string, which corresponds to the `domain` value supplied during client creation. ```typescript -client.getMetadata().getName(); // "my-client" +client.getMetadata().getDomain(); // "domain-1" ``` +In previous drafts, this property was called `name`. +For backwards compatibility, implementations should consider `name` an alias to `domain`. + ### 1.3. Flag Evaluation [![hardening](https://img.shields.io/static/v1?label=Status&message=hardening&color=yellow)](https://github.com/open-feature/spec/tree/main/specification#hardening) diff --git a/specification/sections/03-evaluation-context.md b/specification/sections/03-evaluation-context.md index 919e0da4..7d3222fe 100644 --- a/specification/sections/03-evaluation-context.md +++ b/specification/sections/03-evaluation-context.md @@ -79,19 +79,19 @@ In the static-context paradigm, context is global. The client and invocation can ##### Conditional Requirement 3.2.2.3 -> The API **MUST** have a method for setting `evaluation context` for a provider bound to a named client. +> The API **MUST** have a method for setting `evaluation context` for a `domain`. -In the static-context paradigm, provider specific context can be set using the associated name. +In the static-context paradigm, provider specific context can be set using the associated `domain`. The global context is used if there is no matching provider specific context. -See [setting a provider](./01-flag-evaluation.md#setting-a-provider) for details. +See [setting a provider](./01-flag-evaluation.md#setting-a-provider), [domain](../glossary.md#domain) for details. ##### Conditional Requirement 3.2.2.4 -> The API **MUST** have a a mechanism to manage `evaluation context` for an associated name. +> The API **MUST** have a mechanism to manage `evaluation context` for an associated `domain`. -In the static-context paradigm, it must be possible to create and remove provider-specific context. -See [setting a provider](./01-flag-evaluation.md#setting-a-provider) for details. +In the static-context paradigm, it's possible to create and remove provider-specific context. +See [setting a provider](./01-flag-evaluation.md#setting-a-provider), [domain](../glossary.md#domain) for details. #### Requirement 3.2.3 diff --git a/specification/sections/05-events.md b/specification/sections/05-events.md index 48f693af..a7a56d73 100644 --- a/specification/sections/05-events.md +++ b/specification/sections/05-events.md @@ -42,9 +42,9 @@ see: [provider event types](./../types.md#provider-events) and [event handlers]( > When a `provider` signals the occurrence of a particular `event`, event handlers on clients which are not associated with that provider **MUST NOT** run. -Providers bound to a named client constitute their own "events scope". +Providers bound to a `domain` constitute their own "events scope". -see: [setting a provider](./01-flag-evaluation.md#setting-a-provider) +see [setting a provider](./01-flag-evaluation.md#setting-a-provider), [domain](../glossary.md#domain) for details. #### Requirement 5.1.4 @@ -83,9 +83,9 @@ see: [provider events](#51-provider-events), [`provider event types`](../types.m > The `event details` **MUST** contain the `provider name` associated with the event. The `provider name` indicates the provider from which the event originated. -This is especially relevant for global event handlers used for general monitoring, such as alerting on provider errors. +This is especially relevant for global event handlers used for general monitoring, such as alerting on provider errors. -See [setting a provider](./01-flag-evaluation.md#setting-a-provider), [creating clients](./01-flag-evaluation.md#creating-clients). +See [setting a provider](./01-flag-evaluation.md#setting-a-provider), [creating clients](./01-flag-evaluation.md#creating-clients). #### Requirement 5.2.4