You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs(multi-provider): Document Track Method Support in Multi-Provider (#320)
## This PR
This PR updates the Multi-Provider documentation in the OpenFeature
specification to document the new `track` method support that was added
in [PR #1323](open-feature/js-sdk-contrib#1323).
### 📚 New Documentation Sections
- **Track Method Support**: Added a section explaining how the
Multi-Provider implements tracking functionality
- **Introduction Section**: Updated use case examples to highlight
tracking capabilities
- **BaseEvaluationStrategy**: Added `shouldTrackWithThisProvider` method
to the abstract class
## Code Examples Added
```typescript
// Basic tracking usage
const multiProvider = new MultiProvider([
{ provider: new ProviderA() },
{ provider: new ProviderB() }
])
await OpenFeature.setProviderAndWait(multiProvider)
const client = OpenFeature.getClient()
// Track events across all ready providers
client.track('purchase', { targetingKey: 'user123' }, { value: 99.99, currency: 'USD' })
```
---------
Signed-off-by: Jonathan Norris <jonathan@taplytics.com>
Copy file name to clipboardExpand all lines: specification/appendix-a-included-utilities.md
+69-29Lines changed: 69 additions & 29 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -44,23 +44,21 @@ flowchart LR
44
44
### Introduction
45
45
46
46
The OpenFeature Multi-Provider wraps multiple underlying providers in a unified interface, allowing the SDK client to transparently interact with all those providers at once.
47
-
This allows use cases where a single client and evaluation interface is desired, but where the flag data should come from more than one source.
47
+
This allows use cases where a single client and evaluation interface is desired, but where the flag data should come from more than one source, or where tracking events should be sent to multiple providers simultaneously.
48
48
49
49
Some examples:
50
50
51
-
- A migration from one feature flagging provider to another.
52
-
During that process, you may have some flags that have been ported to the new system and others that haven’t.
53
-
Therefore you’d want the Multi-Provider to return the result of the “new” system if available otherwise, return the "old" system’s result.
54
-
- Long-term use of multiple sources for flags.
55
-
For example, someone might want to be able to combine environment variables, database entries, and vendor feature flag results together in a single interface, and define the precedence order in which those sources should be consulted.
51
+
-**Migration**: When migrating between two providers, you can run both in parallel under a unified flagging interface. As flags are added to the new provider, the Multi-Provider will fetch flags from the new provider first, falling back to the old provider.
52
+
-**Multiple Data Sources**: The Multi-Provider allows you to combine many sources of flagging data, such as environment variables, local files, database values and SaaS hosted feature management systems.
53
+
-**Analytics Aggregation**: Send tracking events to multiple analytics providers simultaneously.
56
54
57
55
Check the [OpenFeature JavaScript Multi-Provider](https://github.com/open-feature/js-sdk-contrib/tree/main/libs/providers/multi-provider) for a reference implementation.
58
56
59
57
### Basics
60
58
61
59
The provider is initialized by passing a list of provider instances it should evaluate.
62
60
The order of the array defines the order in which sources should be evaluated.
63
-
The provider whose value is ultimately used will depend on the “strategy” that is provided, which can be chosen from a set of pre-defined ones or implemented as custom logic.
61
+
The provider whose value is ultimately used will depend on the "strategy" that is provided, which can be chosen from a set of pre-defined ones or implemented as custom logic.
64
62
65
63
For example:
66
64
@@ -80,12 +78,12 @@ const multiProvider = new MultiProvider(
From the perspective of the SDK client, this provider will now act as a “normal” spec-compliant provider, while handling the complexities of aggregating multiple providers internally.
81
+
From the perspective of the SDK client, this provider will now act as a "normal" spec-compliant provider, while handling the complexities of aggregating multiple providers internally.
84
82
85
83
### Specific Behavior
86
84
87
-
When dealing with many providers at once, various aspects of those providers need to be “combined” into one unified view.
88
-
For example, each internal provider has a “status”, which should influence the Multi-Provider’s overall “status”.
85
+
When dealing with many providers at once, various aspects of those providers need to be "combined" into one unified view.
86
+
For example, each internal provider has a "status", which should influence the Multi-Provider's overall "status".
89
87
The specific aspects that need to be addressed are described below.
90
88
91
89
#### Unique Names
@@ -116,13 +114,13 @@ Names for each provider are then determined like this:
116
114
117
115
1. name passed in to constructor if specified
118
116
2.`metadata.name` if it is unique among providers
119
-
3.`${metadata.name}_${index}` if name is not unique. Eg. the first instance of ProviderA provider might be named “providerA_1” and the second might be “providerA_2”
117
+
3.`${metadata.name}_${index}` if name is not unique. Eg. the first instance of ProviderA provider might be named "providerA_1" and the second might be "providerA_2"
120
118
121
119
If multiple names are passed in the constructor which conflict, an error will be thrown.
122
120
123
121
#### Initialization
124
122
125
-
Initialization of each provider should be handled in parallel in the Multi-Provider’s `initialize` method.
123
+
Initialization of each provider should be handled in parallel in the Multi-Provider's `initialize` method.
126
124
It should call `initialize` on each provider it is managing, and bubble up any error that is thrown by re-throwing to the client.
127
125
128
126
#### Status and Event Handling
@@ -141,15 +139,15 @@ The SDK client tracks statuses of a provider as follows:
141
139
- It can emit events like `FATAL`, `ERROR`, `STALE` and `READY` to transition to those states.
142
140
143
141
The only statuses which affect evaluation behavior at the SDK client level are `FATAL` and `NOT_READY`.
144
-
If a provider is in either of these states, evaluation will be “skipped” by the client and the default value will be returned.
142
+
If a provider is in either of these states, evaluation will be "skipped" by the client and the default value will be returned.
145
143
146
-
Other statuses are currently “informational”. Nevertheless, the Multi-Provider will represent an overall “status” based on the combined statuses of the providers.
144
+
Other statuses are currently "informational". Nevertheless, the Multi-Provider will represent an overall "status" based on the combined statuses of the providers.
147
145
148
146
##### Multi-Provider Status
149
147
150
148
The Multi-Provider mimics the event handling logic that tracks statuses in the SDK, and keeps track of the status of each provider it is managing.
151
-
The individual status-changing events from these providers will be “captured” in the Multi-Provider, and not re-emitted to the outer SDK UNLESS they cause the status of the Multi-Provider to change.
152
-
The status of the Multi-Provider will change when one of its providers changes to a status that is considered higher “precedence” than the current status.
149
+
The individual status-changing events from these providers will be "captured" in the Multi-Provider, and not re-emitted to the outer SDK UNLESS they cause the status of the Multi-Provider to change.
150
+
The status of the Multi-Provider will change when one of its providers changes to a status that is considered higher "precedence" than the current status.
153
151
154
152
The precedence order is defined as:
155
153
@@ -164,24 +162,55 @@ If one of the providers is `STALE`, the status of the Multi-Provider will be `ST
164
162
If a different provider now becomes `ERROR`, the status will be `ERROR` even if the other provider is still in `STALE`.
165
163
166
164
When the Multi-Provider changes status, it does so by emitting the appropriate event to the SDK.
167
-
The “details” of that event will be **identical** to the details of the original event from one of the inner providers which triggered this state change.
165
+
The "details" of that event will be **identical** to the details of the original event from one of the inner providers which triggered this state change.
168
166
169
-
There is another event called “configuration changed” which does not affect status.
167
+
There is another event called "configuration changed" which does not affect status.
170
168
This event should be re-emitted any time it occurs from any provider.
171
169
172
170
#### Evaluation Result
173
171
174
172
The evaluation result is based on the results from evaluating each provider.
175
-
There are multiple “strategies” configurable in the Multi-Provider to decide how to use the results.
173
+
There are multiple "strategies" configurable in the Multi-Provider to decide how to use the results.
174
+
175
+
#### Track Method Support
176
+
177
+
The Multi-Provider implements the `track` method from the OpenFeature specification, allowing tracking events to be sent across multiple underlying providers.
178
+
179
+
By default, tracking events are sent to all providers that are in `READY` status.
180
+
Providers in `NOT_READY` or `FATAL` states are automatically skipped for tracking operations.
181
+
182
+
Key features of tracking support include:
183
+
184
+
-**Error Resilience**: Individual provider tracking failures do not break the overall tracking flow - errors are logged but do not throw exceptions
185
+
-**Status Awareness**: Providers in `NOT_READY` or `FATAL` status will not recieve tracking events.
186
+
-**Strategy Integration**: Custom strategies can control which providers receive tracking calls using the `shouldTrackWithThisProvider` method
187
+
-**Graceful Degradation**: Providers that don't implement the `track` method are skipped
For custom tracking behavior, strategies can implement the `shouldTrackWithThisProvider` method to selectively track with specific providers based on event name, context, or provider characteristics.
176
205
177
206
#### Interpreting Errors
178
207
179
208
Currently, providers have multiple ways of signalling evaluation errors to the SDK.
180
-
Particularly in the case of Javascript, a provider can return an evaluation result that contains an error code and message, but still has a “value” for the result. It can also throw an error.
209
+
Particularly in the case of Javascript, a provider can return an evaluation result that contains an error code and message, but still has a "value" for the result. It can also throw an error.
181
210
182
211
Several providers currently use the former approach for indicating errors in operations, and use the `value` field of the result to return the default value from the provider itself.
183
212
184
-
For the purposes of aggregating providers, the Multi-Provider treats both thrown and returned errors as an “error” result. If the returned error result has a value, that value will be ignored by all strategies. Only “nominal” evaluation results will be considered by the evaluation.
213
+
For the purposes of aggregating providers, the Multi-Provider treats both thrown and returned errors as an "error" result. If the returned error result has a value, that value will be ignored by all strategies. Only "nominal" evaluation results will be considered by the evaluation.
185
214
186
215
### Strategies
187
216
@@ -217,31 +246,31 @@ Here are some standard strategies that come with the Multi-Provider:
217
246
Return the first result returned by a provider.
218
247
Skip providers that indicate they had no value due to `FLAG_NOT_FOUND`.
219
248
In all other cases, use the value returned by the provider.
220
-
If any provider returns an error result other than `FLAG_NOT_FOUND`, the whole evaluation should error and “bubble up” the individual provider’s error in the result.
249
+
If any provider returns an error result other than `FLAG_NOT_FOUND`, the whole evaluation should error and "bubble up" the individual provider's error in the result.
221
250
222
251
As soon as a value is returned by a provider, the rest of the operation should short-circuit and not call the rest of the providers.
223
252
224
253
[See the refrence implementation](https://github.com/open-feature/js-sdk-contrib/blob/main/libs/providers/multi-provider/src/lib/strategies/FirstMatchStrategy.ts)
225
254
226
255
#### First Successful Strategy
227
256
228
-
Similar to “First Match”, except that errors from evaluated providers do not halt execution.
257
+
Similar to "First Match", except that errors from evaluated providers do not halt execution.
229
258
Instead, it will return the first successful result from a provider. If no provider successfully responds, it will throw an error result.
230
259
231
260
[See the refrence implementation](https://github.com/open-feature/js-sdk-contrib/blob/main/libs/providers/multi-provider/src/lib/strategies/FirstSuccessfulStrategy.ts)
232
261
233
262
#### Comparison Strategy
234
263
235
264
Require that all providers agree on a value.
236
-
If every provider returns a non-error result, and the values do not agree, the Multi-Provider should return the result from a configurable “fallback” provider.
237
-
It will also call an optional “onMismatch” callback that can be used to monitor cases where mismatches of evaluation occurred.
265
+
If every provider returns a non-error result, and the values do not agree, the Multi-Provider should return the result from a configurable "fallback" provider.
266
+
It will also call an optional "onMismatch" callback that can be used to monitor cases where mismatches of evaluation occurred.
238
267
Otherwise the value of the result will be the result of the first provider in precedence order.
239
268
240
269
[See the refrence implementation](https://github.com/open-feature/js-sdk-contrib/blob/main/libs/providers/multi-provider/src/lib/strategies/ComparisonStrategy.ts)
241
270
242
271
#### User Defined Custom Strategy
243
272
244
-
Rather than making assumptions about when to use a provider’s result and when not to (which may not hold across all providers) there is also a way for the user to define their own strategy that determines whether or not to use a result or fall through to the next one.
273
+
Rather than making assumptions about when to use a provider's result and when not to (which may not hold across all providers) there is also a way for the user to define their own strategy that determines whether or not to use a result or fall through to the next one.
245
274
246
275
A strategy can be implemented by implementing the `BaseEvaluationStrategy` class as follows:
247
276
@@ -292,14 +321,21 @@ abstract class BaseEvaluationStrategy {
292
321
context:EvaluationContext,
293
322
resolutions:ProviderResolutionResult<T>[],
294
323
):FinalResult;
324
+
325
+
abstract shouldTrackWithThisProvider(
326
+
strategyContext:StrategyProviderContext,
327
+
context:EvaluationContext,
328
+
trackingEventName:string,
329
+
trackingEventDetails:TrackingEventDetails,
330
+
):boolean;
295
331
}
296
332
```
297
333
298
334
-**`runMode`**: property defines whether the providers will all be evaluated at once in `parallel`, or whether they will be evaluated `sequentially` with each result determining whether to evaluate the next one in order.
299
335
300
336
-**`shouldEvaluateThisProvider`**: function is called for each provider right before the Multi-Provider would evaluate it.
301
337
- If the function returns false, the provider will be skipped.
302
-
- This can be useful in cases where it’s desired to skip a provider based on what flag key is being used, or based on some state from the provider itself that indicates it shouldn’t be evaluated right now.
338
+
- This can be useful in cases where it's desired to skip a provider based on what flag key is being used, or based on some state from the provider itself that indicates it shouldn't be evaluated right now.
303
339
304
340
-**`shouldEvaluateNextProvider`**: function is called right after a provider is evaluated.
305
341
- It is called with the details of resolution or any error that was thrown (which will be caught).
@@ -312,19 +348,23 @@ abstract class BaseEvaluationStrategy {
312
348
- This function can be used to decide from the set of resolutions which one should ultimately be used.
313
349
- The function must return a `FinalResult` object which contains the final `ResolutionDetails` and the provider that they correspond to, or an array of `errors` in the case of a non-successful result, with the provider that created each error.
314
350
351
+
-**`shouldTrackWithThisProvider`**: function is called when the `track()` method is called on the SDK.
352
+
- This function can be used to decide which providers should recieve `track()` events.
353
+
- Return `true` to send the tracking event to the provider, `false` to skip it.
354
+
315
355
To see [reference implementations](https://github.com/open-feature/js-sdk-contrib/tree/main/libs/providers/multi-provider/src/lib/strategies) of the above-mentioned strategies.
316
356
317
357
### Hooks
318
358
319
359
Provider hooks are capable of modifying the context before an evaluation takes place.
320
-
This behavior must be preserved, but it’s also necessary to prevent these hooks from interfering with the context being passed to other providers.
360
+
This behavior must be preserved, but it's also necessary to prevent these hooks from interfering with the context being passed to other providers.
321
361
322
362
For this reason, the Multi-Provider manages calling the hooks of each provider itself, at the appropriate time.
323
363
It then uses the result of the before hooks for a given provider as the new evaluation context when evaluating **that provider**, without affecting the context used for other providers.
324
364
325
365
It then calls the after, error and finally hooks using the appropriate context as well.
326
366
327
-
Errors thrown from these hooks are be bubbled up to the client, depending on how the evaluation “strategy” defines what to do with errors.
367
+
Errors thrown from these hooks are be bubbled up to the client, depending on how the evaluation "strategy" defines what to do with errors.
0 commit comments