Skip to content

Conversation

@yasirfolio3
Copy link
Contributor

Summary

  • Updated SyncConfig to only fetch datafile through http.
  • Introduced NewAsyncPollingProjectConfigManager which doesn't initially poll.
  • Updated logic to not send notification for initial Datafile.
  • Updated polling_manager tests as per the new implementation.


// SyncConfig gets current datafile and updates projectConfig
func (cm *PollingProjectConfigManager) SyncConfig(datafile []byte) {
func (cm *PollingProjectConfigManager) SyncConfig() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

downloads datafile

if projectConfig, _ := datafileprojectconfig.NewDatafileProjectConfig(initDatafile); projectConfig != nil {
_ = pollingProjectConfigManager.setConfig(projectConfig)
}
pollingProjectConfigManager.notificationCenter = registry.GetNotificationCenter(sdkKey)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add comment, notificationcenter is set later to avoid hard-coded config update notification.

cm.err = nil
cm.configLock.Unlock()

if cm.notificationCenter != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should separate notificationCenter in a new method.

Copy link
Contributor

@msohailhussain msohailhussain left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please address

func assertPeriodically(t *testing.T, evaluationMethod func() bool) {
assert.Eventually(t, func() bool {
return evaluationMethod()
}, 500*time.Millisecond, 110*time.Millisecond)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think no issue to execute for 1 second and reduce recurring time to 50ms

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This causes issues in tests where we expect no changes in config after second poll. In such cases, 50ms returns true at 150ms, before the second polling is done which will be at 200ms.

eg.Go(configManager.Start)
evaluationMethod := func() bool {
actual, _ := configManager.GetConfig()
return reflect.DeepEqual(projectConfig, actual)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use actual.GetRevision() == hardcodedRevision.

eg.Go(configManager.Start)
evaluationMethod := func() bool {
actual, _ := configManager.GetConfig()
return reflect.DeepEqual(projectConfig, actual)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use only revision to identify config version.

eg.TerminateAndWait()
}

func TestSyncConfig(t *testing.T) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What you are trying to test, please add as a comment. TestSyncConfig is very general name.

// poll after 100ms
eg.Go(configManager.Start)
evaluationMethod := func() bool {
_, err := configManager.GetConfig()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above.


func TestNewPollingProjectConfigManagerWithSimilarDatafileRevisions(t *testing.T) {
mockDatafile1 := []byte(`{"revision":"42","botFiltering":true}`)
mockDatafile2 := []byte(`{"revision":"42","botFiltering":false}`)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

botFiltering is false Please make it same.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need the difference in datafiles to make sure the original datafile wasn't changed because of same revision.

eg.TerminateAndWait()
}

func TestNewPollingProjectConfigManagerWithSimilarDatafileRevisions(t *testing.T) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please assert notification, it shouldn't be sent. request assertion should be true.

@yasirfolio3 yasirfolio3 changed the title (DO NOT REVIEW) refact: Updated polling_manager implementation and unit tests. refact: Updated polling_manager implementation and unit tests. Jan 8, 2020
eg.TerminateAndWait()
}

func TestNewAsyncPollingProjectConfigManagerWithSimilarDatafileRevisions(t *testing.T) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's here you want to test, please add in the comments.

asyncConfigManager := NewAsyncPollingProjectConfigManager(sdkKey, WithRequester(mockRequester), WithInitialDatafile(mockDatafile1), WithPollingInterval(100*time.Millisecond))

var numberOfCalls uint64 = 0
callback := func(notification notification.ProjectConfigUpdateNotification) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we have similar datafile revision, then how it's gonna be called. please explain the reason to declare here.


// poll after 100ms
eg.Go(asyncConfigManager.Start)
evaluationMethod := func() bool {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is not best fit here, just use sleep

assert.NotNil(t, actual)
assert.Equal(t, projectConfig1, actual)
// poll after 100ms to check no changes were made to the previous config because of 304 error code (first poll)
eg.Go(configManager.Start)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't use Start, use SyncConfig

actual, err = configManager.GetConfig()
assert.Equal(t, projectConfig2, actual)
// poll after 100ms
eg.Go(configManager.Start)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Start immediately while you are instantiating object.

assert.Equal(t, projectConfig1, actual)

// poll after 100ms
eg.Go(asyncConfigManager.Start)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't poll. just use SyncConfig

@msohailhussain msohailhussain marked this pull request as ready for review January 10, 2020 17:46
@msohailhussain msohailhussain requested a review from a team as a code owner January 10, 2020 17:46
Copy link
Contributor

@pawels-optimizely pawels-optimizely left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please see my comments

return cm.projectConfig, nil
}

func (cm *PollingProjectConfigManager) setConfig(projectConfig ProjectConfig) error {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would remove locking mechanism here and minimize the number of calls to locking.
of course cm.sendConfigUpdateNotification() will need to be called in SyncConfig then

cm.setConfig(projectConfig)
cm.err = nil
} else {
cm.err = err
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think , to be safe, we need to lock cm.err too.

cmLogger.Warning("Problem with sending notification")
}
}
cm.sendConfigUpdateNotification()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think cm.setConfig() should still return an error, and we need to sendConfigUpdateNotification only when error is not nil

Copy link
Contributor

@pawels-optimizely pawels-optimizely left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it looks much cleaner, thank you for the changes, I put 2 small comments which I think need to be addressed. otherwise lgtm

cmLogger.Debug(fmt.Sprintf("New datafile set with revision: %s. Old revision: %s", projectConfig.GetRevision(), previousRevision))
cm.sendConfigUpdateNotification()
}
closeMutex(err)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

closing mutex needs to happen before sending notification.

Copy link
Contributor

@pawels-optimizely pawels-optimizely left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

closing mutex needs to happen before sending notification.

otherwise looks good

Copy link
Contributor

@pawels-optimizely pawels-optimizely left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

Copy link
Contributor

@msohailhussain msohailhussain left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@mikeproeng37 mikeproeng37 merged commit 4aefcaa into master Jan 16, 2020
@mikeproeng37 mikeproeng37 deleted the yasir/refact-polling-manager branch January 16, 2020 21:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants