Skip to content

Commit

Permalink
Modify EvaluationHandler service to separate retrieving evaluation fr…
Browse files Browse the repository at this point in the history
…om updating.

- Make the URL evaluation handler use a separate thread to extract evaluation.
  • Loading branch information
Matt Pearce committed Dec 10, 2018
1 parent 2604c72 commit 9588d89
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 17 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package io.sease.rre.server.services;

/**
* Exception thrown during evaluation handling.
*
* @author Matt Pearce ([email protected])
*/
public class EvaluationHandlerException extends Exception {

public EvaluationHandlerException() {
}

public EvaluationHandlerException(String message) {
super(message);
}

public EvaluationHandlerException(String message, Throwable cause) {
super(message, cause);
}

public EvaluationHandlerException(Throwable cause) {
super(cause);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.fasterxml.jackson.databind.JsonNode;
import io.sease.rre.core.domain.Evaluation;
import io.sease.rre.server.domain.EvaluationMetadata;
import org.springframework.stereotype.Service;

/**
Expand All @@ -10,16 +11,36 @@
* and use them to build an Evaluation object that can be used to populate
* the dashboard.
*
* The {@link #processEvaluationRequest(JsonNode)} method should ideally
* return as quickly as possible, to avoid blocking the sender of the incoming
* request. The evaluation data can then be retrieved using {@link #getEvaluation()}
* where the evaluation contains the most recently processed data.
*
* @author Matt Pearce ([email protected])
*/
@Service
public interface EvaluationHandlerService {

/**
* Update the currently held evaluation data.
* Update the currently held evaluation data. This may be done
* asynchronously - the method should return as quickly as possible.
*
* @param requestData incoming data giving details of evaluation.
* @throws Exception if the data cannot be processed.
* @throws EvaluationHandlerException if the data cannot be processed.
*/
void processEvaluationRequest(final JsonNode requestData) throws EvaluationHandlerException;

/**
* Get the current evaluation data.
*
* @return the Evaluation.
*/
Evaluation getEvaluation();

/**
* Get the current evaluation metadata.
*
* @return the evaluation metadata.
*/
Evaluation processEvaluationRequest(final JsonNode requestData) throws Exception;
EvaluationMetadata getEvaluationMetadata();
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.sease.rre.core.domain.*;
import io.sease.rre.server.domain.EvaluationMetadata;
import io.sease.rre.server.domain.StaticMetric;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import static java.util.stream.StreamSupport.stream;
Expand All @@ -25,9 +29,27 @@ public class HttpEvaluationHandlerService implements EvaluationHandlerService {

private final ObjectMapper mapper = new ObjectMapper();

private Evaluation evaluation = new Evaluation();
private EvaluationMetadata metadata = new EvaluationMetadata(Collections.emptyList(), Collections.emptyList());

@Override
public void processEvaluationRequest(final JsonNode requestData) throws EvaluationHandlerException {
evaluation = make(requestData);
}

@Override
public Evaluation getEvaluation() {
return evaluation;
}

@Override
public Evaluation processEvaluationRequest(final JsonNode requestData) {
return make(requestData);
public EvaluationMetadata getEvaluationMetadata() {
return metadata;
}

void setEvaluation(Evaluation eval) {
this.evaluation = eval;
this.metadata = extractEvaluationMetadata(eval);
}

ObjectMapper getMapper() {
Expand Down Expand Up @@ -99,4 +121,24 @@ private void metrics(final JsonNode data, final DomainMember parent) {
parent.getMetrics().put(metric.getName(), metric);
});
}

/**
* Extract the evaluation metadata from an evaluation.
*
* @param evaluation the evaluation data.
* @return the evaluation metadata.
*/
public static EvaluationMetadata extractEvaluationMetadata(final Evaluation evaluation) {
final List<String> metrics = new ArrayList<>(
evaluation.getChildren()
.iterator().next()
.getMetrics().keySet());

final List<String> versions = new ArrayList<>(
evaluation.getChildren()
.iterator().next()
.getMetrics().values().iterator().next().getVersions().keySet());

return new EvaluationMetadata(versions, metrics);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;

/**
* Implementation of the evaluation handler that extracts a URL from the
Expand All @@ -24,28 +26,62 @@ public class URLEvaluationHandlerService extends HttpEvaluationHandlerService im

private static final Logger LOGGER = LoggerFactory.getLogger(URLEvaluationHandlerService.class);

@Override
public Evaluation processEvaluationRequest(JsonNode requestData) {
Evaluation eval = new Evaluation();
private URLEvaluationUpdater updater = null;

@Override
public void processEvaluationRequest(JsonNode requestData) throws EvaluationHandlerException {
try {
if (updater != null && updater.isAlive()) {
throw new EvaluationHandlerException("Update is already running - request rejected!");
}

final String urlParam = requestData.get("url").asText();
final JsonNode evaluationNode = readNodeFromUrl(new URL(urlParam));
LOGGER.debug("Extracted URL {} from incoming request", urlParam);

eval = make(evaluationNode);
// Build the evaluation in a separate thread - avoid causing timeouts in the report plugin
updater = createUpdaterThread(new URL(urlParam));
updater.start();
} catch (IOException e) {
LOGGER.error("Caught IOException processing request: {}", e.getMessage());
throw new EvaluationHandlerException(e);
}
}

return eval;
private URLEvaluationUpdater createUpdaterThread(URL evaluationUrl) {
URLEvaluationUpdater thread = new URLEvaluationUpdater(evaluationUrl);
// Run the thread in the background
thread.setDaemon(true);
return thread;
}

private JsonNode readNodeFromUrl(URL evaluationUrl) throws IOException {
try {
return getMapper().readTree(evaluationUrl);
} catch (IOException e) {
LOGGER.error("Caught IOException reading JSON from {}: {}", evaluationUrl, e.getMessage());
throw e;

class URLEvaluationUpdater extends Thread {

private final URL evaluationUrl;

URLEvaluationUpdater(URL evaluationUrl) {
this.evaluationUrl = evaluationUrl;
}

@Override
public void run() {
try {
LOGGER.info("Building evaluation from URL {}", evaluationUrl);
final JsonNode evaluationNode = readNodeFromUrl(evaluationUrl);
setEvaluation(make(evaluationNode));
LOGGER.debug("Evaluation build complete");
} catch (IOException e) {
LOGGER.error("Caught IOException building evaluation: {}", e.getMessage());
}
}

private JsonNode readNodeFromUrl(URL evaluationUrl) throws IOException {
try {
return getMapper().readTree(evaluationUrl);
} catch (IOException e) {
LOGGER.error("Caught IOException reading JSON from {}: {}", evaluationUrl, e.getMessage());
throw e;
}
}
}
}

0 comments on commit 9588d89

Please sign in to comment.