Merge pull request #29 from medici/litmus-executor
Chandresh | Fixing polltime corner case
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -11,5 +11,8 @@ public class LitmusCoreConfig {
|
||||
String s3Bucket;
|
||||
|
||||
@Value("${s3.enabled:false}")
|
||||
Boolean s3Enabled;
|
||||
boolean s3Enabled;
|
||||
|
||||
@Value("${default.polling.time.seconds}")
|
||||
long defaultPollingTimeSeconds;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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}
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user