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

…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 :)


// If no cmabService provided, create default one
if (cmabService == null) {
DefaultCmabClient defaultCmabClient = new DefaultCmabClient(CmabClientConfig.withDefaultRetry());
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 change the DefaultCmabClient to use defaultRetry by default, so we can use simpler

Suggested change
DefaultCmabClient defaultCmabClient = new DefaultCmabClient(CmabClientConfig.withDefaultRetry());
DefaultCmabClient defaultCmabClient = new DefaultCmabClient();

@@ -0,0 +1,32 @@
/**
* Copyright 2024, Optimizely and contributors
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
* Copyright 2024, Optimizely and contributors
* Copyright 2025, Optimizely and contributors

// This mirrors how the sync methods handle errors
return OptimizelyDecision.newErrorDecision(key, userContext, "Async decision error: " + errorMessage);
}
} No newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

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

I see this "no-new-line-at-the-end" in several places. Can we clean them up?

}

/**
* Creates a default RetryConfig with 3 retries and exponential backoff.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
* Creates a default RetryConfig with 3 retries and exponential backoff.
* Creates a default RetryConfig with 1 retry and exponential backoff.

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?

/**
* 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)

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.

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