Skip to content

Commit

Permalink
UpdateRecommendation API E2E working code is ready.
Browse files Browse the repository at this point in the history
Signed-off-by: msvinaykumar <vinakuma@redhat.com>
  • Loading branch information
msvinaykumar committed May 20, 2023
1 parent 2819514 commit bf60a9c
Show file tree
Hide file tree
Showing 10 changed files with 87 additions and 67 deletions.
1 change: 1 addition & 0 deletions src/main/java/com/autotune/analyzer/Analyzer.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public static void addServlets(ServletContextHandler context) {
context.addServlet(ExperimentsSummary.class, ServerContext.EXPERIMENTS_SUMMARY);
context.addServlet(CreateExperiment.class, ServerContext.CREATE_EXPERIMENT);
context.addServlet(UpdateResults.class, ServerContext.UPDATE_RESULTS);
context.addServlet(UpdateRecommendation.class, ServerContext.UPDATE_RECOMMENDATIONS);
context.addServlet(ListRecommendations.class, ServerContext.RECOMMEND_RESULTS);
context.addServlet(PerformanceProfileService.class, ServerContext.CREATE_PERF_PROFILE);
context.addServlet(PerformanceProfileService.class, ServerContext.LIST_PERF_PROFILES);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,10 @@
package com.autotune.analyzer.services;

import com.autotune.analyzer.exceptions.KruizeResponse;
import com.autotune.analyzer.experiment.ExperimentInitiator;
import com.autotune.analyzer.kruizeObject.KruizeObject;
import com.autotune.analyzer.utils.AnalyzerErrorConstants;
import com.autotune.common.data.result.ContainerData;
import com.autotune.common.data.result.IntervalResults;
import com.autotune.common.k8sObjects.K8sObject;
import com.autotune.common.data.result.ExperimentResultData;
import com.autotune.database.service.ExperimentDBService;
import com.autotune.utils.KruizeConstants;
import com.autotune.utils.Utils;
Expand All @@ -37,6 +36,7 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Timestamp;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

Expand Down Expand Up @@ -65,13 +65,16 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response)
// Check if experiment_name is provided
if (experiment_name == null || experiment_name.isEmpty()) {
sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.EXPERIMENT_NAME_MANDATORY);
return;
}

// Check if interval_end_time is provided
if (intervalEndTimeStr == null || intervalEndTimeStr.isEmpty()) {
sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.INTERVAL_END_TIME_MANDATORY);
return;
}

LOGGER.debug("experiment_name : {} and interval_end_time : {}", experiment_name, intervalEndTimeStr);
// Convert interval_endtime to UTC date format
if (!Utils.DateUtils.isAValidDate(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT, intervalEndTimeStr)) {
sendErrorResponse(
Expand All @@ -80,46 +83,43 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response)
HttpServletResponse.SC_BAD_REQUEST,
String.format(AnalyzerErrorConstants.APIErrors.ListRecommendationsAPI.INVALID_TIMESTAMP_MSG, intervalEndTimeStr)
);
return;
}

//Check if data exist
Timestamp interval_end_time = Utils.DateUtils.getTimeStampFrom(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT, intervalEndTimeStr);
boolean dataExists = false;
ExperimentResultData experimentResultData = null;
try {
dataExists = new ExperimentDBService().checkIfResultsExists(experiment_name, interval_end_time);
experimentResultData = new ExperimentDBService().getExperimentResultData(experiment_name, interval_end_time);
} catch (Exception e) {
sendErrorResponse(response, e, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
return;
}

if (dataExists) {
if (null != experimentResultData) {
//Load KruizeObject and generate recommendation
Map<String, KruizeObject> mainKruizeExperimentMAP = new HashMap<>();
try {
new ExperimentDBService().loadExperimentAndResultsFromDBByName(mainKruizeExperimentMAP, experiment_name, null, interval_end_time);
KruizeObject kruizeObject = mainKruizeExperimentMAP.get(experiment_name);
for (K8sObject k8Obj : kruizeObject.getKubernetes_objects()) {
for (ContainerData containerData : k8Obj.getContainerDataMap().values()) {
for (IntervalResults result : containerData.getResults().values()) {

}
}
// Subtract LONG_TERM_DURATION_DAYS from the given interval_end_time
long subtractedTime = interval_end_time.getTime() - (KruizeConstants.RecommendationEngineConstants.DurationBasedEngine.DurationAmount.LONG_TERM_DURATION_DAYS * KruizeConstants.DateFormats.MILLI_SECONDS_FOR_DAY);
Timestamp interval_start_time = new Timestamp(subtractedTime);
new ExperimentDBService().loadExperimentAndResultsFromDBByName(mainKruizeExperimentMAP, experiment_name, interval_start_time, interval_end_time);
boolean recommendationCheck = new ExperimentInitiator().generateAndAddRecommendations(mainKruizeExperimentMAP, Collections.singletonList(experimentResultData));
if (!recommendationCheck)
LOGGER.error("Failed to create recommendation for experiment: %s and interval_end_time: %s",
experimentResultData.getExperiment_name(),
experimentResultData.getIntervalEndTime());
else {
new ExperimentDBService().addRecommendationToDB(mainKruizeExperimentMAP, Collections.singletonList(experimentResultData));
sendSuccessResponse(response, "Recommendation generated successfully! visit /listRecommendations");
}
// List<ExperimentResultData> experimentResultDataList = ;
// boolean recommendationCheck = new ExperimentInitiator().generateAndAddRecommendations(mainKruizeExperimentMAP, experimentResultDataList);
// if (!recommendationCheck)
// LOGGER.error("Failed to create recommendation for experiment: %s and interval_end_time: %s",
// experimentResultDataList.get(0).getExperiment_name(),
// experimentResultDataList.get(0).getIntervalEndTime());
// else {
// new ExperimentDBService().addRecommendationToDB(mKruizeExperimentMap, experimentResultDataList);
// }
} catch (Exception e) {
e.printStackTrace();
}
} else {
sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.DATA_NOT_FOUND);
return;
}
sendSuccessResponse(response, "All ok");
}

private void sendSuccessResponse(HttpServletResponse response, String message) throws IOException {
Expand All @@ -139,7 +139,6 @@ public void sendErrorResponse(HttpServletResponse response, Exception e, int htt
IOException {
if (null != e) {
LOGGER.error(e.toString());
e.printStackTrace();
if (null == errorMsg) errorMsg = e.getMessage();
}
response.sendError(httpStatusCode, errorMsg);
Expand Down
24 changes: 12 additions & 12 deletions src/main/java/com/autotune/analyzer/services/UpdateResults.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public void init(ServletConfig config) throws ServletException {

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Map<String, KruizeObject> mKruizeExperimentMap = new ConcurrentHashMap<String, KruizeObject>();;
Map<String, KruizeObject> mKruizeExperimentMap = new ConcurrentHashMap<String, KruizeObject>();
try {
String inputData = request.getReader().lines().collect(Collectors.joining());
List<ExperimentResultData> experimentResultDataList = new ArrayList<>();
Expand All @@ -91,7 +91,7 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response)
if (addedToDB.isSuccess()) {
sendSuccessResponse(response, AnalyzerConstants.ServiceConstants.RESULT_SAVED);
//ToDO add temp code and call system.gc for every 100 results
int count = (int)getServletContext().getAttribute(AnalyzerConstants.RESULTS_COUNT);
int count = (int) getServletContext().getAttribute(AnalyzerConstants.RESULTS_COUNT);
count++;
LOGGER.debug("totalResultsCount so far : {}", count);
if (count >= AnalyzerConstants.GC_THRESHOLD_COUNT) {
Expand All @@ -109,16 +109,16 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response)
sendErrorResponse(response, null, invalidKExperimentResultData.getValidationOutputData().getErrorCode(), invalidKExperimentResultData.getValidationOutputData().getMessage());
}

if (validationOutputData.isSuccess() && addedToDB.isSuccess()) {
boolean recommendationCheck = experimentInitiator.generateAndAddRecommendations(mKruizeExperimentMap, experimentResultDataList);
if (!recommendationCheck)
LOGGER.error("Failed to create recommendation for experiment: %s and interval_end_time: %s",
experimentResultDataList.get(0).getExperiment_name(),
experimentResultDataList.get(0).getIntervalEndTime());
else {
new ExperimentDBService().addRecommendationToDB(mKruizeExperimentMap, experimentResultDataList);
}
}
// if (validationOutputData.isSuccess() && addedToDB.isSuccess()) {
// boolean recommendationCheck = experimentInitiator.generateAndAddRecommendations(mKruizeExperimentMap, experimentResultDataList);
// if (!recommendationCheck)
// LOGGER.error("Failed to create recommendation for experiment: %s and interval_end_time: %s",
// experimentResultDataList.get(0).getExperiment_name(),
// experimentResultDataList.get(0).getIntervalEndTime());
// else {
// new ExperimentDBService().addRecommendationToDB(mKruizeExperimentMap, experimentResultDataList);
// }
// }
}
} catch (Exception e) {
LOGGER.error("Exception: " + e.getMessage());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ public static final class ListRecommendationsAPI {
public static final String RECOMMENDATION_DOES_NOT_EXIST_EXCPTN = "Recommendation does not exist";
public static final String RECOMMENDATION_DOES_NOT_EXIST_MSG = "Recommendation for timestamp - \" %s \" does not exist";
public static final String INVALID_TIMESTAMP_EXCPTN = "Invalid Timestamp format";
public static final String INVALID_TIMESTAMP_MSG = "Given timestamp - \" %s \" is not a valid timestamp format";
public static final String INVALID_TIMESTAMP_MSG = "The provided timestamp, - \" %s \" does not conform to the valid timestamp format: " + KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT;
public static final String INVALID_EXPERIMENT_NAME_EXCPTN = "Invalid Experiment Name";
public static final String INVALID_EXPERIMENT_NAME_MSG = "Given experiment name - \" %s \" is not valid";

Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/autotune/database/dao/ExperimentDAO.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public interface ExperimentDAO {
// Load all recommendations of a particular experiment
List<KruizeRecommendationEntry> loadRecommendationsByExperimentName(String experimentName) throws Exception;

// Check if experiment_name + interval_end_time exist in DB
boolean isDataExistsInResults(String experiment_name, Timestamp interval_end_time) throws Exception;
// Get KruizeResult Record
KruizeResultsEntry getKruizeResultsEntry(String experiment_name, Timestamp interval_end_time) throws Exception;

}
26 changes: 16 additions & 10 deletions src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -214,8 +214,16 @@ public List<KruizeResultsEntry> loadResultsByExperimentName(String experimentNam
// TODO: load only experimentStatus=inProgress , playback may not require completed experiments
List<KruizeResultsEntry> kruizeResultsEntries = null;
try (Session session = KruizeHibernateUtil.getSessionFactory().openSession()) {
kruizeResultsEntries = session.createQuery(DBConstants.SQLQUERY.SELECT_FROM_RESULTS_BY_EXP_NAME, KruizeResultsEntry.class)
.setParameter("experimentName", experimentName).list();
if (null != interval_start_time && null != interval_end_time) {
kruizeResultsEntries = session.createQuery(DBConstants.SQLQUERY.SELECT_FROM_RESULTS_BY_EXP_NAME_AND_DATE_RANGE, KruizeResultsEntry.class)
.setParameter(KruizeConstants.JSONKeys.EXPERIMENT_NAME, experimentName)
.setParameter(KruizeConstants.JSONKeys.INTERVAL_START_TIME, interval_start_time)
.setParameter(KruizeConstants.JSONKeys.INTERVAL_END_TIME, interval_end_time)
.list();
} else {
kruizeResultsEntries = session.createQuery(DBConstants.SQLQUERY.SELECT_FROM_RESULTS_BY_EXP_NAME, KruizeResultsEntry.class)
.setParameter("experimentName", experimentName).list();
}
} catch (Exception e) {
LOGGER.error("Not able to load results due to: {}", e.getMessage());
throw new Exception("Error while loading results from the database due to : " + e.getMessage());
Expand All @@ -237,20 +245,18 @@ public List<KruizeRecommendationEntry> loadRecommendationsByExperimentName(Strin
}

@Override
public boolean isDataExistsInResults(String experiment_name, Timestamp interval_end_time) throws Exception {
boolean success = false;
List<KruizeResultsEntry> kruizeResultsEntries = null;
public KruizeResultsEntry getKruizeResultsEntry(String experiment_name, Timestamp interval_end_time) throws Exception {
KruizeResultsEntry kruizeResultsEntry = null;
try (Session session = KruizeHibernateUtil.getSessionFactory().openSession()) {
kruizeResultsEntries = session.createQuery(SELECT_FROM_RESULTS_BY_EXP_NAME_AND_END_TIME, KruizeResultsEntry.class)
kruizeResultsEntry = session.createQuery(SELECT_FROM_RESULTS_BY_EXP_NAME_AND_END_TIME, KruizeResultsEntry.class)
.setParameter(KruizeConstants.JSONKeys.EXPERIMENT_NAME, experiment_name)
.setParameter(KruizeConstants.JSONKeys.INTERVAL_END_TIME, interval_end_time)
.list();
if (kruizeResultsEntries.size() > 0)
success = true;
.getSingleResult();
} catch (Exception e) {
kruizeResultsEntry = null;
LOGGER.error("Not able to load results due to: {}", e.getMessage());
throw new Exception("Error while loading results from the database due to : " + e.getMessage());
}
return success;
return kruizeResultsEntry;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

Expand Down Expand Up @@ -266,7 +267,6 @@ public void loadExperimentFromDBByName(Map<String, KruizeObject> mainKruizeExper
public void loadExperimentAndResultsFromDBByName(Map<String, KruizeObject> mainKruizeExperimentMap, String experimentName, Timestamp interval_start_time, Timestamp interval_end_time) throws Exception {

loadExperimentFromDBByName(mainKruizeExperimentMap, experimentName);

loadResultsFromDBByName(mainKruizeExperimentMap, experimentName, interval_start_time, interval_end_time);
}

Expand All @@ -291,8 +291,13 @@ public boolean updateExperimentStatus(KruizeObject kruizeObject, AnalyzerConstan
return true;
}

public boolean checkIfResultsExists(String experiment_name, Timestamp interval_end_time) throws Exception {
boolean success = experimentDAO.isDataExistsInResults(experiment_name, interval_end_time);
return success;
public ExperimentResultData getExperimentResultData(String experiment_name, Timestamp interval_end_time) throws Exception {
ExperimentResultData experimentResultData = null;
KruizeResultsEntry kruizeResultsEntry = experimentDAO.getKruizeResultsEntry(experiment_name, interval_end_time);
List<UpdateResultsAPIObject> updateResultsAPIObjects = DBHelpers.Converters.KruizeObjectConverters.convertResultEntryToUpdateResultsAPIObject(Collections.singletonList(kruizeResultsEntry));
if (null != updateResultsAPIObjects && !updateResultsAPIObjects.isEmpty()) {
experimentResultData = Converters.KruizeObjectConverters.convertUpdateResultsAPIObjToExperimentResultData(updateResultsAPIObjects.get(0));
}
return experimentResultData;
}
}
18 changes: 7 additions & 11 deletions src/main/java/com/autotune/utils/KruizeConstants.java
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,7 @@ private DBConstants() {
public static final class DateFormats {
public static final String STANDARD_JSON_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
public static final String DB_EXTRACTION_FORMAT = "yyyy-MM-dd HH:mm:ss.SSS";
public static final long MILLI_SECONDS_FOR_DAY = 24 * 60 * 60 * 1000;

private DateFormats() {

Expand Down Expand Up @@ -408,39 +409,34 @@ private DurationBasedEngine() {
}

public static final class DurationAmount {
private DurationAmount() {

}

public static final int SHORT_TERM_DURATION_DAYS = 1;
public static final int MEDIUM_TERM_DURATION_DAYS = 7;
public static final int LONG_TERM_DURATION_DAYS = 15;
}

public static final class RecommendationDurationRanges {
private RecommendationDurationRanges() {
private DurationAmount() {

}
}

public static final class RecommendationDurationRanges {
private static final double BUFFER_VALUE_IN_MINS = (TimeConv.MEASUREMENT_DURATION_THRESHOLD_SECONDS / TimeConv.NO_OF_SECONDS_PER_MINUTE);
/* SHORT TERM */
public static final double SHORT_TERM_TOTAL_DURATION_UPPER_BOUND_MINS =
(DurationAmount.SHORT_TERM_DURATION_DAYS * TimeConv.NO_OF_HOURS_PER_DAY * TimeConv.NO_OF_MINUTES_PER_HOUR) + BUFFER_VALUE_IN_MINS;

public static final double SHORT_TERM_TOTAL_DURATION_LOWER_BOUND_MINS =
(DurationAmount.SHORT_TERM_DURATION_DAYS * TimeConv.NO_OF_HOURS_PER_DAY * TimeConv.NO_OF_MINUTES_PER_HOUR) - BUFFER_VALUE_IN_MINS;

/* MEDIUM TERM */
public static final double MEDIUM_TERM_TOTAL_DURATION_UPPER_BOUND_MINS =
(DurationAmount.MEDIUM_TERM_DURATION_DAYS * TimeConv.NO_OF_HOURS_PER_DAY * TimeConv.NO_OF_MINUTES_PER_HOUR) + BUFFER_VALUE_IN_MINS;
public static final double MEDIUM_TERM_TOTAL_DURATION_LOWER_BOUND_MINS =
(DurationAmount.MEDIUM_TERM_DURATION_DAYS * TimeConv.NO_OF_HOURS_PER_DAY * TimeConv.NO_OF_MINUTES_PER_HOUR) - BUFFER_VALUE_IN_MINS;

/* LONG TERM */
public static final double LONG_TERM_TOTAL_DURATION_UPPER_BOUND_MINS =
(DurationAmount.LONG_TERM_DURATION_DAYS * TimeConv.NO_OF_HOURS_PER_DAY * TimeConv.NO_OF_MINUTES_PER_HOUR) + BUFFER_VALUE_IN_MINS;
public static final double LONG_TERM_TOTAL_DURATION_LOWER_BOUND_MINS =
(DurationAmount.LONG_TERM_DURATION_DAYS * TimeConv.NO_OF_HOURS_PER_DAY * TimeConv.NO_OF_MINUTES_PER_HOUR) - BUFFER_VALUE_IN_MINS;
private RecommendationDurationRanges() {

}

}
}
Expand Down
Loading

0 comments on commit bf60a9c

Please sign in to comment.