- 
                Notifications
    You must be signed in to change notification settings 
- Fork 20
[FSSDK-11177] Decision Service CMAB + Optimizely Client + Impression event adjustment #394
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
base: master
Are you sure you want to change the base?
[FSSDK-11177] Decision Service CMAB + Optimizely Client + Impression event adjustment #394
Conversation
        
          
                OptimizelySDK/Bucketing/Bucketer.cs
              
                Outdated
          
        
      | /// <param name="userId">User identifier</param> | ||
| /// <param name="trafficAllocations">Traffic allocations to use for bucketing</param> | ||
| /// <returns>Entity ID (string) if user is bucketed, null otherwise</returns> | ||
| public virtual Result<string> BucketToEntityId(ProjectConfig config, Experiment experiment, | 
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.
We can accept ExperimentCore parameter, and reuse the part upto BucketToEntityId for the Bucket metheod below. Logic for bucket would be:
- get entityId by calling BucketToEntityId()
- get the variation from the config and return using the entityId from step 1
|  | ||
| if (config.CustomCache != null) | ||
| { | ||
| _cmabCache = config.CustomCache as LruCache<CmabCacheEntry>; | 
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.
we should not assume that customCache must be LruCache. It could be any implementation
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.
the class field _cmabCache should also be of type ICache<>, not LruCache
| /// <param name="cmabConfig">Configuration for CMAB cache. If null, default values are used.</param> | ||
| /// <param name="cmabClient">Client for fetching decisions from the CMAB prediction service. If null, a default client is created.</param> | ||
| /// <param name="logger">Optional logger for recording service operations.</param> | ||
| public DefaultCmabService(CmabConfig cmabConfig = 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.
instead of taking in the config here, we can take in a ICache<> here and push the resposibility of supplying the cache to the caller, similar to cmabClient
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 all of them can be null. We can just make them required and put the construction responsibility to the caller
| void Save(string key, T value); | ||
| T Lookup(string key); | ||
| void Reset(); | ||
| void Remove(string key); | 
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 a breaking change. We cannot just add the remove method to the old Odp ICache interface. We need a new interface that has the same methods with the remove method added. We can extend this ICache like so
interface ICacheWithRemove extends ICache.
Also, it would be better to put the new extended interface in a separate common package instead of the odp package
| /// <summary> | ||
| /// CMAB UUID associated with the decision for contextual multi-armed bandit experiments. | ||
| /// </summary> | ||
| public string CmabUuid { get; set; } | 
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.
THe CmabUuid should not be in the DecisionReasons class
| var userId = user.GetUserId(); | ||
|  | ||
| // Check if CMAB is properly configured | ||
| if (experiment.Cmab == 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.
can we get rid of this check, the caller can ensure this this is called only with cmab (in our case, it is done already)
| new TrafficAllocation | ||
| { | ||
| EntityId = "$", | ||
| EndOfRange = experiment.Cmab.TrafficAllocation ?? 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.
can we just use experiment.Cmab.TrafficAllocation (without the ??)
| } | ||
|  | ||
| // User is in CMAB traffic allocation, fetch decision from CMAB service | ||
| if (CmabService == 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.
when the sdk is released with cmab, the cmabService must be non null cause we are instantiating it ourself, so no reason for it to be null. We can remove this check
| NotificationCenter = notificationCenter ?? new NotificationCenter(Logger); | ||
|  | ||
| #if USE_CMAB | ||
| if (cmabService == 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.
We will always need a cmabService. We can remove this check and just construct a cmab service
| cache = new LruCache<CmabCacheEntry>(cacheSize, cacheTtl, Logger); | ||
| } | ||
|  | ||
| var cmabRetryConfig = new CmabRetryConfig(1, TimeSpan.FromMilliseconds(100)); | 
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 define these constants (1, 100) instead of hardcoding here
| reasonsToReport); | ||
| reasonsToReport | ||
| #if USE_CMAB | ||
| , flagDecision.CmabUuid | 
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.
the publicly returned value from decide() should not have the cmabUuid, it's just an internal detail. THe OptimizelyDecision type should not change
| /// <summary> | ||
| /// CMAB UUID associated with the decision for contextual multi-armed bandit experiments. | ||
| /// </summary> | ||
| public string CmabUuid { get; private set; } | 
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 that this is the public return value for decide(). We should not add the cmabUuid here, it's only for internal purposes
| /// </summary> | ||
| /// <param name="cacheSize">Maximum number of entries in the CMAB cache.</param> | ||
| /// <param name="cacheTtl">Time-to-live for CMAB cache entries.</param> | ||
| public static void SetCmabCacheConfig(int cacheSize, TimeSpan cacheTtl) | 
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 change to SetCmabConfig instead?
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.
instead of passing each cmab config option separately as the method parameter, we can have a single method that takes a single CmabConfig parameter. This publicly exposed CmabConfig should be in this same package/namespace.
Summary
Test Plan
Issues