|
1 | 1 | package cwms.cda.api; |
2 | 2 |
|
3 | 3 | 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.*; |
44 | 5 |
|
45 | 6 | import com.codahale.metrics.Histogram; |
46 | 7 | import com.codahale.metrics.MetricRegistry; |
47 | 8 | import com.codahale.metrics.Timer; |
| 9 | +import com.google.common.flogger.FluentLogger; |
48 | 10 | import cwms.cda.api.enums.UnitSystem; |
49 | 11 | import cwms.cda.api.errors.CdaError; |
50 | 12 | import cwms.cda.api.errors.NotFoundException; |
|
78 | 40 | import java.sql.Timestamp; |
79 | 41 | import java.time.ZoneId; |
80 | 42 | import java.time.ZonedDateTime; |
81 | | -import com.google.common.flogger.FluentLogger; |
| 43 | +import java.util.concurrent.CompletableFuture; |
| 44 | +import java.util.concurrent.TimeUnit; |
82 | 45 | import javax.servlet.http.HttpServletResponse; |
83 | 46 | import org.apache.commons.io.IOUtils; |
84 | 47 | import org.apache.http.client.utils.URIBuilder; |
@@ -503,7 +466,25 @@ public void getAll(@NotNull Context ctx) { |
503 | 466 | .withShouldTrim(trim.getOrDefault(true)) |
504 | 467 | .withIncludeEntryDate(includeEntryDate) |
505 | 468 | .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 | + } |
507 | 488 |
|
508 | 489 | if(datum != null) { //this will be null for non-elevation ts |
509 | 490 | // user has requested a specific vertical datum |
@@ -553,6 +534,18 @@ public void getAll(@NotNull Context ctx) { |
553 | 534 | } |
554 | 535 | } |
555 | 536 |
|
| 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 | + |
556 | 549 | private void addLinkHeader(@NotNull Context ctx, TimeSeries ts, ContentType contentType) { |
557 | 550 | try { |
558 | 551 | // Send back the link to the next page in the response header |
|
0 commit comments