Skip to content

Commit 940cb8b

Browse files
feat: provider client 1:n binding support (#190)
* eventing implementation Signed-off-by: Kavindu Dodanduwa <[email protected]> * review changes Signed-off-by: Kavindu Dodanduwa <[email protected]> * constructor renaming Signed-off-by: Kavindu Dodanduwa <[email protected]> * sepc compliance Signed-off-by: Kavindu Dodanduwa <[email protected]> * provider readiness to named binding Signed-off-by: Kavindu Dodanduwa <[email protected]> * review suggestion Signed-off-by: Kavindu Dodanduwa <[email protected]> * code docs and refine Signed-off-by: Kavindu Dodanduwa <[email protected]> * nits Signed-off-by: Kavindu Dodanduwa <[email protected]> * Update pkg/openfeature/event_executor.go Co-authored-by: Todd Baert <[email protected]> Signed-off-by: Kavindu Dodanduwa <[email protected]> * Update pkg/openfeature/event_executor.go Co-authored-by: Todd Baert <[email protected]> Signed-off-by: Kavindu Dodanduwa <[email protected]> * review commits Signed-off-by: Kavindu Dodanduwa <[email protected]> * remove timeout Signed-off-by: Kavindu Dodanduwa <[email protected]> * fix deps Signed-off-by: Kavindu Dodanduwa <[email protected]> * eventing implementation Signed-off-by: Kavindu Dodanduwa <[email protected]> * eventing implementation Signed-off-by: Kavindu Dodanduwa <[email protected]> * 1 to n support and eventing completeness Signed-off-by: Kavindu Dodanduwa <[email protected]> * fix merge conflicts Signed-off-by: Kavindu Dodanduwa <[email protected]> * Update pkg/openfeature/api.go Co-authored-by: Todd Baert <[email protected]> Signed-off-by: Kavindu Dodanduwa <[email protected]> * migrate tests to api and client level where possible Signed-off-by: Kavindu Dodanduwa <[email protected]> * review change Signed-off-by: Kavindu Dodanduwa <[email protected]> * rename of noop state handler Signed-off-by: Kavindu Dodanduwa <[email protected]> --------- Signed-off-by: Kavindu Dodanduwa <[email protected]> Signed-off-by: Kavindu Dodanduwa <[email protected]> Co-authored-by: Todd Baert <[email protected]>
1 parent 220dc33 commit 940cb8b

File tree

10 files changed

+1183
-190
lines changed

10 files changed

+1183
-190
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ require (
99
github.com/open-feature/go-sdk-contrib/providers/flagd v0.1.7
1010
github.com/open-feature/go-sdk-contrib/tests/flagd v1.1.0
1111
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1
12-
golang.org/x/text v0.11.0
12+
golang.org/x/text v0.10.0
1313
)
1414

1515
require (

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -440,8 +440,8 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
440440
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
441441
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
442442
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
443-
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
444-
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
443+
golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58=
444+
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
445445
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
446446
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
447447
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=

pkg/openfeature/api.go

Lines changed: 61 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66

77
"github.com/go-logr/logr"
88
"github.com/open-feature/go-sdk/pkg/openfeature/internal"
9+
"golang.org/x/exp/maps"
910
)
1011

1112
// evaluationAPI wraps OpenFeature evaluation API functionalities
@@ -16,7 +17,7 @@ type evaluationAPI struct {
1617
evalCtx EvaluationContext
1718
logger logr.Logger
1819
mu sync.RWMutex
19-
eventExecutor
20+
eventExecutor *eventExecutor
2021
}
2122

2223
// newEvaluationAPI is a helper to generate an API. Used internally
@@ -46,10 +47,10 @@ func (api *evaluationAPI) setProvider(provider FeatureProvider) error {
4647
// Initialize new default provider and shutdown the old one
4748
// Provider update must be non-blocking, hence initialization & shutdown happens concurrently
4849
oldProvider := api.defaultProvider
49-
api.initAndShutdown(provider, oldProvider)
5050
api.defaultProvider = provider
5151

52-
err := api.registerDefaultProvider(provider)
52+
api.initNewAndShutdownOld(provider, oldProvider)
53+
err := api.eventExecutor.registerDefaultProvider(provider)
5354
if err != nil {
5455
return err
5556
}
@@ -76,10 +77,11 @@ func (api *evaluationAPI) setNamedProvider(clientName string, provider FeaturePr
7677

7778
// Initialize new default provider and shutdown the old one
7879
// Provider update must be non-blocking, hence initialization & shutdown happens concurrently
79-
api.initAndShutdown(provider, api.namedProviders[clientName])
80+
oldProvider := api.namedProviders[clientName]
8081
api.namedProviders[clientName] = provider
8182

82-
err := api.registerNamedEventingProvider(clientName, provider)
83+
api.initNewAndShutdownOld(provider, oldProvider)
84+
err := api.eventExecutor.registerNamedEventingProvider(clientName, provider)
8385
if err != nil {
8486
return err
8587
}
@@ -125,6 +127,9 @@ func (api *evaluationAPI) addHooks(hooks ...Hook) {
125127
}
126128

127129
func (api *evaluationAPI) shutdown() {
130+
api.mu.Lock()
131+
defer api.mu.Unlock()
132+
128133
v, ok := api.defaultProvider.(StateHandler)
129134
if ok {
130135
v.Shutdown()
@@ -161,21 +166,57 @@ func (api *evaluationAPI) forTransaction(clientName string) (FeatureProvider, []
161166
return provider, api.hks, api.evalCtx
162167
}
163168

164-
// initAndShutdown is a helper to initialise new FeatureProvider and shutdown old FeatureProvider.
165-
// Operation happens concurrently.
166-
func (api *evaluationAPI) initAndShutdown(newProvider FeatureProvider, oldProvider FeatureProvider) {
167-
go func() {
168-
v, ok := newProvider.(StateHandler)
169-
if ok {
170-
v.Init(api.evalCtx)
171-
}
172-
173-
// oldProvider can be nil
174-
if oldProvider != nil {
175-
v, ok = oldProvider.(StateHandler)
176-
if ok {
177-
v.Shutdown()
169+
// initNewAndShutdownOld is a helper to initialise new FeatureProvider and shutdown the old FeatureProvider.
170+
// Operations happen concurrently.
171+
func (api *evaluationAPI) initNewAndShutdownOld(newProvider FeatureProvider, oldProvider FeatureProvider) {
172+
v, ok := newProvider.(StateHandler)
173+
if ok && v.Status() == NotReadyState {
174+
go func(provider FeatureProvider, stateHandler StateHandler, evalCtx EvaluationContext, eventChan chan eventPayload) {
175+
err := stateHandler.Init(evalCtx)
176+
// emit ready/error event once initialization is complete
177+
if err != nil {
178+
eventChan <- eventPayload{
179+
Event{
180+
ProviderName: provider.Metadata().Name,
181+
EventType: ProviderError,
182+
ProviderEventDetails: ProviderEventDetails{},
183+
}, provider,
184+
}
185+
} else {
186+
eventChan <- eventPayload{
187+
Event{
188+
ProviderName: provider.Metadata().Name,
189+
EventType: ProviderReady,
190+
ProviderEventDetails: ProviderEventDetails{},
191+
}, provider,
192+
}
178193
}
194+
}(newProvider, v, api.evalCtx, api.eventExecutor.eventChan)
195+
}
196+
197+
v, ok = oldProvider.(StateHandler)
198+
199+
// oldProvider can be nil or without state handling capability
200+
if oldProvider == nil || !ok {
201+
return
202+
}
203+
204+
// check for multiple bindings
205+
if oldProvider == api.defaultProvider || contains(oldProvider, maps.Values(api.namedProviders)) {
206+
return
207+
}
208+
209+
go func(forShutdown StateHandler) {
210+
forShutdown.Shutdown()
211+
}(v)
212+
}
213+
214+
func contains(provider FeatureProvider, in []FeatureProvider) bool {
215+
for _, p := range in {
216+
if provider == p {
217+
return true
179218
}
180-
}()
219+
}
220+
221+
return false
181222
}

0 commit comments

Comments
 (0)