Skip to content

Conversation

@FarhanAnjum-opti
Copy link
Contributor

@FarhanAnjum-opti FarhanAnjum-opti commented Sep 24, 2025

Summary

Decision Service methods to handle CMAB

Test plan

Added unit tests

Issues

FSSDK-11170
FSSDK-12013

…ations over CMAB service decisions in DecisionService
Copy link
Contributor

@muzahidul-opti muzahidul-opti left a comment

Choose a reason for hiding this comment

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

Changes look good to me. Added few comments.

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.

A few more suggestions at the top level.

Co-authored-by: Jae Kim <45045038+jaeopt@users.noreply.github.com>
FarhanAnjum-opti and others added 7 commits October 23, 2025 20:54
Co-authored-by: Jae Kim <45045038+jaeopt@users.noreply.github.com>
Co-authored-by: Jae Kim <45045038+jaeopt@users.noreply.github.com>
…ckage-private and add copyright notice to DecisionPath
…and OptimizelyUserContext with corresponding tests
…and enhance builder methods for cache configuration
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.

I see it's now more aligned with android-sdk. I added more comments. Let's discuss.


if (decision != null) {
decisions.add(new DecisionResponse(decision, reasons));
decisions.add(new DecisionResponse(decision, reasons, error, decision.cmabUUID));
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we have any case we need pass cmabUUID separately though it's already in decision?

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.

Bucket cleaning up looks good! A few more changes suggested.

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!
Added a few suggestions - it must be the final round :)

import java.util.regex.Pattern;

public class CmabClientHelper {
public static final String CMAB_PREDICTION_ENDPOINT = "https://prediction.cmab.optimizely.com/predict/%s";
Copy link
Contributor

Choose a reason for hiding this comment

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

remove "final" so that they can override it.
Do you allow it configurable in other way?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

end point configuration is handled separately in the CmabClientConfig. This is kept as the default one.

/**
* Creates a config with default retry settings.
*
* @return A default cmab client config
Copy link
Contributor

Choose a reason for hiding this comment

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

We can have this as default.

@Nonnull ErrorHandler errorHandler,
@Nullable UserProfileService userProfileService) {
@Nullable UserProfileService userProfileService,
@Nonnull CmabService cmabService) {
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 we need to support old constructor for backward compatibility?
DecisionService(bucketer, errorHandler, userProfileService)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As far as I know, cmabService is a mandatory field for decision service. All the other SDKs seem to have followed this.

Copy link
Contributor

Choose a reason for hiding this comment

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

java may be unique - we open it as public before, so it looks like we need to support the old API as well.

Comment on lines +1567 to +1579
Map<String, OptimizelyDecision> decisionMap = new HashMap<>();

ProjectConfig projectConfig = getProjectConfig();
if (projectConfig == null) {
logger.error("Optimizely instance is not valid, failing decideAllSync call.");
return decisionMap;
}

List<FeatureFlag> allFlags = projectConfig.getFeatureFlags();
List<String> allFlagKeys = new ArrayList<>();
for (int i = 0; i < allFlags.size(); i++) allFlagKeys.add(allFlags.get(i).getKey());

return decideForKeysSync(user, allFlagKeys, options);
Copy link
Contributor

Choose a reason for hiding this comment

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

Can't we reuse the code for decideAll - the same logic repeated 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.

Can you clarify a bit more? decideAll logic has cmab enabled while decideAllSync has cmab disabled. Are you referring to the loop and internal check only upto the return statement?

Comment on lines +1524 to +1532
ProjectConfig projectConfig = getProjectConfig();
if (projectConfig == null) {
return OptimizelyDecision.newErrorDecision(key, user, DecisionMessage.SDK_NOT_READY.reason());
}

List<OptimizelyDecideOption> allOptions = getAllOptions(options);
allOptions.remove(OptimizelyDecideOption.ENABLED_FLAGS_ONLY);

return decideForKeysSync(user, Arrays.asList(key), allOptions, true).get(key);
Copy link
Contributor

Choose a reason for hiding this comment

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

Same here - Can't we reuse the code for decide - the same logic repeated here.

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