diff options
author | Håkon Hallingstad <hakon@oath.com> | 2018-06-22 11:01:22 +0200 |
---|---|---|
committer | Håkon Hallingstad <hakon@oath.com> | 2018-06-22 11:01:22 +0200 |
commit | da8720586341957f15bf6a42b291d879c8569538 (patch) | |
tree | 29bb114ffbc6bb5bdd4a048e53845df00f449e08 /clustercontroller-utils | |
parent | d17e36f062c38550a96ccee3e41d7ff5266efecb (diff) |
set-node-state timeout in CC
Diffstat (limited to 'clustercontroller-utils')
5 files changed, 91 insertions, 8 deletions
diff --git a/clustercontroller-utils/pom.xml b/clustercontroller-utils/pom.xml index ecfc6df3bd0..e176ce9d1e5 100644 --- a/clustercontroller-utils/pom.xml +++ b/clustercontroller-utils/pom.xml @@ -40,6 +40,11 @@ <version>${project.version}</version> <scope>provided</scope> </dependency> + <dependency> + <groupId>com.google.guava</groupId> + <artifactId>guava</artifactId> + <scope>provided</scope> + </dependency> </dependencies> <build> <plugins> diff --git a/clustercontroller-utils/src/main/java/com/yahoo/vespa/clustercontroller/utils/staterestapi/requests/SetUnitStateRequest.java b/clustercontroller-utils/src/main/java/com/yahoo/vespa/clustercontroller/utils/staterestapi/requests/SetUnitStateRequest.java index d583e4ecc27..a28ddb3539b 100644 --- a/clustercontroller-utils/src/main/java/com/yahoo/vespa/clustercontroller/utils/staterestapi/requests/SetUnitStateRequest.java +++ b/clustercontroller-utils/src/main/java/com/yahoo/vespa/clustercontroller/utils/staterestapi/requests/SetUnitStateRequest.java @@ -1,6 +1,7 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.clustercontroller.utils.staterestapi.requests; +import com.yahoo.time.TimeBudget; import com.yahoo.vespa.clustercontroller.utils.staterestapi.errors.InvalidContentException; import com.yahoo.vespa.clustercontroller.utils.staterestapi.response.UnitState; @@ -62,4 +63,5 @@ public interface SetUnitStateRequest extends UnitRequest { } ResponseWait getResponseWait(); + TimeBudget timeBudget(); } diff --git a/clustercontroller-utils/src/main/java/com/yahoo/vespa/clustercontroller/utils/staterestapi/server/JsonReader.java b/clustercontroller-utils/src/main/java/com/yahoo/vespa/clustercontroller/utils/staterestapi/server/JsonReader.java index 3d0856669f1..3c62d87098b 100644 --- a/clustercontroller-utils/src/main/java/com/yahoo/vespa/clustercontroller/utils/staterestapi/server/JsonReader.java +++ b/clustercontroller-utils/src/main/java/com/yahoo/vespa/clustercontroller/utils/staterestapi/server/JsonReader.java @@ -8,10 +8,16 @@ import com.yahoo.vespa.clustercontroller.utils.staterestapi.response.UnitState; import org.codehaus.jettison.json.JSONArray; import org.codehaus.jettison.json.JSONObject; +import java.time.Duration; import java.util.HashMap; import java.util.Map; +import java.util.Optional; +import java.util.concurrent.TimeUnit; public class JsonReader { + public static final Duration DEFAULT_TIMEOUT = Duration.ofSeconds(30); + public static final Duration MAX_TIMEOUT = Duration.ofHours(1); + private static final long MICROS_IN_SECOND = TimeUnit.SECONDS.toMillis(1); private static class UnitStateImpl implements UnitState { private final String id; @@ -37,11 +43,16 @@ public class JsonReader { final Map<String, UnitState> stateMap; final SetUnitStateRequest.Condition condition; final SetUnitStateRequest.ResponseWait responseWait; - public SetRequestData(Map<String, UnitState> stateMap, SetUnitStateRequest.Condition condition, - SetUnitStateRequest.ResponseWait responseWait) { + final Optional<Duration> timeout; + + public SetRequestData(Map<String, UnitState> stateMap, + SetUnitStateRequest.Condition condition, + SetUnitStateRequest.ResponseWait responseWait, + Optional<Duration> timeout) { this.stateMap = stateMap; this.condition = condition; this.responseWait = responseWait; + this.timeout = timeout; } } @@ -98,7 +109,33 @@ public class JsonReader { } stateMap.put(type, new UnitStateImpl(code, reason)); } - return new SetRequestData(stateMap, condition, responseWait); + + final Optional<Duration> timeout = parseTimeout(request.getOption("timeout", null)); + + return new SetRequestData(stateMap, condition, responseWait, timeout); + } + + public static Optional<Duration> parseTimeout(String timeoutOption) throws InvalidContentException { + if (timeoutOption == null) { + return Optional.empty(); + } else { + float timeoutSeconds; + try { + timeoutSeconds = Float.parseFloat(timeoutOption); + } catch (NumberFormatException e) { + throw new InvalidContentException("value of timeout->" + timeoutOption + " is not a float"); + } + + if (timeoutSeconds <= 0.0) { + return Optional.of(Duration.ZERO); + } else if (timeoutSeconds <= MAX_TIMEOUT.getSeconds()) { + long micros = Math.round(timeoutSeconds * MICROS_IN_SECOND); + long nanoAdjustment = TimeUnit.MILLISECONDS.toNanos(micros % MICROS_IN_SECOND); + return Optional.of(Duration.ofSeconds(micros / MICROS_IN_SECOND, nanoAdjustment)); + } else { + throw new InvalidContentException("value of timeout->" + timeoutOption + " exceeds max timeout " + MAX_TIMEOUT); + } + } } } diff --git a/clustercontroller-utils/src/main/java/com/yahoo/vespa/clustercontroller/utils/staterestapi/server/RestApiHandler.java b/clustercontroller-utils/src/main/java/com/yahoo/vespa/clustercontroller/utils/staterestapi/server/RestApiHandler.java index 71e6bc36de1..2ccfecf3d17 100644 --- a/clustercontroller-utils/src/main/java/com/yahoo/vespa/clustercontroller/utils/staterestapi/server/RestApiHandler.java +++ b/clustercontroller-utils/src/main/java/com/yahoo/vespa/clustercontroller/utils/staterestapi/server/RestApiHandler.java @@ -1,19 +1,32 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.clustercontroller.utils.staterestapi.server; +import com.google.common.util.concurrent.UncheckedTimeoutException; import com.yahoo.log.LogLevel; -import com.yahoo.yolean.Exceptions; +import com.yahoo.time.TimeBudget; import com.yahoo.vespa.clustercontroller.utils.communication.http.HttpRequest; import com.yahoo.vespa.clustercontroller.utils.communication.http.HttpRequestHandler; import com.yahoo.vespa.clustercontroller.utils.communication.http.HttpResult; import com.yahoo.vespa.clustercontroller.utils.communication.http.JsonHttpResult; import com.yahoo.vespa.clustercontroller.utils.staterestapi.StateRestAPI; -import com.yahoo.vespa.clustercontroller.utils.staterestapi.errors.*; +import com.yahoo.vespa.clustercontroller.utils.staterestapi.errors.DeadlineExceededException; +import com.yahoo.vespa.clustercontroller.utils.staterestapi.errors.InvalidOptionValueException; +import com.yahoo.vespa.clustercontroller.utils.staterestapi.errors.OtherMasterException; +import com.yahoo.vespa.clustercontroller.utils.staterestapi.errors.StateRestApiException; +import com.yahoo.vespa.clustercontroller.utils.staterestapi.errors.UnknownMasterException; import com.yahoo.vespa.clustercontroller.utils.staterestapi.requests.SetUnitStateRequest; import com.yahoo.vespa.clustercontroller.utils.staterestapi.requests.UnitStateRequest; -import com.yahoo.vespa.clustercontroller.utils.staterestapi.response.*; +import com.yahoo.vespa.clustercontroller.utils.staterestapi.response.SetResponse; +import com.yahoo.vespa.clustercontroller.utils.staterestapi.response.UnitResponse; +import com.yahoo.vespa.clustercontroller.utils.staterestapi.response.UnitState; +import com.yahoo.yolean.Exceptions; -import java.util.*; +import java.time.Clock; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; @@ -24,10 +37,12 @@ public class RestApiHandler implements HttpRequestHandler { private final StateRestAPI restApi; private final JsonWriter jsonWriter; private final JsonReader jsonReader = new JsonReader(); + private final Clock clock; public RestApiHandler(StateRestAPI restApi) { this.restApi = restApi; this.jsonWriter = new JsonWriter(); + this.clock = Clock.systemUTC(); } public RestApiHandler setDefaultPathPrefix(String defaultPathPrefix) { @@ -43,6 +58,8 @@ public class RestApiHandler implements HttpRequestHandler { @Override public HttpResult handleRequest(HttpRequest request) { + Instant start = clock.instant(); + try{ final String[] unitPath = createUnitPath(request); if (request.getHttpOperation().equals(HttpRequest.HttpOp.GET)) { @@ -73,6 +90,8 @@ public class RestApiHandler implements HttpRequestHandler { public Condition getCondition() { return setRequestData.condition; } @Override public ResponseWait getResponseWait() { return setRequestData.responseWait; } + @Override + public TimeBudget timeBudget() { return TimeBudget.from(clock, start, setRequestData.timeout); } }); return new JsonHttpResult().setJson(jsonWriter.createJson(setResponse)); } @@ -89,7 +108,7 @@ public class RestApiHandler implements HttpRequestHandler { result.setHttpCode(503, "Service Unavailable"); result.setJson(jsonWriter.createErrorJson(exception.getMessage())); return result; - } catch (DeadlineExceededException exception) { + } catch (DeadlineExceededException | UncheckedTimeoutException exception) { logRequestException(request, exception, Level.WARNING); JsonHttpResult result = new JsonHttpResult(); result.setHttpCode(504, "Gateway Timeout"); diff --git a/clustercontroller-utils/src/test/java/com/yahoo/vespa/clustercontroller/utils/staterestapi/server/JsonReaderTest.java b/clustercontroller-utils/src/test/java/com/yahoo/vespa/clustercontroller/utils/staterestapi/server/JsonReaderTest.java new file mode 100644 index 00000000000..bf47a6605a2 --- /dev/null +++ b/clustercontroller-utils/src/test/java/com/yahoo/vespa/clustercontroller/utils/staterestapi/server/JsonReaderTest.java @@ -0,0 +1,20 @@ +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.clustercontroller.utils.staterestapi.server; + +import com.yahoo.vespa.clustercontroller.utils.staterestapi.errors.InvalidContentException; +import org.junit.Test; + +import java.time.Duration; +import java.util.Optional; + +import static org.junit.Assert.assertEquals; + +public class JsonReaderTest { + @Test + public void testParsingOfTimeout() throws InvalidContentException { + assertEquals(Optional.empty(), JsonReader.parseTimeout(null)); + assertEquals(Optional.of(Duration.ofMillis(12500)), JsonReader.parseTimeout("12.5")); + assertEquals(Optional.of(Duration.ofMillis(0)), JsonReader.parseTimeout("-1")); + assertEquals(Optional.of(Duration.ofMillis(0)), JsonReader.parseTimeout("0.0001")); + } +}
\ No newline at end of file |