Skip to content

Commit 4aefcaa

Browse files
yasirfolio3Michael Ng
authored andcommitted
refact: Updated polling_manager implementation and unit tests. (#224)
1 parent b75e05a commit 4aefcaa

File tree

2 files changed

+495
-130
lines changed

2 files changed

+495
-130
lines changed

pkg/config/polling_manager.go

Lines changed: 90 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -95,52 +95,47 @@ func WithInitialDatafile(datafile []byte) OptionFunc {
9595
}
9696
}
9797

98-
// SyncConfig gets current datafile and updates projectConfig
99-
func (cm *PollingProjectConfigManager) SyncConfig(datafile []byte) {
98+
// SyncConfig downloads datafile and updates projectConfig
99+
func (cm *PollingProjectConfigManager) SyncConfig() {
100100
var e error
101101
var code int
102102
var respHeaders http.Header
103+
var datafile []byte
103104

104105
closeMutex := func(e error) {
105106
cm.err = e
106107
cm.configLock.Unlock()
107108
}
108109

109110
url := fmt.Sprintf(cm.datafileURLTemplate, cm.sdkKey)
110-
if len(datafile) == 0 {
111-
if cm.lastModified != "" {
112-
lastModifiedHeader := utils.Header{Name: ModifiedSince, Value: cm.lastModified}
113-
datafile, respHeaders, code, e = cm.requester.Get(url, lastModifiedHeader)
114-
} else {
115-
datafile, respHeaders, code, e = cm.requester.Get(url)
116-
}
117-
118-
if e != nil {
119-
msg := "unable to fetch fresh datafile"
120-
cmLogger.Warning(msg)
121-
cm.configLock.Lock()
122-
closeMutex(errors.New(fmt.Sprintf("%s, reason (http status code): %s", msg, e.Error())))
123-
return
124-
}
125-
126-
if code == http.StatusNotModified {
127-
cmLogger.Debug("The datafile was not modified and won't be downloaded again")
128-
return
129-
}
111+
if cm.lastModified != "" {
112+
lastModifiedHeader := utils.Header{Name: ModifiedSince, Value: cm.lastModified}
113+
datafile, respHeaders, code, e = cm.requester.Get(url, lastModifiedHeader)
114+
} else {
115+
datafile, respHeaders, code, e = cm.requester.Get(url)
116+
}
130117

131-
// Save last-modified date from response header
132-
lastModified := respHeaders.Get(LastModified)
133-
if lastModified != "" {
134-
cm.configLock.Lock()
135-
cm.lastModified = lastModified
136-
cm.configLock.Unlock()
137-
}
118+
if e != nil {
119+
msg := "unable to fetch fresh datafile"
120+
cmLogger.Warning(msg)
121+
cm.configLock.Lock()
122+
closeMutex(errors.New(fmt.Sprintf("%s, reason (http status code): %s", msg, e.Error())))
123+
return
138124
}
139125

140-
projectConfig, err := datafileprojectconfig.NewDatafileProjectConfig(datafile)
126+
if code == http.StatusNotModified {
127+
cmLogger.Debug("The datafile was not modified and won't be downloaded again")
128+
return
129+
}
141130

131+
// Save last-modified date from response header
142132
cm.configLock.Lock()
133+
lastModified := respHeaders.Get(LastModified)
134+
if lastModified != "" {
135+
cm.lastModified = lastModified
136+
}
143137

138+
projectConfig, err := datafileprojectconfig.NewDatafileProjectConfig(datafile)
144139
if err != nil {
145140
cmLogger.Warning("failed to create project config")
146141
closeMutex(errors.New("unable to parse datafile"))
@@ -156,21 +151,11 @@ func (cm *PollingProjectConfigManager) SyncConfig(datafile []byte) {
156151
closeMutex(nil)
157152
return
158153
}
159-
cmLogger.Debug(fmt.Sprintf("New datafile set with revision: %s. Old revision: %s", projectConfig.GetRevision(), previousRevision))
160-
cm.projectConfig = projectConfig
161-
if cm.optimizelyConfig != nil {
162-
cm.optimizelyConfig = NewOptimizelyConfig(projectConfig)
163-
}
164-
closeMutex(nil)
165-
166-
if cm.notificationCenter != nil {
167-
projectConfigUpdateNotification := notification.ProjectConfigUpdateNotification{
168-
Type: notification.ProjectConfigUpdate,
169-
Revision: cm.projectConfig.GetRevision(),
170-
}
171-
if err = cm.notificationCenter.Send(notification.ProjectConfigUpdate, projectConfigUpdateNotification); err != nil {
172-
cmLogger.Warning("Problem with sending notification")
173-
}
154+
err = cm.setConfig(projectConfig)
155+
closeMutex(err)
156+
if err == nil {
157+
cmLogger.Debug(fmt.Sprintf("New datafile set with revision: %s. Old revision: %s", projectConfig.GetRevision(), previousRevision))
158+
cm.sendConfigUpdateNotification()
174159
}
175160
}
176161

@@ -181,7 +166,7 @@ func (cm *PollingProjectConfigManager) Start(ctx context.Context) {
181166
for {
182167
select {
183168
case <-t.C:
184-
cm.SyncConfig([]byte{})
169+
cm.SyncConfig()
185170
case <-ctx.Done():
186171
cmLogger.Debug("Polling Config Manager Stopped")
187172
return
@@ -204,8 +189,30 @@ func NewPollingProjectConfigManager(sdkKey string, pollingMangerOptions ...Optio
204189
opt(&pollingProjectConfigManager)
205190
}
206191

207-
initDatafile := pollingProjectConfigManager.initDatafile
208-
pollingProjectConfigManager.SyncConfig(initDatafile) // initial poll
192+
if len(pollingProjectConfigManager.initDatafile) > 0 {
193+
pollingProjectConfigManager.setInitialDatafile(pollingProjectConfigManager.initDatafile)
194+
} else {
195+
pollingProjectConfigManager.SyncConfig() // initial poll
196+
}
197+
return &pollingProjectConfigManager
198+
}
199+
200+
// NewAsyncPollingProjectConfigManager returns an instance of the async polling config manager with the customized configuration
201+
func NewAsyncPollingProjectConfigManager(sdkKey string, pollingMangerOptions ...OptionFunc) *PollingProjectConfigManager {
202+
203+
pollingProjectConfigManager := PollingProjectConfigManager{
204+
notificationCenter: registry.GetNotificationCenter(sdkKey),
205+
pollingInterval: DefaultPollingInterval,
206+
requester: utils.NewHTTPRequester(),
207+
datafileURLTemplate: DatafileURLTemplate,
208+
sdkKey: sdkKey,
209+
}
210+
211+
for _, opt := range pollingMangerOptions {
212+
opt(&pollingProjectConfigManager)
213+
}
214+
215+
pollingProjectConfigManager.setInitialDatafile(pollingProjectConfigManager.initDatafile)
209216
return &pollingProjectConfigManager
210217
}
211218

@@ -256,3 +263,38 @@ func (cm *PollingProjectConfigManager) RemoveOnProjectConfigUpdate(id int) error
256263
}
257264
return nil
258265
}
266+
267+
func (cm *PollingProjectConfigManager) setConfig(projectConfig ProjectConfig) error {
268+
if projectConfig == nil {
269+
return errors.New("unable to set nil config")
270+
}
271+
cm.projectConfig = projectConfig
272+
if cm.optimizelyConfig != nil {
273+
cm.optimizelyConfig = NewOptimizelyConfig(projectConfig)
274+
}
275+
return nil
276+
}
277+
278+
func (cm *PollingProjectConfigManager) setInitialDatafile(datafile []byte) {
279+
if len(datafile) != 0 {
280+
cm.configLock.Lock()
281+
defer cm.configLock.Unlock()
282+
projectConfig, err := datafileprojectconfig.NewDatafileProjectConfig(datafile)
283+
if projectConfig != nil {
284+
err = cm.setConfig(projectConfig)
285+
}
286+
cm.err = err
287+
}
288+
}
289+
290+
func (cm *PollingProjectConfigManager) sendConfigUpdateNotification() {
291+
if cm.notificationCenter != nil {
292+
projectConfigUpdateNotification := notification.ProjectConfigUpdateNotification{
293+
Type: notification.ProjectConfigUpdate,
294+
Revision: cm.projectConfig.GetRevision(),
295+
}
296+
if err := cm.notificationCenter.Send(notification.ProjectConfigUpdate, projectConfigUpdateNotification); err != nil {
297+
cmLogger.Warning("Problem with sending notification")
298+
}
299+
}
300+
}

0 commit comments

Comments
 (0)