Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 26 additions & 17 deletions client/src/main/java/io/split/client/SplitClientImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
import com.google.gson.GsonBuilder;
import io.split.client.api.Key;
import io.split.client.api.SplitResult;
import io.split.client.dtos.DecoratedImpression;
import io.split.client.dtos.EvaluationOptions;
import io.split.client.dtos.Event;
import io.split.client.dtos.*;
import io.split.client.events.EventsStorageProducer;
import io.split.client.impressions.Impression;
import io.split.client.impressions.ImpressionsManager;
Expand All @@ -14,7 +12,6 @@
import io.split.engine.evaluator.Evaluator;
import io.split.engine.evaluator.EvaluatorImp;
import io.split.engine.evaluator.Labels;
import io.split.grammar.Treatments;
import io.split.inputValidation.EventsValidator;
import io.split.inputValidation.KeyValidator;
import io.split.inputValidation.SplitNameValidator;
Expand Down Expand Up @@ -49,7 +46,6 @@
* @author adil
*/
public final class SplitClientImpl implements SplitClient {
public static final SplitResult SPLIT_RESULT_CONTROL = new SplitResult(Treatments.CONTROL, null);
private static final String CLIENT_DESTROY = "Client has already been destroyed - no calls possible";
private static final String CATCHALL_EXCEPTION = "CatchAll Exception";
private static final String MATCHING_KEY = "matchingKey";
Expand All @@ -66,6 +62,7 @@ public final class SplitClientImpl implements SplitClient {
private final TelemetryEvaluationProducer _telemetryEvaluationProducer;
private final TelemetryConfigProducer _telemetryConfigProducer;
private final FlagSetsFilter _flagSetsFilter;
private final FallbackTreatmentCalculator _fallbackTreatmentCalculator;

public SplitClientImpl(SplitFactory container,
SplitCacheConsumer splitCacheConsumer,
Expand All @@ -76,7 +73,8 @@ public SplitClientImpl(SplitFactory container,
Evaluator evaluator,
TelemetryEvaluationProducer telemetryEvaluationProducer,
TelemetryConfigProducer telemetryConfigProducer,
FlagSetsFilter flagSetsFilter) {
FlagSetsFilter flagSetsFilter,
FallbackTreatmentCalculator fallbackTreatmentCalculator) {
_container = container;
_splitCacheConsumer = checkNotNull(splitCacheConsumer);
_impressionManager = checkNotNull(impressionManager);
Expand All @@ -87,6 +85,7 @@ public SplitClientImpl(SplitFactory container,
_telemetryEvaluationProducer = checkNotNull(telemetryEvaluationProducer);
_telemetryConfigProducer = checkNotNull(telemetryConfigProducer);
_flagSetsFilter = flagSetsFilter;
_fallbackTreatmentCalculator = fallbackTreatmentCalculator;
}

@Override
Expand Down Expand Up @@ -492,31 +491,31 @@ private SplitResult getTreatmentWithConfigInternal(String matchingKey, String bu

if (_container.isDestroyed()) {
_log.error(CLIENT_DESTROY);
return SPLIT_RESULT_CONTROL;
return checkFallbackTreatment(featureFlag);
}

if (!KeyValidator.isValid(matchingKey, MATCHING_KEY, _config.maxStringLength(), methodEnum.getMethod())) {
return SPLIT_RESULT_CONTROL;
return checkFallbackTreatment(featureFlag);
}

if (!KeyValidator.bucketingKeyIsValid(bucketingKey, _config.maxStringLength(), methodEnum.getMethod())) {
return SPLIT_RESULT_CONTROL;
return checkFallbackTreatment(featureFlag);
}

Optional<String> splitNameResult = SplitNameValidator.isValid(featureFlag, methodEnum.getMethod());
if (!splitNameResult.isPresent()) {
return SPLIT_RESULT_CONTROL;
return checkFallbackTreatment(featureFlag);
}
featureFlag = splitNameResult.get();
long start = System.currentTimeMillis();

EvaluatorImp.TreatmentLabelAndChangeNumber result = _evaluator.evaluateFeature(matchingKey, bucketingKey, featureFlag, attributes);

if (result.treatment.equals(Treatments.CONTROL) && result.label.equals(Labels.DEFINITION_NOT_FOUND) && _gates.isSDKReady()) {
if (result.label != null && result.label.contains(Labels.DEFINITION_NOT_FOUND) && _gates.isSDKReady()) {
_log.warn(String.format(
"%s: you passed \"%s\" that does not exist in this environment, " +
"please double check what feature flags exist in the Split user interface.", methodEnum.getMethod(), featureFlag));
return SPLIT_RESULT_CONTROL;
return checkFallbackTreatment(featureFlag);
}

recordStats(
Expand All @@ -541,10 +540,19 @@ private SplitResult getTreatmentWithConfigInternal(String matchingKey, String bu
} catch (Exception e1) {
// ignore
}
return SPLIT_RESULT_CONTROL;
return checkFallbackTreatment(featureFlag);
}
}

private SplitResult checkFallbackTreatment(String featureName) {
FallbackTreatment fallbackTreatment = _fallbackTreatmentCalculator.resolve(featureName, "");
String config = null;
if (fallbackTreatment.getConfig() != null) {
config = fallbackTreatment.getConfig().toString();
}
return new SplitResult(fallbackTreatment.getTreatment(), config);
}

private String validateProperties(Map<String, Object> properties) {
if (properties == null){
return null;
Expand All @@ -563,6 +571,7 @@ private Map<String, SplitResult> getTreatmentsWithConfigInternal(String matching
_log.error(String.format("%s: featureFlagNames must be a non-empty array", methodEnum.getMethod()));
return new HashMap<>();
}

try {
checkSDKReady(methodEnum, featureFlagNames);
Map<String, SplitResult> result = validateBeforeEvaluate(featureFlagNames, matchingKey, methodEnum, bucketingKey);
Expand Down Expand Up @@ -623,17 +632,17 @@ private Map<String, SplitResult> getTreatmentsBySetsWithConfigInternal(String ma
return createMapControl(featureFlagNames);
}
}

private Map<String, SplitResult> processEvaluatorResult(Map<String, EvaluatorImp.TreatmentLabelAndChangeNumber> evaluatorResult,
MethodEnum methodEnum, String matchingKey, String bucketingKey, Map<String,
Object> attributes, long initTime, String properties){
List<DecoratedImpression> decoratedImpressions = new ArrayList<>();
Map<String, SplitResult> result = new HashMap<>();
evaluatorResult.keySet().forEach(t -> {
if (evaluatorResult.get(t).treatment.equals(Treatments.CONTROL) && evaluatorResult.get(t).label.
equals(Labels.DEFINITION_NOT_FOUND) && _gates.isSDKReady()) {
if (evaluatorResult.get(t).label != null && evaluatorResult.get(t).label.contains(Labels.DEFINITION_NOT_FOUND) && _gates.isSDKReady()) {
_log.warn(String.format("%s: you passed \"%s\" that does not exist in this environment please double check " +
"what feature flags exist in the Split user interface.", methodEnum.getMethod(), t));
result.put(t, SPLIT_RESULT_CONTROL);
result.put(t, checkFallbackTreatment(t));
} else {
result.put(t, new SplitResult(evaluatorResult.get(t).treatment, evaluatorResult.get(t).configurations));
decoratedImpressions.add(
Expand Down Expand Up @@ -735,7 +744,7 @@ private void checkSDKReady(MethodEnum methodEnum) {

private Map<String, SplitResult> createMapControl(List<String> featureFlags) {
Map<String, SplitResult> result = new HashMap<>();
featureFlags.forEach(s -> result.put(s, SPLIT_RESULT_CONTROL));
featureFlags.forEach(s -> result.put(s, checkFallbackTreatment(s)));
return result;
}
}
22 changes: 16 additions & 6 deletions client/src/main/java/io/split/client/SplitFactoryImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.google.common.io.Files;
import io.split.client.dtos.BearerCredentialsProvider;
import io.split.client.dtos.FallbackTreatmentCalculatorImp;
import io.split.client.dtos.Metadata;
import io.split.client.events.EventsSender;
import io.split.client.events.EventsStorage;
Expand Down Expand Up @@ -256,8 +257,9 @@ public SplitFactoryImpl(String apiToken, SplitClientConfig config) throws URISyn
_telemetrySyncTask = new TelemetrySyncTask(config.getTelemetryRefreshRate(), _telemetrySynchronizer,
config.getThreadFactory());

FallbackTreatmentCalculatorImp fallbackTreatmentCalculatorImp = new FallbackTreatmentCalculatorImp(null);
// Evaluator
_evaluator = new EvaluatorImp(splitCache, segmentCache, ruleBasedSegmentCache, null);
_evaluator = new EvaluatorImp(splitCache, segmentCache, ruleBasedSegmentCache, fallbackTreatmentCalculatorImp);

// SplitClient
_client = new SplitClientImpl(this,
Expand All @@ -269,7 +271,9 @@ public SplitFactoryImpl(String apiToken, SplitClientConfig config) throws URISyn
_evaluator,
_telemetryStorageProducer, // TelemetryEvaluation instance
_telemetryStorageProducer, // TelemetryConfiguration instance
flagSetsFilter);
flagSetsFilter,
fallbackTreatmentCalculatorImp
);

// SplitManager
_manager = new SplitManagerImpl(splitCache, config, _gates, _telemetryStorageProducer);
Expand Down Expand Up @@ -348,8 +352,9 @@ protected SplitFactoryImpl(String apiToken, SplitClientConfig config, CustomStor
_telemetrySynchronizer = new TelemetryConsumerSubmitter(customStorageWrapper, _sdkMetadata);
UserCustomRuleBasedSegmentAdapterConsumer userCustomRuleBasedSegmentAdapterConsumer =
new UserCustomRuleBasedSegmentAdapterConsumer(customStorageWrapper);
FallbackTreatmentCalculatorImp fallbackTreatmentCalculatorImp = new FallbackTreatmentCalculatorImp(null);
_evaluator = new EvaluatorImp(userCustomSplitAdapterConsumer, userCustomSegmentAdapterConsumer,
userCustomRuleBasedSegmentAdapterConsumer, null);
userCustomRuleBasedSegmentAdapterConsumer, fallbackTreatmentCalculatorImp);
_impressionsSender = PluggableImpressionSender.create(customStorageWrapper);
_uniqueKeysTracker = createUniqueKeysTracker(config);
_impressionsManager = buildImpressionsManager(config, userCustomImpressionAdapterConsumer,
Expand Down Expand Up @@ -378,7 +383,9 @@ protected SplitFactoryImpl(String apiToken, SplitClientConfig config, CustomStor
_evaluator,
_telemetryStorageProducer, // TelemetryEvaluation instance
_telemetryStorageProducer, // TelemetryConfiguration instance
flagSetsFilter);
flagSetsFilter,
fallbackTreatmentCalculatorImp
);

// SyncManager
_syncManager = new ConsumerSyncManager(synchronizer);
Expand Down Expand Up @@ -446,8 +453,9 @@ protected SplitFactoryImpl(SplitClientConfig config) {
SplitTasks splitTasks = SplitTasks.build(_splitSynchronizationTask, _segmentSynchronizationTaskImp,
_impressionsManager, null, null, null);

FallbackTreatmentCalculatorImp fallbackTreatmentCalculatorImp = new FallbackTreatmentCalculatorImp(null);
// Evaluator
_evaluator = new EvaluatorImp(splitCache, segmentCache, ruleBasedSegmentCache, null);
_evaluator = new EvaluatorImp(splitCache, segmentCache, ruleBasedSegmentCache, fallbackTreatmentCalculatorImp);

EventsStorage eventsStorage = new NoopEventsStorageImp();

Expand All @@ -461,7 +469,9 @@ protected SplitFactoryImpl(SplitClientConfig config) {
_evaluator,
_telemetryStorageProducer, // TelemetryEvaluation instance
_telemetryStorageProducer, // TelemetryConfiguration instance
flagSetsFilter);
flagSetsFilter,
fallbackTreatmentCalculatorImp
);

// Synchronizer
Synchronizer synchronizer = new LocalhostSynchronizer(splitTasks, _splitFetcher,
Expand Down
38 changes: 34 additions & 4 deletions client/src/main/java/io/split/engine/evaluator/EvaluatorImp.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,10 @@
import io.split.client.dtos.ConditionType;
import io.split.client.dtos.FallbackTreatment;
import io.split.client.dtos.FallbackTreatmentCalculator;
import io.split.client.dtos.FallbackTreatmentsConfiguration;
import io.split.client.exceptions.ChangeNumberExceptionWrapper;
import io.split.engine.experiments.ParsedCondition;
import io.split.engine.experiments.ParsedSplit;
import io.split.engine.splitter.Splitter;
import io.split.grammar.Treatments;
import io.split.storages.RuleBasedSegmentCacheConsumer;
import io.split.storages.SegmentCacheConsumer;
import io.split.storages.SplitCacheConsumer;
Expand Down Expand Up @@ -63,7 +61,27 @@ public Map<String, TreatmentLabelAndChangeNumber> evaluateFeatures(String matchi
public Map<String, EvaluatorImp.TreatmentLabelAndChangeNumber> evaluateFeaturesByFlagSets(String key, String bucketingKey,
List<String> flagSets, Map<String, Object> attributes) {
List<String> flagSetsWithNames = getFeatureFlagNamesByFlagSets(flagSets);
return evaluateFeatures(key, bucketingKey, flagSetsWithNames, attributes);
try {
return evaluateFeatures(key, bucketingKey, flagSetsWithNames, attributes);
} catch (Exception e) {
_log.error("Evaluator Exception", e);
return createMapControl(flagSetsWithNames, "exception");
}
}

private Map<String, EvaluatorImp.TreatmentLabelAndChangeNumber> createMapControl(List<String> featureFlags, String label) {
Map<String, TreatmentLabelAndChangeNumber> result = new HashMap<>();
featureFlags.forEach(s -> result.put(s, checkFallbackTreatment(s, label)));
return result;
}

private EvaluatorImp.TreatmentLabelAndChangeNumber checkFallbackTreatment(String featureName, String label) {
FallbackTreatment fallbackTreatment = _fallbackTreatmentCalculator.resolve(featureName, label);
return new EvaluatorImp.TreatmentLabelAndChangeNumber(fallbackTreatment.getTreatment(),
fallbackTreatment.getLabel(),
null,
getFallbackConfig(fallbackTreatment),
false);
}

private List<String> getFeatureFlagNamesByFlagSets(List<String> flagSets) {
Expand Down Expand Up @@ -177,13 +195,25 @@ private String getConfig(ParsedSplit parsedSplit, String returnedTreatment) {
return parsedSplit.configurations() != null ? parsedSplit.configurations().get(returnedTreatment) : null;
}

private String getFallbackConfig(FallbackTreatment fallbackTreatment) {
if (fallbackTreatment.getConfig() != null) {
return fallbackTreatment.getConfig().toString();
}

return null;
}

private TreatmentLabelAndChangeNumber evaluateParsedSplit(String matchingKey, String bucketingKey, Map<String, Object> attributes,
ParsedSplit parsedSplit, String featureName) {
try {

if (parsedSplit == null) {
FallbackTreatment fallbackTreatment = _fallbackTreatmentCalculator.resolve(featureName, Labels.DEFINITION_NOT_FOUND);
return new TreatmentLabelAndChangeNumber(fallbackTreatment.getTreatment(), fallbackTreatment.getLabel());
return new TreatmentLabelAndChangeNumber(fallbackTreatment.getTreatment(),
fallbackTreatment.getLabel(),
null,
getFallbackConfig(fallbackTreatment),
true);
}
return getTreatment(matchingKey, bucketingKey, parsedSplit, attributes);
} catch (ChangeNumberExceptionWrapper e) {
Expand Down
Loading