reverting litmus client to java 11
Signed-off-by: chandresh pancholi <chandresh.pancholi@navi.com>
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -28,4 +28,6 @@ litmus-proxy/target
|
|||||||
litmus-util/litmus-util.iml
|
litmus-util/litmus-util.iml
|
||||||
litmus-util/target
|
litmus-util/target
|
||||||
|
|
||||||
target
|
target
|
||||||
|
log
|
||||||
|
.descriptions.json
|
||||||
|
|||||||
@@ -33,17 +33,25 @@ public class FlexibleRolloutStrategy implements Strategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Optional<String> resolveStickiness(String stickiness, LitmusContext context) {
|
private Optional<String> resolveStickiness(String stickiness, LitmusContext context) {
|
||||||
return switch (stickiness) {
|
switch (stickiness) {
|
||||||
case "userId" -> context.getUserId();
|
case "userId":
|
||||||
case "sessionId" -> context.getSessionId();
|
return context.getUserId();
|
||||||
case "deviceId" -> context.getDeviceId();
|
case "sessionId":
|
||||||
case "appVersionCode" -> context.getAppVersionCode();
|
return context.getSessionId();
|
||||||
case "osType" -> context.getOsType();
|
case "deviceId":
|
||||||
case "random" -> Optional.of(randomGenerator.get());
|
return context.getDeviceId();
|
||||||
case "default" -> Optional.of(context.getUserId()
|
case "appVersionCode":
|
||||||
.orElse(context.getSessionId().orElse(this.randomGenerator.get())));
|
return context.getAppVersionCode();
|
||||||
default -> context.getByName(stickiness);
|
case "osType":
|
||||||
};
|
return context.getOsType();
|
||||||
|
case "random":
|
||||||
|
return Optional.of(randomGenerator.get());
|
||||||
|
case "default":
|
||||||
|
return Optional.of(context.getUserId()
|
||||||
|
.orElse(context.getSessionId().orElse(this.randomGenerator.get())));
|
||||||
|
default:
|
||||||
|
return context.getByName(stickiness);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -12,104 +12,119 @@ import java.util.function.Predicate;
|
|||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
public final class VariantUtil {
|
public final class VariantUtil {
|
||||||
private VariantUtil() {}
|
|
||||||
|
|
||||||
private static Predicate<VariantOverride> overrideMatchesContext(LitmusContext context) {
|
private VariantUtil() {
|
||||||
return (override) -> {
|
}
|
||||||
Optional<String> contextValue;
|
|
||||||
switch (override.getContextName()) {
|
|
||||||
case "userId" -> contextValue = context.getUserId();
|
|
||||||
case "sessionId" -> contextValue = context.getSessionId();
|
|
||||||
case "remoteAddress" -> contextValue = context.getRemoteAddress();
|
|
||||||
case "appVersionCode" -> contextValue = context.getAppVersionCode();
|
|
||||||
case "osType" -> contextValue = context.getOsType();
|
|
||||||
case "deviceId" -> contextValue = context.getDeviceId();
|
|
||||||
default -> contextValue = Optional.ofNullable(context.getProperties().get(override.getContextName()));
|
|
||||||
}
|
|
||||||
return override.getValues().contains(contextValue.orElse(""));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Optional<VariantDefinition> getOverride(
|
private static Predicate<VariantOverride> overrideMatchesContext(LitmusContext context) {
|
||||||
List<VariantDefinition> variants, LitmusContext context) {
|
return (override) -> {
|
||||||
return variants.stream()
|
Optional<String> contextValue;
|
||||||
.filter(
|
switch (override.getContextName()) {
|
||||||
variant ->
|
case "userId":
|
||||||
variant.getOverrides().stream()
|
contextValue = context.getUserId();
|
||||||
.anyMatch(overrideMatchesContext(context)))
|
break;
|
||||||
.findFirst();
|
case "sessionId":
|
||||||
}
|
contextValue = context.getSessionId();
|
||||||
|
break;
|
||||||
private static String getIdentifier(LitmusContext context) {
|
case "remoteAddress":
|
||||||
return context.getUserId()
|
contextValue = context.getRemoteAddress();
|
||||||
.orElse(
|
break;
|
||||||
context.getSessionId()
|
case "appVersionCode":
|
||||||
.orElse(
|
contextValue = context.getAppVersionCode();
|
||||||
context.getRemoteAddress()
|
break;
|
||||||
.orElse(context.getAppVersionCode()
|
case "osType":
|
||||||
.orElse(context.getOsType()
|
contextValue = context.getOsType();
|
||||||
.orElse(context.getDeviceId()
|
break;
|
||||||
.orElse(Double.toString(Math.random())))))
|
case "deviceId":
|
||||||
));
|
contextValue = context.getDeviceId();
|
||||||
}
|
break;
|
||||||
|
default:
|
||||||
private static String randomString() {
|
contextValue = Optional.ofNullable(context.getProperties().get(override.getContextName()));
|
||||||
int randSeed = new Random().nextInt(100000);
|
|
||||||
return "" + randSeed;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getSeed(LitmusContext litmusContext, Optional<String> stickiness) {
|
|
||||||
return stickiness
|
|
||||||
.map(s -> litmusContext.getByName(s).orElse(randomString()))
|
|
||||||
.orElse(getIdentifier(litmusContext));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Variant selectVariant(LitmusExperiment litmusExperiment, LitmusContext context, Variant defaultVariant) {
|
|
||||||
if (litmusExperiment == null || StringUtils.isBlank(litmusExperiment.getVariants())) {
|
|
||||||
return defaultVariant;
|
|
||||||
}
|
|
||||||
List<VariantDefinition> variants = JacksonUtils.stringToListObject(litmusExperiment.getVariants(), VariantDefinition.class);
|
|
||||||
int totalWeight = variants.stream().mapToInt(VariantDefinition::getWeight).sum();
|
|
||||||
if (totalWeight == 0) {
|
|
||||||
return defaultVariant;
|
|
||||||
}
|
}
|
||||||
|
return override.getValues().contains(contextValue.orElse(""));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
Optional<VariantDefinition> variantOverride = getOverride(variants, context);
|
private static Optional<VariantDefinition> getOverride(
|
||||||
if (variantOverride.isPresent()) {
|
List<VariantDefinition> variants, LitmusContext context) {
|
||||||
var variantDefinition = variantOverride.get();
|
return variants.stream()
|
||||||
return Variant.builder()
|
.filter(
|
||||||
.name(variantDefinition.getName())
|
variant ->
|
||||||
.payload(variantDefinition.getPayload())
|
variant.getOverrides().stream()
|
||||||
.enabled(true)
|
.anyMatch(overrideMatchesContext(context)))
|
||||||
.stickiness(variantDefinition.getStickiness())
|
.findFirst();
|
||||||
.build();
|
}
|
||||||
}
|
|
||||||
Optional<String> customStickiness =
|
|
||||||
variants.stream()
|
|
||||||
.filter(f -> f.getStickiness() != null)
|
|
||||||
.map(VariantDefinition::getStickiness)
|
|
||||||
.findFirst();
|
|
||||||
int target =
|
|
||||||
StrategyUtils.getNormalizedNumber(
|
|
||||||
getSeed(context, customStickiness), litmusExperiment.getName(), totalWeight);
|
|
||||||
|
|
||||||
int counter = 0;
|
private static String getIdentifier(LitmusContext context) {
|
||||||
for (final VariantDefinition definition : variants) {
|
return context.getUserId()
|
||||||
if (definition.getWeight() != 0) {
|
.orElse(
|
||||||
counter += definition.getWeight();
|
context.getSessionId()
|
||||||
if (counter >= target) {
|
.orElse(
|
||||||
return Variant.builder()
|
context.getRemoteAddress()
|
||||||
.name(definition.getName())
|
.orElse(context.getAppVersionCode()
|
||||||
.payload(definition.getPayload())
|
.orElse(context.getOsType()
|
||||||
.enabled(true)
|
.orElse(context.getDeviceId()
|
||||||
.stickiness(definition.getStickiness())
|
.orElse(Double.toString(Math.random())))))
|
||||||
.build();
|
));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Should not happen
|
private static String randomString() {
|
||||||
|
int randSeed = new Random().nextInt(100000);
|
||||||
|
return "" + randSeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getSeed(LitmusContext litmusContext, Optional<String> stickiness) {
|
||||||
|
return stickiness
|
||||||
|
.map(s -> litmusContext.getByName(s).orElse(randomString()))
|
||||||
|
.orElse(getIdentifier(litmusContext));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Variant selectVariant(LitmusExperiment litmusExperiment, LitmusContext context, Variant defaultVariant) {
|
||||||
|
if (litmusExperiment == null || StringUtils.isBlank(litmusExperiment.getVariants())) {
|
||||||
|
return defaultVariant;
|
||||||
|
}
|
||||||
|
List<VariantDefinition> variants = JacksonUtils.stringToListObject(litmusExperiment.getVariants(), VariantDefinition.class);
|
||||||
|
int totalWeight = variants.stream().mapToInt(VariantDefinition::getWeight).sum();
|
||||||
|
if (totalWeight == 0) {
|
||||||
return defaultVariant;
|
return defaultVariant;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Optional<VariantDefinition> variantOverride = getOverride(variants, context);
|
||||||
|
if (variantOverride.isPresent()) {
|
||||||
|
var variantDefinition = variantOverride.get();
|
||||||
|
return Variant.builder()
|
||||||
|
.name(variantDefinition.getName())
|
||||||
|
.payload(variantDefinition.getPayload())
|
||||||
|
.enabled(true)
|
||||||
|
.stickiness(variantDefinition.getStickiness())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
Optional<String> customStickiness =
|
||||||
|
variants.stream()
|
||||||
|
.filter(f -> f.getStickiness() != null)
|
||||||
|
.map(VariantDefinition::getStickiness)
|
||||||
|
.findFirst();
|
||||||
|
int target =
|
||||||
|
StrategyUtils.getNormalizedNumber(
|
||||||
|
getSeed(context, customStickiness), litmusExperiment.getName(), totalWeight);
|
||||||
|
|
||||||
|
int counter = 0;
|
||||||
|
for (final VariantDefinition definition : variants) {
|
||||||
|
if (definition.getWeight() != 0) {
|
||||||
|
counter += definition.getWeight();
|
||||||
|
if (counter >= target) {
|
||||||
|
return Variant.builder()
|
||||||
|
.name(definition.getName())
|
||||||
|
.payload(definition.getPayload())
|
||||||
|
.enabled(true)
|
||||||
|
.stickiness(definition.getStickiness())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should not happen
|
||||||
|
return defaultVariant;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,13 +11,11 @@ import org.springframework.context.annotation.Bean;
|
|||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@RequiredArgsConstructor
|
public record LitmusProxyContainer(LitmusProxyConfig litmusProxyConfig) {
|
||||||
public class LitmusProxyContainer {
|
|
||||||
private final LitmusProxyConfig litmusProxyConfig;
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public Litmus litmus(RequestMetadata requestMetadata) {
|
public Litmus litmus(RequestMetadata requestMetadata) {
|
||||||
var litmusConfig = LitmusConfig.builder()
|
var litmusConfig = LitmusConfig.builder()
|
||||||
.litmusAPI(litmusProxyConfig.getLitmusEndpoint())
|
.litmusAPI(litmusProxyConfig.getLitmusEndpoint())
|
||||||
.appName("litmus-proxy")
|
.appName("litmus-proxy")
|
||||||
.instanceId("test-instance")
|
.instanceId("test-instance")
|
||||||
|
|||||||
@@ -12,10 +12,8 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/v1/proxy")
|
@RequestMapping("/v1/proxy")
|
||||||
@RequiredArgsConstructor
|
|
||||||
@Log4j2
|
@Log4j2
|
||||||
public class LitmusProxyController {
|
public record LitmusProxyController(Litmus litmus) {
|
||||||
private final Litmus litmus;
|
|
||||||
|
|
||||||
@GetMapping(value = "/experiment", produces = MediaType.APPLICATION_JSON_VALUE)
|
@GetMapping(value = "/experiment", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
public ResponseEntity<?> fetch(@RequestParam("name") String experimentName) {
|
public ResponseEntity<?> fetch(@RequestParam("name") String experimentName) {
|
||||||
@@ -24,4 +22,11 @@ public class LitmusProxyController {
|
|||||||
return ResponseEntity.ok(result);
|
return ResponseEntity.ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping(value = "/variant", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
public ResponseEntity<?> fetchVariants(@RequestParam("name") String variantName) {
|
||||||
|
var variant = litmus.getVariant(variantName);
|
||||||
|
|
||||||
|
return ResponseEntity.ok(variant);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.navi.medici.provider;
|
package com.navi.medici.provider;
|
||||||
|
|
||||||
|
import com.navi.medici.config.LitmusConfig;
|
||||||
import com.navi.medici.context.LitmusContext;
|
import com.navi.medici.context.LitmusContext;
|
||||||
import com.navi.medici.interceptor.RequestMetadata;
|
import com.navi.medici.interceptor.RequestMetadata;
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
@@ -9,17 +10,12 @@ import org.springframework.web.context.annotation.RequestScope;
|
|||||||
@Component
|
@Component
|
||||||
@RequestScope
|
@RequestScope
|
||||||
@Log4j2
|
@Log4j2
|
||||||
public class CustomLitmusProxyContextProvider implements LitmusContextProvider {
|
public record CustomLitmusProxyContextProvider(RequestMetadata requestMetadata) implements LitmusContextProvider {
|
||||||
|
|
||||||
private final RequestMetadata requestMetadata;
|
|
||||||
|
|
||||||
public CustomLitmusProxyContextProvider(RequestMetadata requestMetadata) {
|
|
||||||
this.requestMetadata = requestMetadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LitmusContext getContext() {
|
public LitmusContext getContext() {
|
||||||
return LitmusContext.builder()
|
return LitmusContext.builder()
|
||||||
|
.userId(requestMetadata.customerId().orElseGet(() -> ""))
|
||||||
.clickStreamPayload(requestMetadata.getClickStreamData())
|
.clickStreamPayload(requestMetadata.getClickStreamData())
|
||||||
.appVersionCode(requestMetadata.getAppVersionCode().orElse(""))
|
.appVersionCode(requestMetadata.getAppVersionCode().orElse(""))
|
||||||
.osType(requestMetadata.getOsVersion().orElse(""))
|
.osType(requestMetadata.getOsVersion().orElse(""))
|
||||||
|
|||||||
Reference in New Issue
Block a user