-
Notifications
You must be signed in to change notification settings - Fork 19
fix(notification): Remote notification only #219
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
pkg/config/polling_manager_test.go
Outdated
configManager.SyncConfig(mockDatafile2) | ||
optimizelyConfig = configManager.GetOptimizelyConfig() | ||
assert.Equal(t, "43", optimizelyConfig.Revision) | ||
//mockRequester.AssertExpectations(t) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@msohailhussain , not sure why I could not check for requester assert expectation. Can you take a look ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know how it was working before. When SyncConfig is called with payload in the argument, it means no Get
call should be asserted. I have removed explicit SyncConfig
call and now dependent on Start
scheduled call. Very first call is called immediately, so no major wait in this unit test.
projectConfigUpdateNotification := notification.ProjectConfigUpdateNotification{ | ||
Type: notification.ProjectConfigUpdate, | ||
Revision: cm.projectConfig.GetRevision(), | ||
Revision: projectConfig.GetRevision(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI. race condition fix
mockDatafile2 := []byte(`{"revision":"43"}`) | ||
sdkKey := "test_sdk_key" | ||
|
||
mockRequester := new(MockRequester) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This mockRequester
isn't passed as an option to NewPollingProjectConfigManager
via WithRequester
, so the assertion on 316 isn't useful, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @mjc1283 for pointing out, i have added requester there.
|
||
// Send sends the notification to the registered handlers | ||
func (am *AtomicManager) Send(notification interface{}) { | ||
am.lock.Lock() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the user calls Remove
in their notification callback, does that cause deadlock?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can try a sample code, and can check.
One more question here is, if user calls |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What this is making pretty clear is that the SyncConfig method is overloaded and causes confusion. We should have distinct methods for SetConfig(datafile []byte)
and PollConfig()
. I think this will simplify the logic and avoid the branching and checking that currently going on.
configManager := NewPollingProjectConfigManager(sdkKey, WithRequester(mockRequester)) | ||
eg.Go(configManager.Start) | ||
|
||
m := sync.RWMutex{} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd be surprised if the ++
operator was not already atomic, but there is an atomic increment as part of the sync package https://gobyexample.com/atomic-counters that you should be able to use instead. Since you're just confirming that the notification was triggered, you can also use a sync.WaitGroup
and block on completion of the group. I found the WaitGroup approach to be less flaky when testing with goroutines.
} | ||
|
||
func TestNewPollingProjectConfigManagerPullImmediatelyOnStart(t *testing.T) { | ||
m := sync.RWMutex{} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar comment here about using the Mutex as opposed to other synchronization options.
type AtomicManager struct { | ||
handlers map[uint32]func(interface{}) | ||
counter uint32 | ||
lock sync.Mutex |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be a RWMutex
?
for _, handler := range am.handlers { | ||
handler(notification) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Per our group discussion, we can first create an array of handlers, outside of the map, then trigger the handlers. That way we are not potentially modifying the Map while we're iterating.
Summary
ProjectConfig
on initializationNewPollingConfigManager
Test plan
Issues
sdk-key
, should have the code to block execution untilProjectConfig
is available or registerOnProjectConfigUpdate
notification