Introducing phonenumber stickiness, phone number segment strategy
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package com.navi.medici.client;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import okhttp3.ConnectionPool;
|
||||
import okhttp3.OkHttpClient;
|
||||
|
||||
public class OkHttpClientContainer {
|
||||
@@ -18,6 +19,7 @@ public class OkHttpClientContainer {
|
||||
.readTimeout(1, TimeUnit.SECONDS)
|
||||
.callTimeout(1, TimeUnit.SECONDS)
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.connectionPool(new ConnectionPool(20, 1, TimeUnit.MINUTES))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,10 +17,12 @@ import lombok.extern.log4j.Log4j2;
|
||||
@Log4j2
|
||||
public class EventDispatcher {
|
||||
private final ClickStreamClient clickStreamClient;
|
||||
private final LitmusConfig litmusConfig;
|
||||
|
||||
public EventDispatcher(LitmusConfig litmusConfig) {
|
||||
this.clickStreamClient = new ClickStreamClient(litmusConfig.getClickStreamAPI(), litmusConfig.getAppName(),
|
||||
litmusConfig.getVertical(), litmusConfig.getMeterRegistry());
|
||||
this.litmusConfig = litmusConfig;
|
||||
}
|
||||
|
||||
public void publish(LitmusContext litmusContext, LitmusExperiment litmusExperiment, Boolean result, Variant variant) {
|
||||
@@ -37,6 +39,8 @@ public class EventDispatcher {
|
||||
.experimentName(litmusExperiment.getName())
|
||||
.variant(variantName)
|
||||
.result(result)
|
||||
.appName(litmusConfig.getAppName())
|
||||
.vertical(litmusConfig.getVertical())
|
||||
.build();
|
||||
|
||||
var event = ClickStreamEvent.<LitmusExperimentEvent>builder()
|
||||
@@ -57,4 +61,5 @@ public class EventDispatcher {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import com.navi.medici.request.v1.LitmusExperiment;
|
||||
import com.navi.medici.strategy.DefaultStrategy;
|
||||
import com.navi.medici.strategy.DeviceWithIdStrategy;
|
||||
import com.navi.medici.strategy.FlexibleRolloutStrategy;
|
||||
import com.navi.medici.strategy.PhoneNumberStrategy;
|
||||
import com.navi.medici.strategy.Strategy;
|
||||
import com.navi.medici.strategy.UnknownStrategy;
|
||||
import com.navi.medici.strategy.UserWithIdStrategy;
|
||||
@@ -35,8 +36,6 @@ import lombok.extern.log4j.Log4j2;
|
||||
|
||||
@Log4j2
|
||||
public class DefaultLitmus implements Litmus {
|
||||
|
||||
|
||||
public static final Variant DISABLED_VARIANT = new Variant("disabled", null, false, null);
|
||||
|
||||
|
||||
@@ -178,6 +177,9 @@ public class DefaultLitmus implements Litmus {
|
||||
new DeviceWithIdStrategy(new HttpExperimentFetcher(litmusConfig.getLitmusURLs(), litmusConfig.getAppName(), litmusConfig.getNamePrefix(),
|
||||
litmusConfig.getProjectName(), litmusConfig.getVertical(), litmusConfig.getMeterRegistry())),
|
||||
|
||||
new PhoneNumberStrategy(new HttpExperimentFetcher(litmusConfig.getLitmusURLs(), litmusConfig.getAppName(), litmusConfig.getNamePrefix(),
|
||||
litmusConfig.getProjectName(), litmusConfig.getVertical(), litmusConfig.getMeterRegistry())),
|
||||
|
||||
new FlexibleRolloutStrategy());
|
||||
|
||||
BUILTIN_STRATEGIES.forEach(strategy -> map.put(strategy.getName(), strategy));
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.navi.medici.strategy;
|
||||
|
||||
import static com.navi.medici.strategy.FlexibleRolloutStrategy.GROUP_ID;
|
||||
import static com.navi.medici.strategy.FlexibleRolloutStrategy.PERCENTAGE;
|
||||
|
||||
import com.navi.medici.client.HttpExperimentFetcher;
|
||||
import com.navi.medici.context.LitmusContext;
|
||||
import com.navi.medici.util.StrategyUtils;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
public class PhoneNumberStrategy implements Strategy {
|
||||
|
||||
private static final String SEGMENT = "segment";
|
||||
private static final String STRATEGY_NAME = "phoneNumber";
|
||||
|
||||
private final HttpExperimentFetcher experimentFetcher;
|
||||
|
||||
public PhoneNumberStrategy(HttpExperimentFetcher experimentFetcher) {
|
||||
this.experimentFetcher = experimentFetcher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return STRATEGY_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(Map<String, String> parameters) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(Map<String, String> parameters, LitmusContext litmusContext) {
|
||||
if (StringUtils.isBlank(parameters.get(PERCENTAGE))) {
|
||||
return phoneNumberSegmentCheck(parameters, litmusContext);
|
||||
} else {
|
||||
return segmentCheckWithRollout(parameters, litmusContext);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean phoneNumberSegmentCheck(Map<String, String> parameters, LitmusContext litmusContext) {
|
||||
var userId = litmusContext.getUserId().orElse(null);
|
||||
var segmentName = parameters.get(SEGMENT);
|
||||
var result = experimentFetcher.segmentIdExists(segmentName, userId);
|
||||
|
||||
return result.getData() != null && (Boolean) result.getData();
|
||||
}
|
||||
|
||||
private boolean segmentCheckWithRollout(Map<String, String> parameters, LitmusContext litmusContext) {
|
||||
var userId = litmusContext.getUserId().orElse(null);
|
||||
var percentage = StrategyUtils.getPercentage(parameters.get(PERCENTAGE));
|
||||
var groupId = parameters.getOrDefault(GROUP_ID, "");
|
||||
|
||||
var norm = StrategyUtils.getNormalizedNumber(userId, groupId);
|
||||
|
||||
return Optional.of(phoneNumberSegmentCheck(parameters, litmusContext))
|
||||
.map(r -> r && percentage > 0 && norm <= percentage)
|
||||
.orElse(false);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -43,11 +43,9 @@ public class StrategyUtils {
|
||||
|
||||
public static int getPercentage(String percentage) {
|
||||
if (isNotEmpty(percentage) && isNumeric(percentage)) {
|
||||
int p = Integer.parseInt(percentage);
|
||||
return p;
|
||||
} else {
|
||||
return 0;
|
||||
return Integer.parseInt(percentage);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static Optional<String> resolveStickiness(String stickiness, LitmusContext context) {
|
||||
@@ -59,6 +57,8 @@ public class StrategyUtils {
|
||||
return context.getSessionId();
|
||||
case "deviceId":
|
||||
return context.getDeviceId();
|
||||
case "phoneNumber":
|
||||
return context.getPhoneNumber();
|
||||
case "appVersionCode":
|
||||
return context.getAppVersionCode();
|
||||
case "osType":
|
||||
|
||||
@@ -38,6 +38,9 @@ public final class VariantUtil {
|
||||
case "deviceId":
|
||||
contextValue = context.getDeviceId();
|
||||
break;
|
||||
case "phoneNumber":
|
||||
contextValue = context.getPhoneNumber();
|
||||
break;
|
||||
default:
|
||||
contextValue = Optional.ofNullable(context.getProperties().get(override.getContextName()));
|
||||
}
|
||||
|
||||
@@ -22,4 +22,8 @@ public class LitmusExperimentEvent {
|
||||
Boolean result;
|
||||
|
||||
String variant;
|
||||
|
||||
String appName;
|
||||
|
||||
String vertical;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ public class LitmusContext {
|
||||
Optional<String> appVersionCode;
|
||||
Optional<String> osType;
|
||||
Optional<String> deviceId;
|
||||
|
||||
Optional<String> phoneNumber;
|
||||
Map<String, String> properties;
|
||||
Optional<String> clickStreamPayload;
|
||||
|
||||
@@ -51,6 +53,8 @@ public class LitmusContext {
|
||||
return osType;
|
||||
case "deviceId":
|
||||
return deviceId;
|
||||
case "phoneNumber":
|
||||
return phoneNumber;
|
||||
default:
|
||||
return Optional.ofNullable(properties.get(contextName));
|
||||
}
|
||||
@@ -62,23 +66,17 @@ public class LitmusContext {
|
||||
|
||||
public static class Builder {
|
||||
|
||||
@Nullable
|
||||
private String appName;
|
||||
@Nullable
|
||||
private String environment;
|
||||
@Nullable
|
||||
private String userId;
|
||||
@Nullable
|
||||
private String sessionId;
|
||||
@Nullable
|
||||
private String remoteAddress;
|
||||
@Nullable
|
||||
private String appVersionCode;
|
||||
@Nullable
|
||||
private String osType;
|
||||
@Nullable
|
||||
private String deviceId;
|
||||
@Nullable
|
||||
|
||||
private String phoneNumber;
|
||||
|
||||
private String clickStreamPayload;
|
||||
|
||||
private final Map<String, String> properties = new HashMap<>();
|
||||
@@ -95,6 +93,7 @@ public class LitmusContext {
|
||||
context.appVersionCode.ifPresent(val -> this.appVersionCode = val);
|
||||
context.osType.ifPresent(val -> this.osType = val);
|
||||
context.deviceId.ifPresent(val -> this.deviceId = val);
|
||||
context.phoneNumber.ifPresent(val -> this.phoneNumber = val);
|
||||
context.clickStreamPayload.ifPresent(val -> this.clickStreamPayload = val);
|
||||
this.properties.putAll(context.properties);
|
||||
}
|
||||
@@ -139,6 +138,11 @@ public class LitmusContext {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder phoneNumber(String phoneNumber) {
|
||||
this.phoneNumber = phoneNumber;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder addProperty(String name, String value) {
|
||||
properties.put(name, value);
|
||||
return this;
|
||||
@@ -153,7 +157,8 @@ public class LitmusContext {
|
||||
return new LitmusContext(
|
||||
Optional.ofNullable(environment), Optional.ofNullable(appName), Optional.ofNullable(userId),
|
||||
Optional.ofNullable(sessionId), Optional.ofNullable(remoteAddress), Optional.ofNullable(appVersionCode),
|
||||
Optional.ofNullable(osType), Optional.ofNullable(deviceId), properties, Optional.ofNullable(clickStreamPayload));
|
||||
Optional.ofNullable(osType), Optional.ofNullable(deviceId), Optional.ofNullable(phoneNumber), properties,
|
||||
Optional.ofNullable(clickStreamPayload));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user