Merge pull request #29 from medici/litmus-executor

Chandresh | Fixing polltime corner case
This commit is contained in:
chandresh pancholi
2022-12-28 11:17:30 +05:30
committed by GitHub Enterprise
14 changed files with 89 additions and 21 deletions

View File

@@ -67,7 +67,11 @@ public class LitmusExperimentRepository implements ExperimentRepository {
return () -> {
try {
LitmusExperimentResponse response = experimentFetcher.fetchExperiments(vertical, pollingTime);
if (response != null && LitmusExperimentResponse.Status.CHANGED == response.getStatus()) {
if (response != null
&& LitmusExperimentResponse.Status.CHANGED == response.getStatus()
&& response.getExperimentCollection() != null
&& !response.getExperimentCollection().getLitmusExperiments().isEmpty()
) {
experimentCollection = response.getExperimentCollection();
experimentBackupHandler.write(response.getExperimentCollection());
this.inMemoryCache = new InMemoryCache(experimentCollection);

View File

@@ -11,5 +11,8 @@ public class LitmusCoreConfig {
String s3Bucket;
@Value("${s3.enabled:false}")
Boolean s3Enabled;
boolean s3Enabled;
@Value("${default.polling.time.seconds}")
long defaultPollingTimeSeconds;
}

View File

@@ -32,6 +32,8 @@ public class ExperimentController {
@PostMapping(value = "/create", consumes = MediaType.APPLICATION_JSON_VALUE)
@Timed(value = "litmus.create.experiment", percentiles = {0.95, 0.99})
public ResponseEntity<LitmusExperiment> createExperiment(@RequestBody LitmusExperiment litmusExperimentRequest) {
log.info("litmus experiment creation request received. name: {}", litmusExperimentRequest.getName());
return ResponseEntity.ok(experimentService.create(litmusExperimentRequest));
}
@@ -39,12 +41,14 @@ public class ExperimentController {
@GetMapping
@Timed(value = "litmus.fetch.experiment", percentiles = {0.95, 0.99})
public LitmusExperimentCollection fetchExperiments() {
log.info("fetching all experiments");
return experimentService.fetchAllExperiments();
}
@GetMapping("/fetch")
@Timed(value = "litmus.core.fetch.experiment.by.name", percentiles = {0.95, 0.99})
public LitmusExperiment fetchExperimentsByName(@RequestParam("experiment_name") String experimentName) {
log.info("fetch experiment request received. experiment_name: {}", experimentName);
return experimentService.fetchExperimentByName(experimentName);
}
@@ -52,8 +56,11 @@ public class ExperimentController {
@Timed(value = "litmus.fetch.vertical.experiment", percentiles = {0.95, 0.99})
public ResponseEntity<LitmusExperimentCollection> fetchExperimentsForVertical(@RequestParam("vertical") String vertical,
@RequestParam("polling_time") Long pollingTime) {
log.info("fetch experiment with polling time received. vertical: {}, polling_time: {}", vertical, pollingTime);
var collection = experimentService.fetchAllExperimentsForVertical(vertical);
var collection = experimentService.fetchAllExperimentsForVerticals(vertical, pollingTime);
log.info("experiments updated in last polling time. polling_time: {}, experiments: {}",
pollingTime, collection.getLitmusExperiments().size());
if (collection.getLitmusExperiments().isEmpty()) {
return ResponseEntity.status(HttpStatus.NOT_MODIFIED).body(collection);
}
@@ -72,8 +79,7 @@ public class ExperimentController {
@PutMapping(value = "/update/strategies", consumes = MediaType.APPLICATION_JSON_VALUE)
@Timed(value = "litmus.update.strategies", percentiles = {0.95, 0.99})
public void updateStrategies(@RequestBody LitmusExperimentStrategyUpdate litmusExperimentStrategyUpdate) {
log.info("strategy update request received. experiment_id: {}, strategies: {}",
litmusExperimentStrategyUpdate.getExperimentId(), litmusExperimentStrategyUpdate.getStrategies());
log.info("strategy update request received. experiment_id: {}", litmusExperimentStrategyUpdate.getExperimentId());
experimentService.updateStrategies(litmusExperimentStrategyUpdate);
}

View File

@@ -17,7 +17,7 @@ import software.amazon.awssdk.services.s3.model.PutObjectResponse;
public record S3Service(S3Client s3Client, LitmusCoreConfig litmusConfig) {
public void upload(MultipartFile file, String destinationBucket) {
if (litmusConfig.getS3Enabled()) {
if (litmusConfig.isS3Enabled()) {
try {
PutObjectRequest putOb = PutObjectRequest.builder()
.bucket(litmusConfig.getS3Bucket())

View File

@@ -18,9 +18,11 @@ public interface ExperimentService {
void attachVariants(String experimentId, List<VariantDefinition> variantDefinitions);
LitmusExperimentCollection fetchAllExperimentsForVerticals(String vertical, Long pollingTime);
LitmusExperimentCollection fetchAllExperimentsForVerticalInPollingTime(String vertical, Long pollingTime);
void updateStrategies(LitmusExperimentStrategyUpdate litmusExperimentStrategyUpdate);
void updateVertical(VerticalUpdateRequest verticalUpdateRequest);
LitmusExperimentCollection fetchAllExperimentsForVertical(String vertical);
}

View File

@@ -3,10 +3,12 @@ package com.navi.medici.service.experiment;
import static com.navi.medici.enums.ExperimentType.KILL_SWITCH;
import static com.navi.medici.enums.ExperimentType.RELEASE;
import com.navi.medici.config.LitmusCoreConfig;
import com.navi.medici.entity.ExperimentEntity;
import com.navi.medici.exceptions.BadRequestException;
import com.navi.medici.exceptions.ExperimentAlreadyExistException;
import com.navi.medici.exceptions.LitmusExperimentNotFoundException;
import com.navi.medici.exceptions.NoExperimentsFoundForVerticalException;
import com.navi.medici.query.experiment.IExperimentQuery;
import com.navi.medici.request.v1.LitmusExperiment;
import com.navi.medici.request.v1.LitmusExperimentStrategyUpdate;
@@ -30,7 +32,8 @@ import org.springframework.stereotype.Service;
@Service
@Log4j2
public record ExperimentServiceImpl(IExperimentQuery experimentQuery,
JacksonUtils jacksonUtils) implements ExperimentService {
JacksonUtils jacksonUtils,
LitmusCoreConfig litmusCoreConfig) implements ExperimentService {
@Override
public LitmusExperiment create(LitmusExperiment litmusExperimentRequest) {
@@ -101,8 +104,12 @@ public record ExperimentServiceImpl(IExperimentQuery experimentQuery,
}
@Override
public LitmusExperimentCollection fetchAllExperimentsForVerticals(String vertical, Long pollingTime) {
var experimentEntities = experimentQuery.findByVertical(vertical, pollingTime);
public LitmusExperimentCollection fetchAllExperimentsForVerticalInPollingTime(String vertical, Long pollingTime) {
//This will help where client failed to poll and should get all the data in next poll
if (pollingTime < litmusCoreConfig.getDefaultPollingTimeSeconds()) {
pollingTime = litmusCoreConfig.getDefaultPollingTimeSeconds();
}
var experimentEntities = experimentQuery.findByVerticalAndPollingTime(vertical, pollingTime);
List<LitmusExperiment> litmusExperiments = experimentEntities.stream()
.map(this::build)
@@ -117,21 +124,25 @@ public record ExperimentServiceImpl(IExperimentQuery experimentQuery,
public void updateStrategies(LitmusExperimentStrategyUpdate litmusExperimentStrategyUpdate) {
var experimentExist = experimentQuery.findByExperimentId(litmusExperimentStrategyUpdate.getExperimentId());
if (experimentExist.isEmpty()) {
throw new LitmusExperimentNotFoundException(String.format("experiment %s not found in system", litmusExperimentStrategyUpdate.getExperimentId()));
throw new LitmusExperimentNotFoundException(String.format("experiment %s not found in system",
litmusExperimentStrategyUpdate.getExperimentId()));
}
log.info("updating strategies. experiment_id: {}, strategies: {}",
litmusExperimentStrategyUpdate.getExperimentId(),
jacksonUtils.objectToString(litmusExperimentStrategyUpdate.getStrategies()));
var litmusExperiment = experimentExist.get();
litmusExperiment.setStrategies(jacksonUtils.objectToString(litmusExperimentStrategyUpdate.getStrategies()));
experimentQuery.save(litmusExperiment);
}
@Override
public void updateVertical(VerticalUpdateRequest verticalUpdateRequest) {
var experimentExist = experimentQuery.findByExperimentId(verticalUpdateRequest.getExperimentId());
if (experimentExist.isEmpty()) {
throw new LitmusExperimentNotFoundException(String.format("experiment not found. experiment_id: %s", verticalUpdateRequest.getExperimentId()));
throw new LitmusExperimentNotFoundException(String.format("experiment not found. experiment_id: %s",
verticalUpdateRequest.getExperimentId()));
}
var litmusExperiment = experimentExist.get();
@@ -140,6 +151,23 @@ public record ExperimentServiceImpl(IExperimentQuery experimentQuery,
experimentQuery.save(litmusExperiment);
}
@Override
public LitmusExperimentCollection fetchAllExperimentsForVertical(String vertical) {
var experimentEntities = experimentQuery.findByVertical(vertical);
if (experimentEntities.isEmpty()) {
throw new NoExperimentsFoundForVerticalException(String.format("no experiments found for this vertical %s",
vertical));
}
List<LitmusExperiment> litmusExperiments = experimentEntities.stream()
.map(this::build)
.collect(Collectors.toList());
return LitmusExperimentCollection.builder()
.litmusExperiments(litmusExperiments)
.build();
}
private LitmusExperiment build(ExperimentEntity experimentEntity) {
List<VariantDefinition> variants = StringUtils.isBlank(experimentEntity.getVariants()) ? Collections.emptyList() :
jacksonUtils.stringToListObject(experimentEntity.getVariants(), VariantDefinition.class);

View File

@@ -33,12 +33,12 @@ redis.port=6379
redis.expected.insertions=99999
redis.false.probability=0.001
segment.s3.bucket=${SEGMENT_S3_BUCKET:navi-test}
s3.enabled=${S3_ENABLED:false}
springdoc.swagger-ui.path=/swagger-ui.html
spring.servlet.multipart.max-file-size=-1
spring.servlet.multipart.max-request-size=-1
spring.servlet.multipart.max-request-size=-1
default.polling.time.seconds= ${DEFAULT_POLLING_TIME_SECONDS:300}

View File

@@ -30,12 +30,17 @@ public class ExperimentQueryImpl implements IExperimentQuery {
}
@Override
public List<ExperimentEntity> findByVertical(String vertical, Long pollingTime) {
public List<ExperimentEntity> findByVerticalAndPollingTime(String vertical, Long pollingTime) {
var lastPollingTime = LocalDateTime.now().minusSeconds(pollingTime);
return experimentRepository.findByVerticalAndUpdatedTime(vertical, lastPollingTime, LocalDateTime.now());
}
@Override
public List<ExperimentEntity> findByVertical(String vertical) {
return experimentRepository.findByVertical(vertical);
}
@Override
public ExperimentEntity save(ExperimentEntity experiment) {
return experimentRepository.save(experiment);

View File

@@ -11,7 +11,9 @@ public interface IExperimentQuery {
Optional<ExperimentEntity> findByExperimentId(String experimentId);
List<ExperimentEntity> findByVertical(String vertical, Long pollingTime);
List<ExperimentEntity> findByVerticalAndPollingTime(String vertical, Long pollingTime);
List<ExperimentEntity> findByVertical(String vertical);
ExperimentEntity save(ExperimentEntity experiment);
}

View File

@@ -15,7 +15,7 @@ public class CustomLitmusContextProvider implements LitmusContextProvider {
@Override
public LitmusContext getContext() {
return LitmusContext.builder()
.addProperty("loanOfferReferenceId", "873a0877-51a7-4acf-96f6-66eb6ac80652")
.userId("3e082c85-6fe2-4da2-a87e-470838df878e")
// .deviceId(new Random().nextInt() + "")
// .clickStreamPayload("{\"app\":{\"name\":\"NaviDebug\",\"version\":\"77\",\"version_name\":\"1.9.3-cug-1-debug\"},\"client_ts\":\"1633768839907\",\"device\":{\"advertising_id\":\"8835d2b0-5615-412e-b133-8f8dc28e228e\",\"device_id\":\"9a14136215e76324\",\"manufacturer\":\"vivo\",\"model\":\"V2040\",\"os\":\"Android\",\"os_version\":\"30\"},\"events\":[{\"event_name\":\"splash\",\"timestamp\":1633768835058},{\"event_name\":\"home_activity\",\"timestamp\":1633768839791},{\"event_name\":\"home\",\"timestamp\":1633768839860},{\"event_name\":\"full_page_loader_shown\",\"timestamp\":1633768839868}],\"location\":{\"latitude\":\"null\",\"longitude\":\"null\"},\"network\":{\"carrier\":\"\",\"type\":\"Wifi\"},\"source\":\"SyncTimer\",\"user\":{}}")
.build();

View File

@@ -18,7 +18,7 @@ public class MockContainer {
.instanceId("test-instance")
.litmusContextProvider(new CustomLitmusContextProvider())
.clickStreamAPI("https://dev-janus.np.navi-tech.in/events/json")
.vertical("SA")
.vertical("PL")
.meterRegistry(meterRegistry)
.synchronousFetchOnInitialisation(true)
.build();

View File

@@ -10,6 +10,7 @@ import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import lombok.experimental.FieldDefaults;
@AllArgsConstructor
@@ -19,6 +20,7 @@ import lombok.experimental.FieldDefaults;
@Setter
@JsonIgnoreProperties(ignoreUnknown = true)
@FieldDefaults(level = AccessLevel.PRIVATE)
@ToString
public class LitmusExperimentStrategyUpdate {
@JsonProperty("experiment_name")
String experimentName;

View File

@@ -0,0 +1,15 @@
package com.navi.medici.exceptions;
import lombok.extern.log4j.Log4j2;
@Log4j2
public class NoExperimentsFoundForVerticalException extends RuntimeException {
public NoExperimentsFoundForVerticalException(String message) {
super(message);
}
public NoExperimentsFoundForVerticalException(String message, Throwable e) {
super(message, e);
log.error(message, e);
}
}

View File

@@ -2,4 +2,5 @@ DATASOURCE_URL=jdbc:postgresql://dev-db-service-db.np.navi-tech.in:5432/litmus
DATASOURCE_USERNAME=service_user
DATASOURCE_PASSWORD=JRCFCMXUXBJHGZVTPBNTXHYCCFVMWN
REDIS_HOST=dev-env-redis.twod4l.0001.aps1.cache.amazonaws.com
SEGMENT_S3_BUCKET=
SEGMENT_S3_BUCKET=
DEFAULT_POLLING_TIME_SECONDS=300