Skip to content

Commit d35f4d6

Browse files
jblackerbbland1
andauthored
feat: implement multiprovider (#669)
Signed-off-by: bbland1 <[email protected]> Signed-off-by: Jordan Blacker <[email protected]> Co-authored-by: bbland1 <[email protected]>
1 parent 7762020 commit d35f4d6

19 files changed

+4567
-1
lines changed

.release-please-manifest.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,6 @@
1515
"providers/ofrep": "0.1.5",
1616
"providers/prefab": "0.0.2",
1717
"tests/flagd": "1.4.1",
18-
"providers/go-feature-flag-in-process": "0.1.0"
18+
"providers/go-feature-flag-in-process": "0.1.0",
19+
"providers/multi-provider": "0.0.3"
1920
}

providers/multi-provider/Makefile

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
.PHONY: generate test
2+
GOPATH_LOC = ${GOPATH}
3+
4+
generate:
5+
go generate ./...
6+
go mod download
7+
mockgen -source=${GOPATH}/pkg/mod/github.com/open-feature/[email protected]/openfeature/provider.go -package=mocks -destination=./internal/mocks/provider_mock.go
8+
9+
test:
10+
go test ./...

providers/multi-provider/README.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
OpenFeature Multi-Provider
2+
------------
3+
4+
The Multi-Provider allows you to use multiple underlying providers as sources of flag data for the OpenFeature server SDK.
5+
When a flag is being evaluated, the Multi-Provider will consult each underlying provider it is managing in order to
6+
determine the final result. Different evaluation strategies can be defined to control which providers get evaluated and
7+
which result is used.
8+
9+
The Multi-Provider is a powerful tool for performing migrations between flag providers, or combining multiple providers
10+
into a single feature flagging interface. For example:
11+
12+
- **Migration**: When migrating between two providers, you can run both in parallel under a unified flagging interface.
13+
As flags are added to the new provider, the Multi-Provider will automatically find and return them, falling back to the old provider
14+
if the new provider does not have
15+
- **Multiple Data Sources**: The Multi-Provider allows you to seamlessly combine many sources of flagging data, such as
16+
environment variables, local files, database values and SaaS hosted feature management systems.
17+
18+
# Installation
19+
20+
```sh
21+
go get github.com/open-feature/go-sdk-contrib/providers/multi-provider
22+
go get github.com/open-feature/go-sdk
23+
```
24+
25+
# Usage
26+
27+
```go
28+
import (
29+
"github.com/open-feature/go-sdk/openfeature"
30+
mp "github.com/open-feature/go-sdk-contrib/providers/multi-provider"
31+
)
32+
33+
providers := make(mp.ProviderMap)
34+
providers["providerA"] = providerA
35+
providers["providerB"] = providerB
36+
provider, err := mp.NewMultiProvider(providers, mp.StrategyFirstMatch, WithLogger(myLogger))
37+
openfeature.SetProvider(provider)
38+
```
39+
40+
# Options
41+
42+
- `WithTimeout` - the duration is used for the total timeout across parallel operations. If none is set it will default
43+
to 5 seconds. This is not supported for `FirstMatch` yet, which executes sequentially
44+
- `WithFallbackProvider` - Used for setting a fallback provider for the `Comparison` strategy
45+
- `WithLogger` - Provides slog support
46+
47+
# Strategies
48+
49+
There are multiple strategies that can be used to determine the result returned to the caller. A strategy must be set at
50+
initialization time.
51+
52+
There are 3 strategies available currently:
53+
54+
- _First Match_
55+
- _First Success_
56+
- _Comparison_
57+
58+
## First Match Strategy
59+
60+
The first match strategy works by **sequentially** calling each provider in the order that they are provided to the mutli-provider.
61+
The first provider that returns a result. It will try calling the next provider whenever it encounters a `FLAG_NOT_FOUND`
62+
error. However, if a provider returns an error other than `FLAG_NOT_FOUND` the provider will stop and return the default
63+
value along with setting the error details if a detailed request is issued. (allow changing this behavior?)
64+
65+
## First Success Strategy
66+
67+
The First Success strategy works by calling each provider in **parallel**. The first provider that returns a response
68+
with no errors is returned and all other calls are cancelled. If no provider provides a successful result the default
69+
value will be returned to the caller.
70+
71+
## Comparison
72+
73+
The Comparison strategy works by calling each provider in **parallel**. All results are collected from each provider and
74+
then the resolved results are compared to each other. If they all agree then that value is returned. If not and a fallback
75+
provider is specified then the fallback will be executed. If no fallback is configured then the default value will be
76+
returned. If a provider returns `FLAG_NOT_FOUND` that is not included in the comparison. If all providers
77+
return not found then the default value is returned. Finally, if any provider returns an error other than `FLAG_NOT_FOUND`
78+
the evaluation immediately stops and that error result is returned. This strategy does NOT support `ObjectEvaluation`
79+
80+
# Not Yet Implemented
81+
82+
- Hooks support
83+
- Event support
84+
- Full slog support

providers/multi-provider/go.mod

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
module github.com/open-feature/go-sdk-contrib/providers/multi-provider
2+
3+
go 1.23.0
4+
5+
require (
6+
github.com/open-feature/go-sdk v1.13.1
7+
github.com/stretchr/testify v1.9.0
8+
go.uber.org/mock v0.5.1
9+
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842
10+
golang.org/x/sync v0.7.0
11+
)
12+
13+
require (
14+
github.com/davecgh/go-spew v1.1.1 // indirect
15+
github.com/go-logr/logr v1.4.2 // indirect
16+
github.com/pmezard/go-difflib v1.0.0 // indirect
17+
gopkg.in/yaml.v3 v3.0.1 // indirect
18+
)

providers/multi-provider/go.sum

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
2+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3+
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
4+
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
5+
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
6+
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
7+
github.com/open-feature/go-sdk v1.13.1 h1:RJbS70eyi7Jd3Zm5bFnaahNKNDXn+RAVnctpGu+uPis=
8+
github.com/open-feature/go-sdk v1.13.1/go.mod h1:O8r4mhgeRIsjJ0ZBXlnE0BtbT/79W44gQceR7K8KYgo=
9+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
10+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
11+
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
12+
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
13+
go.uber.org/mock v0.5.1 h1:ASgazW/qBmR+A32MYFDB6E2POoTgOwT509VP0CT/fjs=
14+
go.uber.org/mock v0.5.1/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
15+
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM=
16+
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
17+
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
18+
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
19+
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
20+
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
21+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
22+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
23+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
24+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

providers/multi-provider/internal/mocks/provider_mock.go

Lines changed: 242 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)