Skip to content

Commit c061cf4

Browse files
feat: flagd - make sure provider initialize only once (#418)
Signed-off-by: Kavindu Dodanduwa <[email protected]>
1 parent f56b208 commit c061cf4

File tree

2 files changed

+56
-2
lines changed

2 files changed

+56
-2
lines changed

providers/flagd/pkg/provider.go

+16-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
)
1414

1515
type Provider struct {
16+
initialized bool
1617
logger logr.Logger
1718
providerConfiguration *providerConfiguration
1819
service IService
@@ -29,6 +30,7 @@ func NewProvider(opts ...ProviderOption) *Provider {
2930
providerConfiguration := NewDefaultConfiguration(log)
3031

3132
provider := &Provider{
33+
initialized: false,
3234
eventStream: make(chan of.Event),
3335
logger: log,
3436
providerConfiguration: providerConfiguration,
@@ -73,7 +75,15 @@ func NewProvider(opts ...ProviderOption) *Provider {
7375
return provider
7476
}
7577

76-
func (p *Provider) Init(evaluationContext of.EvaluationContext) error {
78+
func (p *Provider) Init(_ of.EvaluationContext) error {
79+
p.mtx.Lock()
80+
defer p.mtx.Unlock()
81+
82+
// avoid reinitialization if initialized
83+
if p.initialized {
84+
return nil
85+
}
86+
7787
err := p.service.Init()
7888
if err != nil {
7989
return err
@@ -86,6 +96,7 @@ func (p *Provider) Init(evaluationContext of.EvaluationContext) error {
8696
}
8797

8898
p.status = of.ReadyState
99+
p.initialized = true
89100

90101
// start event handling after the first ready event
91102
go func() {
@@ -112,6 +123,10 @@ func (p *Provider) Status() of.State {
112123
}
113124

114125
func (p *Provider) Shutdown() {
126+
p.mtx.Lock()
127+
defer p.mtx.Unlock()
128+
129+
p.initialized = false
115130
p.service.Shutdown()
116131
}
117132

providers/flagd/pkg/provider_test.go

+40-1
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ func TestEventHandling(t *testing.T) {
122122

123123
svcMock := mock.NewMockIService(ctrl)
124124
svcMock.EXPECT().EventChannel().Return(customChan).AnyTimes()
125-
svcMock.EXPECT().Init().AnyTimes()
125+
svcMock.EXPECT().Init().Times(1)
126126

127127
provider := NewProvider()
128128
provider.service = svcMock
@@ -174,5 +174,44 @@ func TestEventHandling(t *testing.T) {
174174
if provider.Status() != of.ErrorState {
175175
t.Errorf("expected status to be error, but got %v", provider.Status())
176176
}
177+
}
178+
179+
func TestInitializeOnlyOnce(t *testing.T) {
180+
// given
181+
ctrl := gomock.NewController(t)
182+
defer ctrl.Finish()
183+
184+
eventChan := make(chan of.Event)
185+
186+
svcMock := mock.NewMockIService(ctrl)
187+
svcMock.EXPECT().Init().Times(1)
188+
svcMock.EXPECT().EventChannel().Return(eventChan).Times(1)
189+
svcMock.EXPECT().Shutdown().Times(1)
190+
191+
provider := NewProvider()
192+
provider.service = svcMock
193+
194+
// make service ready with events
195+
go func() {
196+
eventChan <- of.Event{
197+
ProviderName: "mock provider",
198+
EventType: of.ProviderReady,
199+
}
200+
}()
201+
202+
// multiple init invokes
203+
_ = provider.Init(of.EvaluationContext{})
204+
_ = provider.Init(of.EvaluationContext{})
205+
206+
if !provider.initialized {
207+
t.Errorf("expected provider to be ready, but got not ready")
208+
}
209+
210+
// shutdown should make provider uninitialized
211+
provider.Shutdown()
212+
213+
if provider.initialized {
214+
t.Errorf("expected provider to be not ready, but got ready")
215+
}
177216

178217
}

0 commit comments

Comments
 (0)