Skip to content

Commit cf87999

Browse files
ssharaevKavindu-Dodan
authored andcommitted
feat: context propagation review
Signed-off-by: Sviatoslav Sharaev <[email protected]>
1 parent da8e7d7 commit cf87999

File tree

5 files changed

+37
-12
lines changed

5 files changed

+37
-12
lines changed

README.md

+21
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,27 @@ This should only be called when your application is in the process of shutting d
273273
OpenFeatureAPI.getInstance().shutdown();
274274
```
275275

276+
### Transaction Context Propagation
277+
Transaction context is a container for transaction-specific evaluation context (e.g. user id, user agent, IP).
278+
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).
279+
By default, the `NoOpTransactionContextPropagator` is used, which doesn't store anything.
280+
To register a `ThreadLocal` context propagator, you can use the `setTransactionContextPropagator` method as shown below:
281+
```java
282+
// registering the ThreadLocalTransactionContextPropagator
283+
OpenFeatureAPI.getInstance().setTransactionContextPropagator(new ThreadLocalTransactionContextPropagator());
284+
```
285+
Once you've registered a transaction context propagator, you can propagate the data into request scoped transaction context.
286+
287+
```java
288+
// adding userId to transaction context
289+
OpenFeatureAPI api = OpenFeatureAPI.getInstance();
290+
Map<String, Value> transactionAttrs = new HashMap<>();
291+
transactionAttrs.put("userId", new Value("userId"));
292+
EvaluationContext transactionCtx = new ImmutableContext(transactionAttrs);
293+
api.setTransactionContext(apiCtx);
294+
```
295+
Additionally, you can develop a custom transaction context propagator by implementing the `TransactionContextPropagator` interface and registering it as shown above.
296+
276297
## Extending
277298

278299
### Develop a provider

src/main/java/dev/openfeature/sdk/NoOpTransactionContextPropagator.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
package dev.openfeature.sdk;
22

33
/**
4-
* A {@link TransactionContextPropagator} that simply returns null.
4+
* A {@link TransactionContextPropagator} that simply returns empty context.
55
*/
66
public class NoOpTransactionContextPropagator implements TransactionContextPropagator {
77

88
/**
99
* {@inheritDoc}
10-
* @return null
10+
* @return empty immutable context
1111
*/
1212
@Override
1313
public EvaluationContext getTransactionContext() {
14-
return null;
14+
return new ImmutableContext();
1515
}
1616

1717
/**

src/main/java/dev/openfeature/sdk/OpenFeatureAPI.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -127,14 +127,14 @@ public void setTransactionContextPropagator(TransactionContextPropagator transac
127127
*
128128
* @return {@link EvaluationContext} The current transaction context
129129
*/
130-
public EvaluationContext getTransactionContext() {
130+
EvaluationContext getTransactionContext() {
131131
return this.transactionContextPropagator.getTransactionContext();
132132
}
133133

134134
/**
135135
* Sets the transaction context using the registered transaction context propagator.
136136
*/
137-
void setTransactionContext(EvaluationContext evaluationContext) {
137+
public void setTransactionContext(EvaluationContext evaluationContext) {
138138
this.transactionContextPropagator.setTransactionContext(evaluationContext);
139139
}
140140

src/main/java/dev/openfeature/sdk/OpenFeatureClient.java

+1-3
Original file line numberDiff line numberDiff line change
@@ -164,9 +164,7 @@ private EvaluationContext mergeEvaluationContext(
164164
? openfeatureApi.getTransactionContext()
165165
: new ImmutableContext();
166166

167-
EvaluationContext mergedInvocationCtx = invocationContext.merge(hookContext);
168-
169-
return apiContext.merge(transactionContext.merge(clientContext.merge(mergedInvocationCtx)));
167+
return apiContext.merge(transactionContext.merge(clientContext.merge(invocationContext.merge(hookContext))));
170168
}
171169

172170
private <T> ProviderEvaluation<?> createProviderEvaluation(

src/test/java/dev/openfeature/sdk/NoOpTransactionContextPropagatorTest.java

+10-4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
import org.junit.jupiter.api.Test;
44

5+
import java.util.HashMap;
6+
import java.util.Map;
7+
58
import static org.junit.jupiter.api.Assertions.*;
69

710
class NoOpTransactionContextPropagatorTest {
@@ -11,13 +14,16 @@ class NoOpTransactionContextPropagatorTest {
1114
@Test
1215
public void emptyTransactionContext() {
1316
EvaluationContext result = contextPropagator.getTransactionContext();
14-
assertNull(result);
17+
assertTrue(result.asMap().isEmpty());
1518
}
1619

1720
@Test
1821
public void setTransactionContext() {
19-
EvaluationContext firstContext = new ImmutableContext();
20-
contextPropagator.setTransactionContext(firstContext);
21-
assertNull(contextPropagator.getTransactionContext());
22+
Map<String, Value> transactionAttrs = new HashMap<>();
23+
transactionAttrs.put("userId", new Value("userId"));
24+
EvaluationContext transactionCtx = new ImmutableContext(transactionAttrs);
25+
contextPropagator.setTransactionContext(transactionCtx);
26+
EvaluationContext result = contextPropagator.getTransactionContext();
27+
assertTrue(result.asMap().isEmpty());
2228
}
2329
}

0 commit comments

Comments
 (0)