Skip to content
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

Fix: Added notificationRegistry to make sure that odpSettings updates #501

Merged
merged 20 commits into from
Jan 26, 2023

Conversation

mnoman09
Copy link
Contributor

@mnoman09 mnoman09 commented Jan 11, 2023

Summary

  • NotificationRegistry is added to create default NotificationCenter for internal use for updating ODPConfigSetting.
  • This is to handle a corner case that if in any case user passes different notificationCenter to Optimizely and ProjectconfigManager then the Notification of UpdateProjectConfig will not trigger because its handler is getting added in the main NotificationCenter object.
  • This will make sure UpdateProjectConfig will update ODPConfigSetting everytime irrespective of different NotificationCenter passed by user.
  • Added getCachedConfig method in ProjectconfigManager to return ProjectConfig without await.

NOTE: breaking change
Anyone who is implementing custom ProjectConfigManager should now have to implement getCachedConfig and getSdkKey .

Test plan

  • Added additional unit test to test NotificationRegistry
  • All tests should pass.

Issue

FSSDK-8769

Copy link
Contributor

@jaeopt jaeopt left a comment

Choose a reason for hiding this comment

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

Looks good. Some changes suggested.

@@ -127,7 +128,12 @@ private Optimizely(@Nonnull EventHandler eventHandler,
if (getProjectConfig() != null) {
updateODPSettings();
}
addUpdateConfigNotificationHandler(configNotification -> { updateODPSettings(); });
if (projectConfigManager != null) {
NotificationRegistry.getNotificationCenter(projectConfigManager.getSDKKey()).
Copy link
Contributor

Choose a reason for hiding this comment

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

This can be confusing with with public NotificationCenter. What about changing names to
NotificationRegistry.getInternalNotificationCenter or some other names to avoid confusion?
@msohailhussain What do you think?

@@ -23,5 +23,7 @@ public interface ProjectConfigManager {
* @return ProjectConfig
*/
ProjectConfig getConfig();

String getSDKKey();
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we get sdkKey via getConfig().getSDKKey() instead of adding the new inferface?
This will be convenient but we want to avoid any breaking changes with this new method here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

see this comment. It will make sure that even when the config is not fetched, notificationCenter will contain the handler, which updates the ODPConfig.

Copy link
Contributor

Choose a reason for hiding this comment

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

@mnoman09 Got it! Can we add a default implementation of this method (returning null), so no changes required for existing implementations. They'll all share the same internal notificationCenter for "null" sdkKey (until they fix it), which looks safe to me.
I believe the default interface method is supported in Java8 and also supported in android.

@@ -73,11 +74,13 @@ private HttpProjectConfigManager(long period,
String datafileAccessToken,
long blockingTimeoutPeriod,
TimeUnit blockingTimeoutUnit,
NotificationCenter notificationCenter) {
NotificationCenter notificationCenter,
String sdkKey) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we also avoid this change as well if we can get sdkKey via ProjectConfig?

Copy link
Contributor Author

@mnoman09 mnoman09 Jan 12, 2023

Choose a reason for hiding this comment

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

Same as above. We need to have sdkKey pass in here, to make sure that the when we call getSDKKey on projectConfigManager then we won't get it null in case if it is http config Manager.

@@ -127,7 +128,12 @@ private Optimizely(@Nonnull EventHandler eventHandler,
if (getProjectConfig() != null) {
updateODPSettings();
}
addUpdateConfigNotificationHandler(configNotification -> { updateODPSettings(); });
if (projectConfigManager != null) {
NotificationRegistry.getNotificationCenter(projectConfigManager.getSDKKey()).
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jaeopt we are getting sdkKey from projectConfigManager instead of getProjectConfig() because of Asynchronous call of httpConfigManager it might not able to add this NotificationHandler when projectConfig is not fetched.

@mnoman09 mnoman09 requested a review from jaeopt January 12, 2023 11:27
@mnoman09 mnoman09 removed their assignment Jan 12, 2023
Copy link
Contributor

@jaeopt jaeopt left a comment

Choose a reason for hiding this comment

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

All changes look great. A couple of more changes suggested.

@@ -153,6 +159,7 @@ public void close() {
tryClose(eventProcessor);
tryClose(eventHandler);
tryClose(projectConfigManager);
NotificationRegistry.clearNotificationCenterRegistry();
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this safe to clear all notificationCenters? We can clear one for the current sdkKey. @msohailhussain also shared concern about memory leak when we close a notificationCenter, which may be addressed together when we clean it up.

@@ -127,7 +128,12 @@ private Optimizely(@Nonnull EventHandler eventHandler,
if (getProjectConfig() != null) {
Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like my previous comment on this line got lost :)
We discussed this blocking "getProjectConfig" while constructing Optimizely is not desirable, so we need to make it return null if not available. @msohailhussain may have a good idea on how to fix it.

Copy link
Contributor

@jaeopt jaeopt left a comment

Choose a reason for hiding this comment

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

We may need one more change. See my comments.

@@ -124,10 +125,15 @@ private Optimizely(@Nonnull EventHandler eventHandler,

if (odpManager != null) {
odpManager.getEventManager().start();
if (getProjectConfig() != null) {
if (!(projectConfigManager instanceof PollingProjectConfigManager)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

PollingProjectConfigManager can also have a preset projectConfig from a fallback datafile. In that case, we have to call updateODPSettings for the projectConfig immediately (we may not get notification later if the fallback is updated already).
I think we can keep the getProjectConfig() != null condition as before, with the change that `getProjectConfig() returns null immediately if config is not available.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

getProjectConfig() != null condition is not possible without wait, with our current implementation. However, we can use the similar approach as we are using in Csharp, adding additional function of getCachedConfig() in ProjectConfigManager. Now the only concern I have, related to this approach, is that do we want to enforce its implementation or return null by default as we are doing for getSDKKey() function?
In my opinion we should enforce it because if anyone uses custom ProjectConfigManager without giving getCachedConfig implementation then they won't be able use ODP as it only gets config using this new function.

Copy link
Contributor

Choose a reason for hiding this comment

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

@mnoman09 Agreed. Let's make them (getSdkKey and getCachedConfig) mandatory changes and keep them in the list of breaking changes for release.

@mnoman09 mnoman09 removed their assignment Jan 18, 2023
Copy link
Contributor

@jaeopt jaeopt left a comment

Choose a reason for hiding this comment

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

All changes look good to me!
A couple of small changes suggested - clarifications about required changes for existing custom configMangers. Android-sdk is one of them with tricky changes required.

@jaeopt
Copy link
Contributor

jaeopt commented Jan 19, 2023

@mnoman09 It'll be great if we can have a note about these breaking changes so we do not miss them when releasing a major rev.
We can use the "Unreleased" header in CHANGELOG.md like csharp-sdk - https://github.com/optimizely/csharp-sdk/blob/master/CHANGELOG.md

@mnoman09 mnoman09 removed their assignment Jan 25, 2023
@mnoman09 mnoman09 requested a review from jaeopt January 25, 2023 10:54
Copy link
Contributor

@jaeopt jaeopt left a comment

Choose a reason for hiding this comment

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

LGTM - See a couple of small changes to clean up.

Comment on lines 368 to 369
sdkKey);

httpProjectManager.setSdkKey(sdkKey);
Copy link
Contributor

Choose a reason for hiding this comment

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

Isn't this seSdkKey is redundant? I see `sdkKey' parameter to the constructor (line 368).

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 will ensure that to trigger notification user provided sdkKey will always be prioritized, instead of what is available in ProjectConfig. This allows registry to always trigger notification even if the SDKKey is changed in the Projectconfig.

Copy link
Contributor

Choose a reason for hiding this comment

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

@mnoman09 If we need this extra description for proper initializing sdkKey, this may be a source of issues. If you have to call setSdkKey() for proper overriding, can we remove sdkKey from constructor?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I already removed it from the HttpProjectConfigManager constructor if that is what you are asking?

Copy link
Contributor

Choose a reason for hiding this comment

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

@mnoman09 looks good!

…hat to trigger the notification always user provided sdkKey will be prioritized
Copy link
Contributor

@jaeopt jaeopt left a comment

Choose a reason for hiding this comment

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

LGTM

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.

5 participants