Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 12 additions & 11 deletions openfeature/multi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,13 @@ import (
"github.com/open-feature/go-sdk/openfeature/memprovider"
)

providers := make(multi.ProviderMap)
providers["providerA"] = memprovider.NewInMemoryProvider(map[string]memprovider.InMemoryFlag{})
providers["providerB"] = myCustomProvider
mprovider, err := multi.NewProvider(providers, multi.StrategyFirstMatch)
mprovider, err := multi.NewProvider(
multi.StrategyFirstMatch,
multi.WithProvider("providerA", memprovider.NewInMemoryProvider(/*...*/),
multi.WithProvider("providerB", myCustomProvider),
)
if err != nil {
return err
return err
}

openfeature.SetNamedProviderAndWait("multiprovider", mprovider)
Expand Down Expand Up @@ -101,7 +102,7 @@ type StrategyConstructor func(providers []*NamedProvider) StrategyFn[FlagTypes]

Build your strategy to wrap around the slice of providers
```go
option := multi.WithCustomStrategy(func(providers []*NamedProvider) StrategyFn[FlagTypes] {
option := multi.WithCustomStrategy(func(providers []NamedProvider) StrategyFn[FlagTypes] {
return func[T FlagTypes](ctx context.Context, flag string, defaultValue T, flatCtx openfeature.FlattenedContext) openfeature.GenericResolutionDetail[T] {
// implementation
// ...
Expand Down Expand Up @@ -140,12 +141,12 @@ essentially a factory that allows the `StrategyFn` to wrap around a slice of `Na
Allows for setting global hooks for the multi-provider. These are `openfeature.Hook` implementations that affect
**all** internal `FeatureProvider` instances.

### `WithProviderHooks`
### `WithProvider`

Allows for setting `openfeature.Hook` implementations on a specific named `FeatureProvider` within the multi-provider.
This should only be used when hooks need to be attached to a `FeatureProvider` instance that does not implement that functionality.
Using a provider name that is not known will cause an error to be returned during the creation time. This option can be
used multiple times using unique provider names.
Allows for registering a specific `FeatureProvider` instance under a unique provider name. Optional `openfeature.Hook`
implementations may also be provided, which will execute only for this specific provider. This option can be used multiple
times with unique provider names to register multiple providers.
The order in which `WithProvider` options are provided determines the order in which the providers are registered and evaluated.

## `StrategyComparision` specific options

Expand Down
12 changes: 6 additions & 6 deletions openfeature/multi/comparison_strategy.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ type Comparator func(values []any) bool
// can be passed as long as ObjectEvaluation is never called with objects that are not comparable. The custom [Comparator]
// will only be used for [of.FeatureProvider.ObjectEvaluation] if set. If [of.FeatureProvider.ObjectEvaluation] is
// called without setting a [Comparator], and the returned object(s) are not comparable, then an error will occur.
func newComparisonStrategy(providers []*NamedProvider, fallbackProvider of.FeatureProvider, comparator Comparator) StrategyFn[FlagTypes] {
func newComparisonStrategy(providers []NamedProvider, fallbackProvider of.FeatureProvider, comparator Comparator) StrategyFn[FlagTypes] {
return evaluateComparison[FlagTypes](providers, fallbackProvider, comparator)
}

Expand Down Expand Up @@ -81,7 +81,7 @@ func comparisonResolutionError(metadata of.FlagMetadata) of.ResolutionError {
return of.NewGeneralResolutionError("comparison failure")
}

func evaluateComparison[T FlagTypes](providers []*NamedProvider, fallbackProvider of.FeatureProvider, comparator Comparator) StrategyFn[T] {
func evaluateComparison[T FlagTypes](providers []NamedProvider, fallbackProvider of.FeatureProvider, comparator Comparator) StrategyFn[T] {
return func(ctx context.Context, flag string, defaultValue T, evalCtx of.FlattenedContext) of.GenericResolutionDetail[T] {
if comparator == nil {
comparator = defaultComparator
Expand All @@ -103,7 +103,7 @@ func evaluateComparison[T FlagTypes](providers []*NamedProvider, fallbackProvide
// Short circuit if there's only one provider as no comparison nor workers are needed
if len(providers) == 1 {
result := Evaluate(ctx, providers[0], flag, defaultValue, evalCtx)
metadata := setFlagMetadata(StrategyComparison, providers[0].Name, make(of.FlagMetadata))
metadata := setFlagMetadata(StrategyComparison, providers[0].Name(), make(of.FlagMetadata))
metadata[MetadataFallbackUsed] = false
result.FlagMetadata = mergeFlagMeta(result.FlagMetadata, metadata)
return result
Expand All @@ -124,13 +124,13 @@ func evaluateComparison[T FlagTypes](providers []*NamedProvider, fallbackProvide
notFound := result.ResolutionDetail().ErrorCode == of.FlagNotFoundCode
if !notFound && result.Error() != nil {
return &ProviderError{
ProviderName: closedProvider.Name,
ProviderName: closedProvider.Name(),
Err: result.Error(),
}
}
if !notFound {
resultChan <- &namedResult{
name: closedProvider.Name,
name: closedProvider.Name(),
res: &result,
}
} else {
Expand Down Expand Up @@ -225,7 +225,7 @@ func evaluateComparison[T FlagTypes](providers []*NamedProvider, fallbackProvide
if fallbackProvider != nil {
fallbackResult := Evaluate(
ctx,
&NamedProvider{Name: "fallback", FeatureProvider: fallbackProvider},
&namedProvider{name: "fallback", FeatureProvider: fallbackProvider},
flag,
defaultValue,
evalCtx,
Expand Down
Loading
Loading