Skip to content

Commit 91db87d

Browse files
authored
Feature/1288 ts timer (#1700)
I've added metrics to dao to try and detect where the request is timing out (in total calc or in data retrieve). I've also added to the Controller so that it should cause a timeout if the dao is taking longer than 45 seconds.
1 parent 611949d commit 91db87d

15 files changed

Lines changed: 369 additions & 229 deletions

cwms-data-api/src/main/java/cwms/cda/api/CdaVersionHandler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ private Timer.Context markAndTime(String subject) {
7272
public void handle(@NotNull Context ctx) throws Exception {
7373
try (Timer.Context ignored = markAndTime(GET_ONE)) {
7474
DSLContext dsl = getDslContext(ctx);
75-
CdaVersionDao dao = new CdaVersionDao(dsl);
75+
CdaVersionDao dao = new CdaVersionDao(dsl, metrics);
7676
CdaVersion cdaVersion = dao.getCdaVersion();
7777
String serialized = Formats.format(new ContentType(Formats.JSON), cdaVersion);
7878
ctx.result(serialized);

cwms-data-api/src/main/java/cwms/cda/api/TimeSeriesController.java

Lines changed: 35 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,12 @@
11
package cwms.cda.api;
22

33
import static com.codahale.metrics.MetricRegistry.name;
4-
import static cwms.cda.api.Controllers.BEGIN;
5-
import static cwms.cda.api.Controllers.CREATE;
6-
import static cwms.cda.api.Controllers.CREATE_AS_LRTS;
7-
import static cwms.cda.api.Controllers.CURSOR;
8-
import static cwms.cda.api.Controllers.DATUM;
9-
import static cwms.cda.api.Controllers.DELETE;
10-
import static cwms.cda.api.Controllers.END;
11-
import static cwms.cda.api.Controllers.END_TIME_INCLUSIVE;
12-
import static cwms.cda.api.Controllers.FORMAT;
13-
import static cwms.cda.api.Controllers.GET_ALL;
14-
import static cwms.cda.api.Controllers.GET_ONE;
15-
import static cwms.cda.api.Controllers.INCLUDE_ENTRY_DATE;
16-
import static cwms.cda.api.Controllers.MAX_VERSION;
17-
import static cwms.cda.api.Controllers.NAME;
18-
import static cwms.cda.api.Controllers.NOT_SUPPORTED_YET;
19-
import static cwms.cda.api.Controllers.OFFICE;
20-
import static cwms.cda.api.Controllers.OVERRIDE_PROTECTION;
21-
import static cwms.cda.api.Controllers.PAGE;
22-
import static cwms.cda.api.Controllers.PAGE_SIZE;
23-
import static cwms.cda.api.Controllers.RESULTS;
24-
import static cwms.cda.api.Controllers.SIZE;
25-
import static cwms.cda.api.Controllers.START_TIME_INCLUSIVE;
26-
import static cwms.cda.api.Controllers.STATUS_200;
27-
import static cwms.cda.api.Controllers.STATUS_400;
28-
import static cwms.cda.api.Controllers.STATUS_404;
29-
import static cwms.cda.api.Controllers.STATUS_501;
30-
import static cwms.cda.api.Controllers.STORE_RULE;
31-
import static cwms.cda.api.Controllers.TIMESERIES;
32-
import static cwms.cda.api.Controllers.TIMEZONE;
33-
import static cwms.cda.api.Controllers.TIME_FORMAT_DESC;
34-
import static cwms.cda.api.Controllers.UNIT;
35-
import static cwms.cda.api.Controllers.UNITS;
36-
import static cwms.cda.api.Controllers.UPDATE;
37-
import static cwms.cda.api.Controllers.VERSION;
38-
import static cwms.cda.api.Controllers.VERSION_DATE;
39-
import static cwms.cda.api.Controllers.addDeprecatedContentTypeWarning;
40-
import static cwms.cda.api.Controllers.queryParamAsClass;
41-
import static cwms.cda.api.Controllers.queryParamAsZdt;
42-
import static cwms.cda.api.Controllers.requiredParam;
43-
import static cwms.cda.api.Controllers.requiredZdt;
4+
import static cwms.cda.api.Controllers.*;
445

456
import com.codahale.metrics.Histogram;
467
import com.codahale.metrics.MetricRegistry;
478
import com.codahale.metrics.Timer;
9+
import com.google.common.flogger.FluentLogger;
4810
import cwms.cda.api.enums.UnitSystem;
4911
import cwms.cda.api.errors.CdaError;
5012
import cwms.cda.api.errors.NotFoundException;
@@ -78,7 +40,8 @@
7840
import java.sql.Timestamp;
7941
import java.time.ZoneId;
8042
import java.time.ZonedDateTime;
81-
import com.google.common.flogger.FluentLogger;
43+
import java.util.concurrent.CompletableFuture;
44+
import java.util.concurrent.TimeUnit;
8245
import javax.servlet.http.HttpServletResponse;
8346
import org.apache.commons.io.IOUtils;
8447
import org.apache.http.client.utils.URIBuilder;
@@ -503,7 +466,25 @@ public void getAll(@NotNull Context ctx) {
503466
.withShouldTrim(trim.getOrDefault(true))
504467
.withIncludeEntryDate(includeEntryDate)
505468
.build();
506-
TimeSeries ts = dao.getTimeseries(cursor, pageSize, requestParameters);
469+
// Execute DAO call with a timeout so we can return a clearer message instead of a generic 500
470+
int apiTimeoutMs = Integer.getInteger("cwms.cda.api.apiTimeoutMs", 45000);
471+
CompletableFuture<TimeSeries> daoFuture = CompletableFuture.supplyAsync(() -> dao.getTimeseries(cursor, pageSize, requestParameters));
472+
TimeSeries ts;
473+
try {
474+
ts = daoFuture.get(apiTimeoutMs, TimeUnit.MILLISECONDS);
475+
} catch (java.util.concurrent.TimeoutException ex) {
476+
daoFuture.cancel(true);
477+
cwms.cda.api.errors.CdaError re = new cwms.cda.api.errors.CdaError("Request is taking too long; try narrowing the date range.");
478+
ctx.status(HttpServletResponse.SC_REQUEST_TIMEOUT);
479+
ctx.json(re);
480+
return;
481+
} catch (InterruptedException ex) {
482+
daoFuture.cancel(true);
483+
Thread.currentThread().interrupt();
484+
throw new RuntimeException(ex);
485+
} catch (java.util.concurrent.ExecutionException ex) {
486+
throw unwrapExecutionException(ex);
487+
}
507488

508489
if(datum != null) { //this will be null for non-elevation ts
509490
// user has requested a specific vertical datum
@@ -553,6 +534,18 @@ public void getAll(@NotNull Context ctx) {
553534
}
554535
}
555536

537+
static RuntimeException unwrapExecutionException(java.util.concurrent.ExecutionException ex) {
538+
Throwable cause = ex.getCause();
539+
if (cause instanceof RuntimeException) {
540+
// CDA ApplicationException extends RuntimeException.
541+
throw (RuntimeException) cause;
542+
}
543+
if (cause instanceof Error) {
544+
throw (Error) cause;
545+
}
546+
return new RuntimeException(cause);
547+
}
548+
556549
private void addLinkHeader(@NotNull Context ctx, TimeSeries ts, ContentType contentType) {
557550
try {
558551
// Send back the link to the next page in the response header

cwms-data-api/src/main/java/cwms/cda/data/dao/CdaVersionDao.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
package cwms.cda.data.dao;
2828

29+
import com.codahale.metrics.MetricRegistry;
2930
import cwms.cda.ApiServlet;
3031
import cwms.cda.data.dto.CdaVersion;
3132
import java.util.HashMap;
@@ -36,9 +37,11 @@
3637

3738
public final class CdaVersionDao extends JooqDao<CdaVersion> {
3839
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
40+
private final MetricRegistry metrics;
3941

40-
public CdaVersionDao(DSLContext dsl) {
42+
public CdaVersionDao(DSLContext dsl, MetricRegistry metrics) {
4143
super(dsl);
44+
this.metrics = metrics;
4245
}
4346

4447
/**
@@ -62,7 +65,7 @@ private Map<String, Object> buildFeatures() {
6265
}
6366

6467
private String hasTsDataEntryDateSupport() {
65-
TimeSeriesDaoImpl tsDao = new TimeSeriesDaoImpl(super.dsl);
68+
TimeSeriesDaoImpl tsDao = new TimeSeriesDaoImpl(super.dsl, metrics);
6669
boolean supported = false;
6770
try {
6871
tsDao.validateEntryDateSupport(true);

0 commit comments

Comments
 (0)