diff options
author | Jon Marius Venstad <venstad@gmail.com> | 2019-09-15 07:33:53 +0200 |
---|---|---|
committer | Jon Marius Venstad <venstad@gmail.com> | 2019-09-15 07:33:53 +0200 |
commit | 70a1b6410611e74e7c55b9452d5b14838242a827 (patch) | |
tree | 02044cd66417b78979093069f7a4a21ed58cdd5d /hosted-api | |
parent | 1492dfe3718acd1025644ab38bc034b2cbf86ae1 (diff) |
Retry timeouts and 5XXs from controller
Diffstat (limited to 'hosted-api')
-rw-r--r-- | hosted-api/src/main/java/ai/vespa/hosted/api/ControllerHttpClient.java | 49 |
1 files changed, 33 insertions, 16 deletions
diff --git a/hosted-api/src/main/java/ai/vespa/hosted/api/ControllerHttpClient.java b/hosted-api/src/main/java/ai/vespa/hosted/api/ControllerHttpClient.java index c6c5c64bd9f..43864f5f9d6 100644 --- a/hosted-api/src/main/java/ai/vespa/hosted/api/ControllerHttpClient.java +++ b/hosted-api/src/main/java/ai/vespa/hosted/api/ControllerHttpClient.java @@ -127,7 +127,7 @@ public abstract class ControllerHttpClient { /** Returns the test config for functional and verification tests of the indicated Vespa deployment. */ public TestConfig testConfig(ApplicationId id, ZoneId zone) { - return TestConfig.fromJson(asBytes(send(request(HttpRequest.newBuilder(testConfigPath(id, zone)), GET)))); + return TestConfig.fromJson(send(request(HttpRequest.newBuilder(testConfigPath(id, zone)), GET)).body()); } /** Returns the sorted list of log entries after the given after from the deployment job of the given ids. */ @@ -218,8 +218,37 @@ public abstract class ControllerHttpClient { return zone.environment().value() + "-" + zone.region().value(); } + /** Returns a response with a 2XX status code, with up to 3 attempts, or throws. */ private HttpResponse<byte[]> send(HttpRequest request) { - return unchecked(() -> client.send(request, ofByteArray())); + UncheckedIOException thrown = null; + for (int retry = 0; retry < 3; retry++) { + try { + HttpResponse<byte[]> response = client.send(request, ofByteArray()); + if (response.statusCode() / 100 == 2) + return response; + + Inspector rootObject = toSlime(response.body()).get(); + String message = response.request() + " returned code " + response.statusCode() + + " (" + rootObject.field("error-code").asString() + "): " + + rootObject.field("message").asString(); + + if (response.statusCode() / 100 == 4) + throw new IllegalArgumentException(message); + + throw new IOException(message); + + } + catch (IOException e) { // Catches the above, and timeout exceptions from the client. + if (thrown == null) + thrown = new UncheckedIOException(e); + else + thrown.addSuppressed(e); + } + catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + throw thrown; } private static <T> T unchecked(Callable<T> callable) { @@ -262,24 +291,12 @@ public abstract class ControllerHttpClient { /** Returns the response body as a String, or throws if the status code is non-2XX. */ private static String asString(HttpResponse<byte[]> response) { - return new String(asBytes(response), UTF_8); - } - - /** Returns the response body as a byte array, or throws if the status code is non-2XX. */ - private static byte[] asBytes(HttpResponse<byte[]> response) { - toInspector(response); - return response.body(); + return new String(response.body(), UTF_8); } /** Returns an {@link Inspector} for the assumed JSON formatted response, or throws if the status code is non-2XX. */ private static Inspector toInspector(HttpResponse<byte[]> response) { - Inspector rootObject = toSlime(response.body()).get(); - if (response.statusCode() / 100 != 2) - throw new RuntimeException(response.request() + " returned code " + response.statusCode() + - " (" + rootObject.field("error-code").asString() + "): " + - rootObject.field("message").asString()); - - return rootObject; + return toSlime(response.body()).get(); } /** Returns the "message" element contained in the JSON formatted response, if 2XX status code, or throws otherwise. */ |