From dc58b11e57fc80c6ba1e00710638b5f5ea3c7f72 Mon Sep 17 00:00:00 2001 From: Lukas Reining Date: Sat, 30 Dec 2023 18:33:08 +0100 Subject: [PATCH 01/16] feat: add context propagation as described in #81 Signed-off-by: Lukas Reining --- specification.json | 55 ++++++++++++++- specification/glossary.md | 5 ++ .../sections/03-evaluation-context.md | 70 ++++++++++++++++--- 3 files changed, 118 insertions(+), 12 deletions(-) diff --git a/specification.json b/specification.json index db14ddc2..cf0be271 100644 --- a/specification.json +++ b/specification.json @@ -530,7 +530,7 @@ { "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 name.", "RFC 2119 keyword": "MUST", "children": [] } @@ -539,7 +539,7 @@ { "id": "Requirement 3.2.3", "machine_id": "requirement_3_2_3", - "content": "Evaluation context MUST be merged in the order: API (global; lowest precedence) - client - invocation - before hooks (highest precedence), with duplicate values being overwritten.", + "content": "Evaluation context MUST be merged in the order: API (global; lowest precedence) - transaction - client - invocation - before hooks (highest precedence), with duplicate values being overwritten.", "RFC 2119 keyword": "MUST", "children": [] }, @@ -565,6 +565,57 @@ } ] }, + { + "id": "Condition 3.3.1", + "machine_id": "condition_3_3_1", + "content": "The implementation uses the dynamic-context paradigm.", + "RFC 2119 keyword": null, + "children": [ + { + "id": "Conditional Requirement 3.3.1.1", + "machine_id": "conditional_requirement_3_3_1_1", + "content": "The API MUST have a method for setting a `transaction context propagator`.", + "RFC 2119 keyword": "MUST", + "children": [] + }, + { + "id": "Conditional Requirement 3.3.1.2", + "machine_id": "conditional_requirement_3_3_1_2", + "content": "The API MUST have a method for setting the `evaluation context` of the `transaction context propagator`.", + "RFC 2119 keyword": "MUST", + "children": [] + }, + { + "id": "Conditional Requirement 3.3.1.3", + "machine_id": "conditional_requirement_3_3_1_3", + "content": "A `transaction context propagator` MUST have a method for setting the `evaluation context` of the current transaction.", + "RFC 2119 keyword": "MUST", + "children": [] + }, + { + "id": "Conditional Requirement 3.3.1.4", + "machine_id": "conditional_requirement_3_3_1_4", + "content": "A `transaction context propagator` MUST have a method for getting the `evaluation context` of the current transaction.", + "RFC 2119 keyword": "MUST", + "children": [] + } + ] + }, + { + "id": "Condition 3.3.2", + "machine_id": "condition_3_3_2", + "content": "The implementation uses the static-context paradigm.", + "RFC 2119 keyword": null, + "children": [ + { + "id": "Conditional Requirement 3.3.2.1", + "machine_id": "conditional_requirement_3_3_2_1", + "content": "The API MUST NOT have a method for setting a `transaction context propagator`.", + "RFC 2119 keyword": "MUST NOT", + "children": [] + } + ] + }, { "id": "Requirement 4.1.1", "machine_id": "requirement_4_1_1", diff --git a/specification/glossary.md b/specification/glossary.md index 3b903d39..4b421861 100644 --- a/specification/glossary.md +++ b/specification/glossary.md @@ -30,6 +30,7 @@ This document defines some terms that are used across this specification. - [Provider](#provider) - [Integration](#integration) - [Evaluation Context](#evaluation-context) + - [Transaction Context Propagator](#transaction-context-propagator) - [Evaluating Flag Values](#evaluating-flag-values) - [Resolving Flag Values](#resolving-flag-values) - [Flagging specifics](#flagging-specifics) @@ -117,6 +118,10 @@ An SDK-compliant secondary function that is abstracted by the Feature Flag API, Context object for flag evaluation, which may contain information about the runtime environment, details of the transport method encapsulating the flag evaluation, the host, the client, the subject (user), etc. This data may be used as a basis for differential evaluation of feature flags based on rules that can be defined in the flag system. Context data may be provided by merging static global context, arguments to flag evaluation, and implicit language-dependant state propagation mechanisms (thread-local storage, promise chains, continuations, etc). +### Transaction Context Propagator + +An SDK-compliant implementation which stores and returns transaction specific evaluation context. A transaction can be something like a thread or web request. + ### Evaluating Flag Values The process of retrieving a feature flag value in it's entirety, including: diff --git a/specification/sections/03-evaluation-context.md b/specification/sections/03-evaluation-context.md index 919e0da4..b9f5d10a 100644 --- a/specification/sections/03-evaluation-context.md +++ b/specification/sections/03-evaluation-context.md @@ -88,26 +88,28 @@ See [setting a provider](./01-flag-evaluation.md#setting-a-provider) 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 name. 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. #### Requirement 3.2.3 -> Evaluation context **MUST** be merged in the order: API (global; lowest precedence) -> client -> invocation -> before hooks (highest precedence), with duplicate values being overwritten. +> Evaluation context **MUST** be merged in the order: API (global; lowest precedence) -> transaction -> client -> invocation -> before hooks (highest precedence), with duplicate values being overwritten. Any fields defined in the client `evaluation context` will overwrite duplicate fields defined globally, and fields defined in the invocation `evaluation context` will overwrite duplicate fields defined globally or on the client. Any resulting `evaluation context` from a [before hook](./04-hooks.md#requirement-434) will overwrite duplicate fields defined globally, on the client, or in the invocation. ```mermaid flowchart LR - global("API (global)") - client("Client") - invocation("Invocation") - hook("Before Hooks") - global --> client - client --> invocation - invocation --> hook + global("API (global)") + transaction("Transaction") + client("Client") + invocation("Invocation") + hook("Before Hooks") + global --> transaction + transaction --> client + client --> invocation + invocation --> hook ``` #### Condition 3.2.4 @@ -128,4 +130,52 @@ The SDK implementation must run the `on context changed` handler on all register > When the `evaluation context` for a specific provider is set, the `on context changed` handler **MUST** only run on the associated provider. -The SDK implementation must run the `on context changed` handler only on the provider that is scoped to the mutated `evaluation context`. \ No newline at end of file +The SDK implementation must run the `on context changed` handler only on the provider that is scoped to the mutated `evaluation context`. + +### 3.3 Context Propagation + +[![experimental](https://img.shields.io/static/v1?label=Status&message=experimental&color=orange)](https://github.com/open-feature/spec/tree/main/specification#experimental) + +#### Condition 3.3.1 + +> The implementation uses the dynamic-context paradigm. + +see: [dynamic-context paradigm](../glossary.md#dynamic-context-paradigm) + +##### Conditional Requirement 3.3.1.1 + +> The API **MUST** have a method for setting a `transaction context propagator`. + +If there already is a `transaction context propagator`, it is replaced with the new one. + +##### Conditional Requirement 3.3.1.2 + +> The API **MUST** have a method for setting the `evaluation context` of the `transaction context propagator`. + +If a `transaction context propagator` is set, this `evaluation context` must be supplied to it and so will be available during the current transaction. +This method can e.g. be used in a request handler to add request specific information to the `evaluation context`. + +##### Conditional Requirement 3.3.1.3 + +> A `transaction context propagator` **MUST** have a method for setting the `evaluation context` of the current transaction. + +A `transaction context propagator` is responsible for persisting context for the duration of a single transaction. +Typically, a transaction context propagator will propagate the context using a language-specific carrier such as [`ThreadLocal` (Java)](https://docs.oracle.com/javase/8/docs/api/java/lang/ThreadLocal.html), [`async hooks` (Node.js)](https://nodejs.org/api/async_hooks.html), [`Context` (Go)](https://pkg.go.dev/context) or another similar mechanism. + +##### Conditional Requirement 3.3.1.4 + +> A `transaction context propagator` **MUST** have a method for getting the `evaluation context` of the current transaction. + +This must be used by the SDK implementation when merging the context for evaluating a feature flag. + +#### Condition 3.3.2 + +> The implementation uses the static-context paradigm. + +see: [static-context paradigm](../glossary.md#static-context-paradigm) + +##### Conditional Requirement 3.3.2.1 + +> The API **MUST NOT** have a method for setting a `transaction context propagator`. + +In the static-context paradigm, context is global, so there should not be different context between transactions. From 65260dc9c5f409c391a222e21427cffd069ef86d Mon Sep 17 00:00:00 2001 From: Lukas Reining Date: Tue, 2 Jan 2024 17:28:46 +0100 Subject: [PATCH 02/16] feat: explicitly state that setting context without a propagator is a no-op Signed-off-by: Lukas Reining --- specification/sections/03-evaluation-context.md | 1 + 1 file changed, 1 insertion(+) diff --git a/specification/sections/03-evaluation-context.md b/specification/sections/03-evaluation-context.md index b9f5d10a..5ebafe77 100644 --- a/specification/sections/03-evaluation-context.md +++ b/specification/sections/03-evaluation-context.md @@ -153,6 +153,7 @@ If there already is a `transaction context propagator`, it is replaced with the > The API **MUST** have a method for setting the `evaluation context` of the `transaction context propagator`. If a `transaction context propagator` is set, this `evaluation context` must be supplied to it and so will be available during the current transaction. +If no `transaction context propagator` is set, this `evaluation context` is not used for evaluations. This method can e.g. be used in a request handler to add request specific information to the `evaluation context`. ##### Conditional Requirement 3.3.1.3 From 5bc837378e05234ee48c6d5f4ee22f8418b5f4bf Mon Sep 17 00:00:00 2001 From: Lukas Reining Date: Fri, 12 Jan 2024 22:00:00 +0100 Subject: [PATCH 03/16] Update 03-evaluation-context.md Co-authored-by: Michael Beemer Signed-off-by: Lukas Reining --- specification/sections/03-evaluation-context.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specification/sections/03-evaluation-context.md b/specification/sections/03-evaluation-context.md index 5ebafe77..c0bc3cd0 100644 --- a/specification/sections/03-evaluation-context.md +++ b/specification/sections/03-evaluation-context.md @@ -154,7 +154,7 @@ If there already is a `transaction context propagator`, it is replaced with the If a `transaction context propagator` is set, this `evaluation context` must be supplied to it and so will be available during the current transaction. If no `transaction context propagator` is set, this `evaluation context` is not used for evaluations. -This method can e.g. be used in a request handler to add request specific information to the `evaluation context`. +This method can e.g. be used in a request handler to add request-specific information to the `evaluation context`. ##### Conditional Requirement 3.3.1.3 From 797ba0ea4ea5a098006505ec578dc573a69ffde6 Mon Sep 17 00:00:00 2001 From: Lukas Reining Date: Sun, 14 Jan 2024 15:27:33 +0100 Subject: [PATCH 04/16] feat: add node example for context propagation Signed-off-by: Lukas Reining --- .../sections/03-evaluation-context.md | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/specification/sections/03-evaluation-context.md b/specification/sections/03-evaluation-context.md index c0bc3cd0..12858443 100644 --- a/specification/sections/03-evaluation-context.md +++ b/specification/sections/03-evaluation-context.md @@ -161,7 +161,33 @@ This method can e.g. be used in a request handler to add request-specific inform > A `transaction context propagator` **MUST** have a method for setting the `evaluation context` of the current transaction. A `transaction context propagator` is responsible for persisting context for the duration of a single transaction. -Typically, a transaction context propagator will propagate the context using a language-specific carrier such as [`ThreadLocal` (Java)](https://docs.oracle.com/javase/8/docs/api/java/lang/ThreadLocal.html), [`async hooks` (Node.js)](https://nodejs.org/api/async_hooks.html), [`Context` (Go)](https://pkg.go.dev/context) or another similar mechanism. +Typically, a transaction context propagator will propagate the context using a language-specific carrier such as [ThreadLocal (Java)](https://docs.oracle.com/javase/8/docs/api/java/lang/ThreadLocal.html), [async hooks (Node.js)](https://nodejs.org/api/async_hooks.html), [Context (Go)](https://pkg.go.dev/context) or another similar mechanism. + +The following shows a possible TypeScript implementation using [AsyncLocalStorage (async_hooks)](https://nodejs.org/api/async_context.html): + +```typescript +export class AsyncLocalStorageTransactionContext implements TransactionContextPropagator { + private asyncLocalStorage = new AsyncLocalStorage(); + + getTransactionContext(): EvaluationContext { + return this.asyncLocalStorage.getStore() ?? {}; + } + setTransactionContext(context: EvaluationContext, callback: () => void): void { + this.asyncLocalStorage.run(context, callback); + } +} + +/** + * This example is based on an express middleware. + */ +app.use((req: Request, res: Response, next: NextFunction) => { + const ip = res.headers.get("X-Forwarded-For") + OpenFeature.setTransactionContext({ targetingKey: req.user.id, ipAddress: ip }, () => { + // The transaction context is used in any flag evaluation throughout the whole call chain of next + next(); + }); +}) +``` ##### Conditional Requirement 3.3.1.4 From fed54fb4a3381378cd854b890b1a2ab0cfb84c24 Mon Sep 17 00:00:00 2001 From: Lukas Reining Date: Sun, 14 Jan 2024 15:45:14 +0100 Subject: [PATCH 05/16] feat: add note that not all context variants might be available Signed-off-by: Lukas Reining --- specification.json | 2 +- specification/sections/03-evaluation-context.md | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/specification.json b/specification.json index cf0be271..51007fc6 100644 --- a/specification.json +++ b/specification.json @@ -539,7 +539,7 @@ { "id": "Requirement 3.2.3", "machine_id": "requirement_3_2_3", - "content": "Evaluation context MUST be merged in the order: API (global; lowest precedence) - transaction - client - invocation - before hooks (highest precedence), with duplicate values being overwritten.", + "content": "[!NOTE] This describes the precedence of all `evaluation context` variants. Depending on the `paradigm`, not all variants might be available in an `SDK` implementation. Evaluation context MUST be merged in the order: API (global; lowest precedence) - transaction - client - invocation - before hooks (highest precedence), with duplicate values being overwritten.", "RFC 2119 keyword": "MUST", "children": [] }, diff --git a/specification/sections/03-evaluation-context.md b/specification/sections/03-evaluation-context.md index 12858443..30dda330 100644 --- a/specification/sections/03-evaluation-context.md +++ b/specification/sections/03-evaluation-context.md @@ -95,9 +95,12 @@ See [setting a provider](./01-flag-evaluation.md#setting-a-provider) for details #### Requirement 3.2.3 +> [!NOTE] +> This describes the precedence of all `evaluation context` variants. Depending on the `paradigm`, not all variants might be available in an `SDK` implementation. + > Evaluation context **MUST** be merged in the order: API (global; lowest precedence) -> transaction -> client -> invocation -> before hooks (highest precedence), with duplicate values being overwritten. -Any fields defined in the client `evaluation context` will overwrite duplicate fields defined globally, and fields defined in the invocation `evaluation context` will overwrite duplicate fields defined globally or on the client. Any resulting `evaluation context` from a [before hook](./04-hooks.md#requirement-434) will overwrite duplicate fields defined globally, on the client, or in the invocation. +Any fields defined in the transaction `evaluation context` will overwrite duplicate fields defined in the global `evaluation context`, any fields defined in the client `evaluation context` will overwrite duplicate fields defined in the transaction `evaluation context`, and fields defined in the invocation `evaluation context` will overwrite duplicate fields defined globally or on the client. Any resulting `evaluation context` from a [before hook](./04-hooks.md#requirement-434) will overwrite duplicate fields defined globally, on the client, or in the invocation. ```mermaid flowchart LR From f3cb33ca4669ac378c4002f0680b6301725b1d1c Mon Sep 17 00:00:00 2001 From: Lukas Reining Date: Mon, 15 Jan 2024 17:03:29 +0100 Subject: [PATCH 06/16] Update glossary.md Co-authored-by: Todd Baert Signed-off-by: Lukas Reining --- specification/glossary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specification/glossary.md b/specification/glossary.md index 4b421861..bed638fa 100644 --- a/specification/glossary.md +++ b/specification/glossary.md @@ -120,7 +120,7 @@ Context object for flag evaluation, which may contain information about the runt ### Transaction Context Propagator -An SDK-compliant implementation which stores and returns transaction specific evaluation context. A transaction can be something like a thread or web request. +An SDK-compliant implementation which stores and returns transaction-specific evaluation context. A _transaction_ might be a web request or application event, which carries it's own contextual data in thread or continuation storage. ### Evaluating Flag Values From 9ecdb6e8c53477c26911526c2fc0a64444506f26 Mon Sep 17 00:00:00 2001 From: Lukas Reining Date: Mon, 15 Jan 2024 19:46:57 +0100 Subject: [PATCH 07/16] Update specification/sections/03-evaluation-context.md Co-authored-by: Todd Baert Signed-off-by: Lukas Reining --- specification/sections/03-evaluation-context.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specification/sections/03-evaluation-context.md b/specification/sections/03-evaluation-context.md index 30dda330..c98300d4 100644 --- a/specification/sections/03-evaluation-context.md +++ b/specification/sections/03-evaluation-context.md @@ -153,7 +153,7 @@ If there already is a `transaction context propagator`, it is replaced with the ##### Conditional Requirement 3.3.1.2 -> The API **MUST** have a method for setting the `evaluation context` of the `transaction context propagator`. +> The API **MUST** have a method for setting the `evaluation context` of the `transaction context propagator` for the current transaction. If a `transaction context propagator` is set, this `evaluation context` must be supplied to it and so will be available during the current transaction. If no `transaction context propagator` is set, this `evaluation context` is not used for evaluations. From fab22fa7fe07380925140fe62a935d6c224525fc Mon Sep 17 00:00:00 2001 From: Lukas Reining Date: Mon, 15 Jan 2024 19:47:21 +0100 Subject: [PATCH 08/16] Update specification/sections/03-evaluation-context.md Co-authored-by: Todd Baert Signed-off-by: Lukas Reining --- specification/sections/03-evaluation-context.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specification/sections/03-evaluation-context.md b/specification/sections/03-evaluation-context.md index c98300d4..3ca97652 100644 --- a/specification/sections/03-evaluation-context.md +++ b/specification/sections/03-evaluation-context.md @@ -196,7 +196,7 @@ app.use((req: Request, res: Response, next: NextFunction) => { > A `transaction context propagator` **MUST** have a method for getting the `evaluation context` of the current transaction. -This must be used by the SDK implementation when merging the context for evaluating a feature flag. +This will be used by the SDK implementation when merging the context for evaluating a feature flag. #### Condition 3.3.2 From ff23af6f9f18de4d11c3ea6f51ed28968cec1419 Mon Sep 17 00:00:00 2001 From: Lukas Reining Date: Mon, 15 Jan 2024 19:46:43 +0100 Subject: [PATCH 09/16] feat: move precedence note Signed-off-by: Lukas Reining --- specification.json | 4 ++-- specification/sections/03-evaluation-context.md | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/specification.json b/specification.json index 51007fc6..b7d843a2 100644 --- a/specification.json +++ b/specification.json @@ -539,7 +539,7 @@ { "id": "Requirement 3.2.3", "machine_id": "requirement_3_2_3", - "content": "[!NOTE] This describes the precedence of all `evaluation context` variants. Depending on the `paradigm`, not all variants might be available in an `SDK` implementation. Evaluation context MUST be merged in the order: API (global; lowest precedence) - transaction - client - invocation - before hooks (highest precedence), with duplicate values being overwritten.", + "content": "Evaluation context MUST be merged in the order: API (global; lowest precedence) - transaction - client - invocation - before hooks (highest precedence), with duplicate values being overwritten.", "RFC 2119 keyword": "MUST", "children": [] }, @@ -581,7 +581,7 @@ { "id": "Conditional Requirement 3.3.1.2", "machine_id": "conditional_requirement_3_3_1_2", - "content": "The API MUST have a method for setting the `evaluation context` of the `transaction context propagator`.", + "content": "The API MUST have a method for setting the `evaluation context` of the `transaction context propagator` for the current transaction.", "RFC 2119 keyword": "MUST", "children": [] }, diff --git a/specification/sections/03-evaluation-context.md b/specification/sections/03-evaluation-context.md index 3ca97652..bf8707d9 100644 --- a/specification/sections/03-evaluation-context.md +++ b/specification/sections/03-evaluation-context.md @@ -95,9 +95,6 @@ See [setting a provider](./01-flag-evaluation.md#setting-a-provider) for details #### Requirement 3.2.3 -> [!NOTE] -> This describes the precedence of all `evaluation context` variants. Depending on the `paradigm`, not all variants might be available in an `SDK` implementation. - > Evaluation context **MUST** be merged in the order: API (global; lowest precedence) -> transaction -> client -> invocation -> before hooks (highest precedence), with duplicate values being overwritten. Any fields defined in the transaction `evaluation context` will overwrite duplicate fields defined in the global `evaluation context`, any fields defined in the client `evaluation context` will overwrite duplicate fields defined in the transaction `evaluation context`, and fields defined in the invocation `evaluation context` will overwrite duplicate fields defined globally or on the client. Any resulting `evaluation context` from a [before hook](./04-hooks.md#requirement-434) will overwrite duplicate fields defined globally, on the client, or in the invocation. @@ -115,6 +112,8 @@ flowchart LR invocation --> hook ``` +This describes the precedence of all `evaluation context` variants. Depending on the `paradigm`, not all variants might be available in an `SDK` implementation. + #### Condition 3.2.4 [![experimental](https://img.shields.io/static/v1?label=Status&message=experimental&color=orange)](https://github.com/open-feature/spec/tree/main/specification#experimental) From a7c9f70fda81a565715c6eaac552ccbfe55c3ce0 Mon Sep 17 00:00:00 2001 From: Lukas Reining Date: Thu, 18 Jan 2024 16:58:21 +0100 Subject: [PATCH 10/16] feat: move example to beginning of the section Signed-off-by: Lukas Reining --- .../sections/03-evaluation-context.md | 55 ++++++++++--------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/specification/sections/03-evaluation-context.md b/specification/sections/03-evaluation-context.md index bf8707d9..cc29830e 100644 --- a/specification/sections/03-evaluation-context.md +++ b/specification/sections/03-evaluation-context.md @@ -138,6 +138,35 @@ The SDK implementation must run the `on context changed` handler only on the pro [![experimental](https://img.shields.io/static/v1?label=Status&message=experimental&color=orange)](https://github.com/open-feature/spec/tree/main/specification#experimental) +`Transaction context` is a container for transaction-specific `evaluation context` (e.g. user id, user agent, IP). +Transaction context can be set where specific data is available (e.g. an auth service or request handler) and by using the `transaction context propagator` it will automatically be applied to all flag evaluations within a transaction (e.g. a request or thread). + +The following shows a possible TypeScript implementation using [AsyncLocalStorage (async_hooks)](https://nodejs.org/api/async_context.html): + +```typescript +export class AsyncLocalStorageTransactionContext implements TransactionContextPropagator { + private asyncLocalStorage = new AsyncLocalStorage(); + + getTransactionContext(): EvaluationContext { + return this.asyncLocalStorage.getStore() ?? {}; + } + setTransactionContext(context: EvaluationContext, callback: () => void): void { + this.asyncLocalStorage.run(context, callback); + } +} + +/** + * This example is based on an express middleware. + */ +app.use((req: Request, res: Response, next: NextFunction) => { + const ip = res.headers.get("X-Forwarded-For") + OpenFeature.setTransactionContext({ targetingKey: req.user.id, ipAddress: ip }, () => { + // The transaction context is used in any flag evaluation throughout the whole call chain of next + next(); + }); +}) +``` + #### Condition 3.3.1 > The implementation uses the dynamic-context paradigm. @@ -165,32 +194,6 @@ This method can e.g. be used in a request handler to add request-specific inform A `transaction context propagator` is responsible for persisting context for the duration of a single transaction. Typically, a transaction context propagator will propagate the context using a language-specific carrier such as [ThreadLocal (Java)](https://docs.oracle.com/javase/8/docs/api/java/lang/ThreadLocal.html), [async hooks (Node.js)](https://nodejs.org/api/async_hooks.html), [Context (Go)](https://pkg.go.dev/context) or another similar mechanism. -The following shows a possible TypeScript implementation using [AsyncLocalStorage (async_hooks)](https://nodejs.org/api/async_context.html): - -```typescript -export class AsyncLocalStorageTransactionContext implements TransactionContextPropagator { - private asyncLocalStorage = new AsyncLocalStorage(); - - getTransactionContext(): EvaluationContext { - return this.asyncLocalStorage.getStore() ?? {}; - } - setTransactionContext(context: EvaluationContext, callback: () => void): void { - this.asyncLocalStorage.run(context, callback); - } -} - -/** - * This example is based on an express middleware. - */ -app.use((req: Request, res: Response, next: NextFunction) => { - const ip = res.headers.get("X-Forwarded-For") - OpenFeature.setTransactionContext({ targetingKey: req.user.id, ipAddress: ip }, () => { - // The transaction context is used in any flag evaluation throughout the whole call chain of next - next(); - }); -}) -``` - ##### Conditional Requirement 3.3.1.4 > A `transaction context propagator` **MUST** have a method for getting the `evaluation context` of the current transaction. From 161839502e674570e3286c2be4b242c258c3f4b6 Mon Sep 17 00:00:00 2001 From: Lukas Reining Date: Thu, 18 Jan 2024 17:09:57 +0100 Subject: [PATCH 11/16] feat: specify that setTransactionsContext method call each other Signed-off-by: Lukas Reining --- specification/sections/03-evaluation-context.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specification/sections/03-evaluation-context.md b/specification/sections/03-evaluation-context.md index cc29830e..acc8d487 100644 --- a/specification/sections/03-evaluation-context.md +++ b/specification/sections/03-evaluation-context.md @@ -183,7 +183,7 @@ If there already is a `transaction context propagator`, it is replaced with the > The API **MUST** have a method for setting the `evaluation context` of the `transaction context propagator` for the current transaction. -If a `transaction context propagator` is set, this `evaluation context` must be supplied to it and so will be available during the current transaction. +If a `transaction context propagator` is set, the SDK will call the [method defined in 3.3.1.3](#conditional-requirement-3313) with this `evaluation context` and so this `evaluation context` will be available during the current transaction. If no `transaction context propagator` is set, this `evaluation context` is not used for evaluations. This method can e.g. be used in a request handler to add request-specific information to the `evaluation context`. From c9b47df760231ca28599fc28045c09a8b9542172 Mon Sep 17 00:00:00 2001 From: Lukas Reining Date: Fri, 19 Jan 2024 08:00:03 +0100 Subject: [PATCH 12/16] Update glossary.md Co-authored-by: Kavindu Dodanduwa Signed-off-by: Lukas Reining --- specification/glossary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specification/glossary.md b/specification/glossary.md index bed638fa..2d49c10b 100644 --- a/specification/glossary.md +++ b/specification/glossary.md @@ -120,7 +120,7 @@ Context object for flag evaluation, which may contain information about the runt ### Transaction Context Propagator -An SDK-compliant implementation which stores and returns transaction-specific evaluation context. A _transaction_ might be a web request or application event, which carries it's own contextual data in thread or continuation storage. +An SDK-compliant implementation that stores and returns transaction-specific evaluation context. A _transaction_ might be a web request or application event, which carries its contextual data in a thread or continuation storage. ### Evaluating Flag Values From ef30f16db28101693f9141f132a06c7d81782343 Mon Sep 17 00:00:00 2001 From: Lukas Reining Date: Fri, 19 Jan 2024 08:03:00 +0100 Subject: [PATCH 13/16] Update 03-evaluation-context.md Co-authored-by: Kavindu Dodanduwa Signed-off-by: Lukas Reining --- specification/sections/03-evaluation-context.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specification/sections/03-evaluation-context.md b/specification/sections/03-evaluation-context.md index acc8d487..0347bdff 100644 --- a/specification/sections/03-evaluation-context.md +++ b/specification/sections/03-evaluation-context.md @@ -210,4 +210,4 @@ see: [static-context paradigm](../glossary.md#static-context-paradigm) > The API **MUST NOT** have a method for setting a `transaction context propagator`. -In the static-context paradigm, context is global, so there should not be different context between transactions. +In the static-context paradigm, context is global, so there must not be different contexts between transactions. From c6e7064c3ab3df0a7cd3f687b566e36bd69333e2 Mon Sep 17 00:00:00 2001 From: Lukas Reining Date: Fri, 19 Jan 2024 17:58:43 +0100 Subject: [PATCH 14/16] Update specification/sections/03-evaluation-context.md Co-authored-by: Kavindu Dodanduwa Signed-off-by: Lukas Reining --- specification/sections/03-evaluation-context.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specification/sections/03-evaluation-context.md b/specification/sections/03-evaluation-context.md index 0347bdff..42717e83 100644 --- a/specification/sections/03-evaluation-context.md +++ b/specification/sections/03-evaluation-context.md @@ -185,7 +185,7 @@ If there already is a `transaction context propagator`, it is replaced with the If a `transaction context propagator` is set, the SDK will call the [method defined in 3.3.1.3](#conditional-requirement-3313) with this `evaluation context` and so this `evaluation context` will be available during the current transaction. If no `transaction context propagator` is set, this `evaluation context` is not used for evaluations. -This method can e.g. be used in a request handler to add request-specific information to the `evaluation context`. +This method then can be used for example in a request handler to add request-specific information to the `evaluation context`. ##### Conditional Requirement 3.3.1.3 From 7fcf7e6d8c9cb32a72648c1883d9f3391f89b184 Mon Sep 17 00:00:00 2001 From: Lukas Reining Date: Wed, 31 Jan 2024 21:52:43 +0100 Subject: [PATCH 15/16] feat: add condition for context propagation implementation Signed-off-by: Lukas Reining --- specification.json | 26 ++++++++++++------- .../sections/03-evaluation-context.md | 14 +++++++--- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/specification.json b/specification.json index b7d843a2..2b22deb2 100644 --- a/specification.json +++ b/specification.json @@ -574,27 +574,35 @@ { "id": "Conditional Requirement 3.3.1.1", "machine_id": "conditional_requirement_3_3_1_1", - "content": "The API MUST have a method for setting a `transaction context propagator`.", - "RFC 2119 keyword": "MUST", + "content": "The API SHOULD have a method for setting a `transaction context propagator`.", + "RFC 2119 keyword": "SHOULD", "children": [] - }, + } + ] + }, + { + "id": "Condition 3.3.1.2", + "machine_id": "condition_3_3_1_2", + "content": "The SDK implements context propagation.", + "RFC 2119 keyword": null, + "children": [ { - "id": "Conditional Requirement 3.3.1.2", - "machine_id": "conditional_requirement_3_3_1_2", + "id": "Conditional Requirement 3.3.1.2.1", + "machine_id": "conditional_requirement_3_3_1_2_1", "content": "The API MUST have a method for setting the `evaluation context` of the `transaction context propagator` for the current transaction.", "RFC 2119 keyword": "MUST", "children": [] }, { - "id": "Conditional Requirement 3.3.1.3", - "machine_id": "conditional_requirement_3_3_1_3", + "id": "Conditional Requirement 3.3.1.2.2", + "machine_id": "conditional_requirement_3_3_1_2_2", "content": "A `transaction context propagator` MUST have a method for setting the `evaluation context` of the current transaction.", "RFC 2119 keyword": "MUST", "children": [] }, { - "id": "Conditional Requirement 3.3.1.4", - "machine_id": "conditional_requirement_3_3_1_4", + "id": "Conditional Requirement 3.3.1.2.3", + "machine_id": "conditional_requirement_3_3_1_2_3", "content": "A `transaction context propagator` MUST have a method for getting the `evaluation context` of the current transaction.", "RFC 2119 keyword": "MUST", "children": [] diff --git a/specification/sections/03-evaluation-context.md b/specification/sections/03-evaluation-context.md index 42717e83..b8185b25 100644 --- a/specification/sections/03-evaluation-context.md +++ b/specification/sections/03-evaluation-context.md @@ -175,11 +175,17 @@ see: [dynamic-context paradigm](../glossary.md#dynamic-context-paradigm) ##### Conditional Requirement 3.3.1.1 -> The API **MUST** have a method for setting a `transaction context propagator`. +> The API **SHOULD** have a method for setting a `transaction context propagator`. If there already is a `transaction context propagator`, it is replaced with the new one. -##### Conditional Requirement 3.3.1.2 +#### Condition 3.3.1.2 + +> The SDK implements context propagation. + +A language may not have any applicable way of implementing `transaction context propagation` so the language SDK might not implement context propagation. + +##### Conditional Requirement 3.3.1.2.1 > The API **MUST** have a method for setting the `evaluation context` of the `transaction context propagator` for the current transaction. @@ -187,14 +193,14 @@ If a `transaction context propagator` is set, the SDK will call the [method defi If no `transaction context propagator` is set, this `evaluation context` is not used for evaluations. This method then can be used for example in a request handler to add request-specific information to the `evaluation context`. -##### Conditional Requirement 3.3.1.3 +##### Conditional Requirement 3.3.1.2.2 > A `transaction context propagator` **MUST** have a method for setting the `evaluation context` of the current transaction. A `transaction context propagator` is responsible for persisting context for the duration of a single transaction. Typically, a transaction context propagator will propagate the context using a language-specific carrier such as [ThreadLocal (Java)](https://docs.oracle.com/javase/8/docs/api/java/lang/ThreadLocal.html), [async hooks (Node.js)](https://nodejs.org/api/async_hooks.html), [Context (Go)](https://pkg.go.dev/context) or another similar mechanism. -##### Conditional Requirement 3.3.1.4 +##### Conditional Requirement 3.3.1.2.3 > A `transaction context propagator` **MUST** have a method for getting the `evaluation context` of the current transaction. From a60531251ec76cd4a6e603ba6a52e361cbf9e85d Mon Sep 17 00:00:00 2001 From: Lukas Reining Date: Wed, 31 Jan 2024 22:13:35 +0100 Subject: [PATCH 16/16] fix: wrong link Signed-off-by: Lukas Reining --- specification/sections/03-evaluation-context.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specification/sections/03-evaluation-context.md b/specification/sections/03-evaluation-context.md index fc8112ff..9a7641c4 100644 --- a/specification/sections/03-evaluation-context.md +++ b/specification/sections/03-evaluation-context.md @@ -189,7 +189,7 @@ A language may not have any applicable way of implementing `transaction context > The API **MUST** have a method for setting the `evaluation context` of the `transaction context propagator` for the current transaction. -If a `transaction context propagator` is set, the SDK will call the [method defined in 3.3.1.3](#conditional-requirement-3313) with this `evaluation context` and so this `evaluation context` will be available during the current transaction. +If a `transaction context propagator` is set, the SDK will call the [method defined in 3.3.1.3](#conditional-requirement-33122) with this `evaluation context` and so this `evaluation context` will be available during the current transaction. If no `transaction context propagator` is set, this `evaluation context` is not used for evaluations. This method then can be used for example in a request handler to add request-specific information to the `evaluation context`.