-
Notifications
You must be signed in to change notification settings - Fork 20
feat: Integrated ODPManager with UserContext and Optimizely client #323
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
feat: Integrated ODPManager with UserContext and Optimizely client #323
Conversation
Includes lint/format updates...Sorry PR-Reviewer :-/
Sorry for the linter formatting updates
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.
Overall it looks good. See my first-round comments. Key changes suggested -
- a logic to extract segments from audiences is missing. This is a key to ODP integration.
- a fix for async fetchQualifiedSegments.
OptimizelySDK/Optimizely.cs
Outdated
WithLogger(Logger). | ||
WithErrorHandler(ErrorHandler). | ||
Build(!SdkSettings.DisableOdp); | ||
OdpManager.EventManager.Start(); |
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 see "eventManager.start()" inside OdpManagher.Build()", which looks good. Do we need it here again?
@@ -373,6 +408,7 @@ private void Initialize() | |||
var integration = Integrations.FirstOrDefault(i => i.Key.ToLower() == "odp"); | |||
HostForOdp = integration?.Host; | |||
PublicKeyForOdp = integration?.PublicKey; | |||
Segments = TypedAudiences.Select(a => a.Name).ToArray(); |
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 is not correct to get all segments from audiences. This is critical for ODP integration.
You can check with other SDKs and need more testing for this.
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.
Looking 👀 into this....
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'm still working on how to parse odp.
typed audiences based on other sdk work.
Can you review your other notes to see if they're ok before you go on holiday?
OptimizelySDK/Optimizely.cs
Outdated
var optimizelyConfig = | ||
new OptimizelyConfigService(config).GetOptimizelyConfig(); | ||
var allSegments = optimizelyConfig.Audiences.Select(a => a.Name).ToList(); |
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.
You already have "Segments" in DatafileProjectConfig. Can't we use it directly.
OptimizelySDK/Optimizely.cs
Outdated
/// <param name="userId">FS User ID</param> | ||
/// <param name="segmentOptions">Options used during segment cache handling</param> | ||
/// <returns>Qualified segments for the user from the cache or the ODP server</returns> | ||
public string[] FetchQualifiedSegments(string userId, List<OdpSegmentOption> segmentOptions) |
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 should not be public. It'll be called from OptimizelyUserContext only. "internal"?
OptimizelySDK/Optimizely.cs
Outdated
/// Send identification event to Optimizely Data Platform | ||
/// </summary> | ||
/// <param name="userId">FS User ID to send</param> | ||
public void IdentifyUser(string userId) |
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 should not be public. It'll be called from OptimizelyUserContext only. "internal"?
OptimizelySDK/Optimizely.cs
Outdated
if (OdpManager == null) | ||
{ | ||
Logger.Log(LogLevel.ERROR, Constants.ODP_NOT_ENABLED_MESSAGE); | ||
return; | ||
} |
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.
Why don't we have this guard for "fetchQualifiedSegments" and "identifyUser" above?
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.
Oops, I meant to remove this guard here in SendOdpEvent
too. Instantiating OdpManager
should be guaranteed via InitializeComponents
call be constructor.
Should add the guards back, just in case things change? What's your thought?
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.
No need for guard here if it's guaranteed non-null.
List<OdpSegmentOption> segmentOptions = null | ||
) | ||
{ | ||
var segments = Optimizely.FetchQualifiedSegments(userId, |
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 should be non-blocking if callback is provided (async API).
We can consider splitting the API into 2 (sync and async).
- bool FetchQualifiedSegments(userId, options)
- void FetchQaulifiedSegments(userId, options, callback)
hopefully ;-)
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.
Changes look good! One more suggestion to consider for compatibility support.
|
||
private HttpProjectConfigManager(TimeSpan period, string url, TimeSpan blockingTimeout, | ||
bool autoUpdate, ILogger logger, IErrorHandler errorHandler, string sdkKey | ||
bool autoUpdate, ILogger logger, IErrorHandler errorHandler, string sdkKey = null |
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 default null sdkKey parameter will make existing clients compile ok but it'll fail to run because of missing sdkKey for ODP notification.
What about removing the default null value (breaking changes note in release), so they are all forced to change to use ODP?
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.
Can we also keep the list of all breaking changes, so we won't miss them in the release note?
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.
Great concept. Are we planning to release ATS as a v4.0 or v3.12? For breaking changes, I'd like to go 4.0 with @trishahanlon 's documentation to back up the reasoning.
This default null sdkKey parameter will make existing clients compile ok...
If we're planning to release ODP as a minor semantic version, I'd like to keep the default. I guess this is a point of internal clarification in standup maybe.
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.
It looks like we have a few breaking changes (new interface methods and new sdkKey constructor param) so we have to bump a major version to 4.0.
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.
@jaeopt Thanks for the guidance. I hope this looks better now.
/// <summary> | ||
/// SDK key in use for this project | ||
/// </summary> | ||
string SdkKey { get; } |
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.
@mikechu-optimizely in addition to doc update, we should list all these breaking changes in release note.
Still holding for @msohailhussain 's approval (maybe if he's time). @mnoman09 I'll hold for your merge and Approval too. |
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.
LGTM
@msohailhussain can you double check if you see any concerns about compatibility?
* Some suggested changes to fix null pointer exception * - Removed batchsize support from ODP event manager - Made some general fixes * Flush previous event * reverting this change Co-authored-by: mnoman09 <m.nomanshoaib09@gmail.com>
@msohailhussain @mnoman09 It looks like some FSC tests are erroring for this branch. Shall I start investigating the test app? |
I can look at the testapp. Most of these tests are failing because we haven't merged the testapp PR: 79. Once we merge that PR FSC should pass. |
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.
Overall, these changes lgtm.
Great. Thank you. |
Is there something I can be helping with for getting FSC/test-app scenarios corrected? |
I will do by tomorrow. |
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.
have few more comments. please address.
[TestFixtureSetUp] | ||
public void Setup() | ||
{ | ||
_qualifiedMatchCondition = new BaseCondition |
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.
not addressed.
@@ -67,7 +67,7 @@ public void ShouldSaveAndLookupMultipleItems() | |||
cache.Save("user2", _segments3And4); | |||
cache.Save("user3", _segments5And6); | |||
|
|||
var cacheKeys = cache._readCurrentCacheKeys(); | |||
var cacheKeys = cache.CurrentCacheKeysForTesting(); |
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.
Please use reflection to get private properties.
@@ -151,6 +153,9 @@ | |||
</ProjectReference> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<None Include="..\keypair.snk"> |
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.
why this added?
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 allows for signing the Test project so InternalsVisibleTo would work when testing runs in GitHub Actions.
private string _sdkKey = string.Empty; | ||
|
||
private HttpProjectConfigManager(TimeSpan period, string url, TimeSpan blockingTimeout, | ||
bool autoUpdate, ILogger logger, IErrorHandler errorHandler, string sdkKey |
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.
constructor is private, not a breaking change.
I'm starting to understand FSC and the C# testapp. Working to figure out failing tests... |
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. lgtm
Thanks for the approval. FSC and the test app are my last blocker |
* Refactored OdpEventManager flushEvent function. * To wait for events using flushInterval when eventBatch is not empty. * Or wait indefinitely if no event is in batch until any event arrive. * Avoid calling flush on shutdown if no events are present * Avoid calling unnecessary flushQueue if _currentBatch.Count is zero. * Fixed the test as when there are no remaining items in queue then odpEventManager should not flush. * Removing mutex lock from notification registry instead using concurrentDictionary * Revert "Removing mutex lock from notification registry instead using concurrentDictionary" This reverts commit 64cdf80. * Added Thread.sleep which somehow enabling thread to shutdown gracefully. --------- Co-authored-by: mnoman09 <m.nomanshoaib09@gmail.com>
OMG @msohailhussain and @mnoman09 You guys are the best. Valuable lesson for me is to keep PR's much smaller. I'll start working on the full-repo linting. Thanks again, you guys. |
Summary
This PR integrates ODP functionality with UserContext and Optimizely client to make it available for users. There are two ways to integrate ODPManager.
😬 Sorry about the numerous auto-format changes polluting the core enhancements. Need to satisfy the linter.
Test plan
Issues
FSSDK-8476