From b8cb61bbe09f26576a5d362b0e8e490444fedc95 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 10 Mar 2020 12:19:44 +0000 Subject: [PATCH] Align embedded Jetty's graceful shutdown behaviour with standalone Standalone Jetty will, by default, include a Connection: close header in all responses once graceful shutdown has begun. Previously, the way in which we were shutting Jetty down did not cause this to happen. This commit updates JettyGracefulShutdown to shut down each connector. This causes Jetty to send the Connection: close header, aligning its behaviour more closely with what it does when used standalone. The tests have also been updated to verify this behaviour and to ensure that the correct port is used for requests even once the connector is no longer bound and the web server no longer knows its ephemeral port. See gh-4657 --- .../embedded/jetty/JettyGracefulShutdown.java | 12 ++- .../JettyReactiveWebServerFactoryTests.java | 33 ++------ .../JettyServletWebServerFactoryTests.java | 82 +++++++++++++++++-- .../NettyReactiveWebServerFactoryTests.java | 2 +- .../TomcatReactiveWebServerFactoryTests.java | 2 +- .../TomcatServletWebServerFactoryTests.java | 5 +- ...UndertowReactiveWebServerFactoryTests.java | 4 +- .../UndertowServletWebServerFactoryTests.java | 5 +- ...AbstractReactiveWebServerFactoryTests.java | 24 +++--- .../AbstractServletWebServerFactoryTests.java | 21 +++-- 10 files changed, 127 insertions(+), 63 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/jetty/JettyGracefulShutdown.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/jetty/JettyGracefulShutdown.java index bb203a33d1..af1c7cfb5f 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/jetty/JettyGracefulShutdown.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/jetty/JettyGracefulShutdown.java @@ -17,13 +17,13 @@ package org.springframework.boot.web.embedded.jetty; import java.time.Duration; +import java.util.concurrent.ExecutionException; import java.util.function.Supplier; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; import org.springframework.boot.web.server.GracefulShutdown; @@ -55,7 +55,15 @@ class JettyGracefulShutdown implements GracefulShutdown { logger.info("Commencing graceful shutdown, allowing up to " + this.period.getSeconds() + "s for active requests to complete"); for (Connector connector : this.server.getConnectors()) { - ((ServerConnector) connector).setAccepting(false); + try { + connector.shutdown().get(); + } + catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + catch (ExecutionException ex) { + // Continue + } } this.shuttingDown = true; long end = System.currentTimeMillis() + this.period.toMillis(); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/jetty/JettyReactiveWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/jetty/JettyReactiveWebServerFactoryTests.java index 886eb0a95f..7bf3c53059 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/jetty/JettyReactiveWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/jetty/JettyReactiveWebServerFactoryTests.java @@ -16,14 +16,12 @@ package org.springframework.boot.web.embedded.jetty; +import java.net.ConnectException; import java.net.InetAddress; import java.time.Duration; -import java.util.ArrayList; import java.util.Arrays; -import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Server; @@ -39,6 +37,7 @@ import org.springframework.http.client.reactive.JettyResourceFactory; import org.springframework.http.server.reactive.HttpHandler; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.inOrder; @@ -128,32 +127,18 @@ class JettyReactiveWebServerFactoryTests extends AbstractReactiveWebServerFactor BlockingHandler blockingHandler = new BlockingHandler(); this.webServer = factory.getWebServer(blockingHandler); this.webServer.start(); + int port = this.webServer.getPort(); CountDownLatch responseLatch = new CountDownLatch(1); - getWebClient().build().get().retrieve().toBodilessEntity().subscribe((response) -> responseLatch.countDown()); + getWebClient(port).build().get().retrieve().toBodilessEntity() + .subscribe((response) -> responseLatch.countDown()); blockingHandler.awaitQueue(); Future shutdownResult = initiateGracefulShutdown(); - // We need to make two requests as Jetty accepts one additional request after a - // connector has been told to stop accepting requests - Mono> unconnectableRequest1 = getWebClient().build().get().retrieve().toBodilessEntity(); - Mono> unconnectableRequest2 = getWebClient().build().get().retrieve().toBodilessEntity(); + Mono> unconnectableRequest = getWebClient(port).build().get().retrieve() + .toBodilessEntity(); assertThat(shutdownResult.get()).isEqualTo(false); blockingHandler.completeOne(); - responseLatch.await(5, TimeUnit.SECONDS); - this.webServer.stop(); - List results = new ArrayList<>(); - try { - results.add(unconnectableRequest1.block()); - } - catch (Exception ex) { - results.add(ex); - } - try { - results.add(unconnectableRequest2.block()); - } - catch (Exception ex) { - results.add(ex); - } - assertThat(results).anySatisfy((result) -> assertThat(result).isInstanceOf(Exception.class)); + assertThatExceptionOfType(RuntimeException.class).isThrownBy(() -> unconnectableRequest.block()) + .withCauseInstanceOf(ConnectException.class); } @Override diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/jetty/JettyServletWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/jetty/JettyServletWebServerFactoryTests.java index 033702b075..ffd26ad513 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/jetty/JettyServletWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/jetty/JettyServletWebServerFactoryTests.java @@ -21,7 +21,7 @@ import java.time.Duration; import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.List; +import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -30,8 +30,11 @@ import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.ServletRegistration.Dynamic; +import org.apache.http.Header; import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; import org.apache.http.conn.HttpHostConnectException; +import org.apache.http.impl.client.HttpClients; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Server; @@ -189,19 +192,80 @@ class JettyServletWebServerFactoryTests extends AbstractJettyServletWebServerFac registration.setAsyncSupported(true); }); this.webServer.start(); - Future request = initiateGetRequest("/blocking"); + int port = this.webServer.getPort(); + Future request = initiateGetRequest(port, "/blocking"); blockingServlet.awaitQueue(); Future shutdownResult = initiateGracefulShutdown(); - // Jetty accepts one additional request after a connector has been told to stop - // accepting requests - Future unconnectableRequest1 = initiateGetRequest("/"); - Future unconnectableRequest2 = initiateGetRequest("/"); + Future unconnectableRequest = initiateGetRequest(port, "/"); assertThat(shutdownResult.get()).isEqualTo(false); blockingServlet.admitOne(); - assertThat(request.get()).isInstanceOf(HttpResponse.class); + Object response = request.get(); + assertThat(response).isInstanceOf(HttpResponse.class); + assertThat(unconnectableRequest.get()).isInstanceOf(HttpHostConnectException.class); this.webServer.stop(); - List results = Arrays.asList(unconnectableRequest1.get(), unconnectableRequest2.get()); - assertThat(results).anySatisfy((result) -> assertThat(result).isInstanceOf(HttpHostConnectException.class)); + } + + @Test + void whenServerIsShuttingDownGracefullyThenResponseToRequestOnIdleConnectionWillHaveAConnectionCloseHeader() + throws Exception { + AbstractServletWebServerFactory factory = getFactory(); + Shutdown shutdown = new Shutdown(); + shutdown.setGracePeriod(Duration.ofSeconds(5)); + factory.setShutdown(shutdown); + BlockingServlet blockingServlet = new BlockingServlet(); + this.webServer = factory.getWebServer((context) -> { + Dynamic registration = context.addServlet("blockingServlet", blockingServlet); + registration.addMapping("/blocking"); + registration.setAsyncSupported(true); + }); + this.webServer.start(); + int port = this.webServer.getPort(); + HttpClient client = HttpClients.createMinimal(); + Future request = initiateGetRequest(client, port, "/blocking"); + blockingServlet.awaitQueue(); + blockingServlet.admitOne(); + Object response = request.get(); + assertThat(response).isInstanceOf(HttpResponse.class); + assertThat(((HttpResponse) response).getStatusLine().getStatusCode()).isEqualTo(200); + assertThat(((HttpResponse) response).getFirstHeader("Connection")).isNull(); + this.webServer.shutDownGracefully(); + request = initiateGetRequest(client, port, "/blocking"); + blockingServlet.awaitQueue(); + blockingServlet.admitOne(); + response = request.get(); + assertThat(response).isInstanceOf(HttpResponse.class); + assertThat(((HttpResponse) response).getStatusLine().getStatusCode()).isEqualTo(200); + assertThat(((HttpResponse) response).getFirstHeader("Connection")).isNotNull().extracting(Header::getValue) + .isEqualTo("close"); + this.webServer.stop(); + } + + @Test + void whenARequestCompletesAfterGracefulShutdownHasBegunThenItHasAConnectionCloseHeader() + throws InterruptedException, ExecutionException { + AbstractServletWebServerFactory factory = getFactory(); + Shutdown shutdown = new Shutdown(); + shutdown.setGracePeriod(Duration.ofSeconds(30)); + factory.setShutdown(shutdown); + BlockingServlet blockingServlet = new BlockingServlet(); + this.webServer = factory.getWebServer((context) -> { + Dynamic registration = context.addServlet("blockingServlet", blockingServlet); + registration.addMapping("/blocking"); + registration.setAsyncSupported(true); + }); + this.webServer.start(); + int port = this.webServer.getPort(); + Future request = initiateGetRequest(port, "/blocking"); + blockingServlet.awaitQueue(); + long start = System.currentTimeMillis(); + Future shutdownResult = initiateGracefulShutdown(); + blockingServlet.admitOne(); + assertThat(shutdownResult.get()).isTrue(); + long end = System.currentTimeMillis(); + assertThat(end - start).isLessThanOrEqualTo(30000); + Object requestResult = request.get(); + assertThat(requestResult).isInstanceOf(HttpResponse.class); + assertThat(((HttpResponse) requestResult).getFirstHeader("Connection").getValue()).isEqualTo("close"); } private Ssl getSslSettings(String... enabledProtocols) { diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactoryTests.java index 7180a29a07..06c1dead36 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactoryTests.java @@ -112,7 +112,7 @@ class NettyReactiveWebServerFactoryTests extends AbstractReactiveWebServerFactor BlockingHandler blockingHandler = new BlockingHandler(); this.webServer = factory.getWebServer(blockingHandler); this.webServer.start(); - WebClient webClient = getWebClient().build(); + WebClient webClient = getWebClient(this.webServer.getPort()).build(); webClient.get().retrieve().toBodilessEntity().subscribe(); blockingHandler.awaitQueue(); Future shutdownResult = initiateGracefulShutdown(); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatReactiveWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatReactiveWebServerFactoryTests.java index 5b452e8d5a..8c7eeaaf02 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatReactiveWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatReactiveWebServerFactoryTests.java @@ -271,7 +271,7 @@ class TomcatReactiveWebServerFactoryTests extends AbstractReactiveWebServerFacto BlockingHandler blockingHandler = new BlockingHandler(); this.webServer = factory.getWebServer(blockingHandler); this.webServer.start(); - WebClient webClient = getWebClient().build(); + WebClient webClient = getWebClient(this.webServer.getPort()).build(); webClient.get().retrieve().toBodilessEntity().subscribe(); blockingHandler.awaitQueue(); Future shutdownResult = initiateGracefulShutdown(); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactoryTests.java index 6c27655eb1..5a5c11e396 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactoryTests.java @@ -574,10 +574,11 @@ class TomcatServletWebServerFactoryTests extends AbstractServletWebServerFactory registration.setAsyncSupported(true); }); this.webServer.start(); - Future request = initiateGetRequest("/blocking"); + int port = this.webServer.getPort(); + Future request = initiateGetRequest(port, "/blocking"); blockingServlet.awaitQueue(); Future shutdownResult = initiateGracefulShutdown(); - Future unconnectableRequest = initiateGetRequest("/"); + Future unconnectableRequest = initiateGetRequest(port, "/"); assertThat(shutdownResult.get()).isEqualTo(false); blockingServlet.admitOne(); assertThat(request.get()).isInstanceOf(HttpResponse.class); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/undertow/UndertowReactiveWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/undertow/UndertowReactiveWebServerFactoryTests.java index 465aa6fe2f..86ad899b16 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/undertow/UndertowReactiveWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/undertow/UndertowReactiveWebServerFactoryTests.java @@ -118,7 +118,7 @@ class UndertowReactiveWebServerFactoryTests extends AbstractReactiveWebServerFac BlockingHandler blockingHandler = new BlockingHandler(); this.webServer = factory.getWebServer(blockingHandler); this.webServer.start(); - WebClient webClient = getWebClient().build(); + WebClient webClient = getWebClient(this.webServer.getPort()).build(); webClient.get().retrieve().toBodilessEntity().subscribe(); blockingHandler.awaitQueue(); Future shutdownResult = initiateGracefulShutdown(); @@ -146,7 +146,7 @@ class UndertowReactiveWebServerFactoryTests extends AbstractReactiveWebServerFac assertThat(accessLogDirectory.listFiles()).isEmpty(); this.webServer = factory.getWebServer(new EchoHandler()); this.webServer.start(); - WebClient client = getWebClient().build(); + WebClient client = getWebClient(this.webServer.getPort()).build(); Mono result = client.post().uri("/test").contentType(MediaType.TEXT_PLAIN) .body(BodyInserters.fromValue("Hello World")).exchange() .flatMap((response) -> response.bodyToMono(String.class)); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/undertow/UndertowServletWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/undertow/UndertowServletWebServerFactoryTests.java index 298562a719..3952436ad5 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/undertow/UndertowServletWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/undertow/UndertowServletWebServerFactoryTests.java @@ -190,10 +190,11 @@ class UndertowServletWebServerFactoryTests extends AbstractServletWebServerFacto registration.setAsyncSupported(true); }); this.webServer.start(); - Future request = initiateGetRequest("/blocking"); + int port = this.webServer.getPort(); + Future request = initiateGetRequest(port, "/blocking"); blockingServlet.awaitQueue(); Future shutdownResult = initiateGracefulShutdown(); - Future rejectedRequest = initiateGetRequest("/"); + Future rejectedRequest = initiateGetRequest(port, "/"); assertThat(shutdownResult.get()).isEqualTo(false); blockingServlet.admitOne(); assertThat(request.get()).isInstanceOf(HttpResponse.class); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java index a574226ed8..d77f79384c 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java @@ -109,8 +109,8 @@ public abstract class AbstractReactiveWebServerFactoryTests { this.webServer.start(); return port; }); - Mono result = getWebClient().build().post().uri("/test").contentType(MediaType.TEXT_PLAIN) - .body(BodyInserters.fromValue("Hello World")).exchange() + Mono result = getWebClient(this.webServer.getPort()).build().post().uri("/test") + .contentType(MediaType.TEXT_PLAIN).body(BodyInserters.fromValue("Hello World")).exchange() .flatMap((response) -> response.bodyToMono(String.class)); assertThat(result.block(Duration.ofSeconds(30))).isEqualTo("Hello World"); assertThat(this.webServer.getPort()).isEqualTo(specificPort); @@ -269,12 +269,12 @@ public abstract class AbstractReactiveWebServerFactoryTests { StepVerifier.create(result).expectError(SSLException.class).verify(Duration.ofSeconds(10)); } - protected WebClient.Builder getWebClient() { - return getWebClient(HttpClient.create().wiretap(true)); + protected WebClient.Builder getWebClient(int port) { + return getWebClient(HttpClient.create().wiretap(true), port); } - protected WebClient.Builder getWebClient(HttpClient client) { - InetSocketAddress address = new InetSocketAddress(this.webServer.getPort()); + protected WebClient.Builder getWebClient(HttpClient client, int port) { + InetSocketAddress address = new InetSocketAddress(port); String baseUrl = "http://" + address.getHostString() + ":" + address.getPort(); return WebClient.builder().clientConnector(new ReactorClientHttpConnector(client)).baseUrl(baseUrl); } @@ -368,7 +368,8 @@ public abstract class AbstractReactiveWebServerFactoryTests { BlockingHandler blockingHandler = new BlockingHandler(); this.webServer = factory.getWebServer(blockingHandler); this.webServer.start(); - Mono> request = getWebClient().build().get().retrieve().toBodilessEntity(); + Mono> request = getWebClient(this.webServer.getPort()).build().get().retrieve() + .toBodilessEntity(); AtomicReference> responseReference = new AtomicReference<>(); CountDownLatch responseLatch = new CountDownLatch(1); request.subscribe((response) -> { @@ -399,7 +400,8 @@ public abstract class AbstractReactiveWebServerFactoryTests { BlockingHandler blockingHandler = new BlockingHandler(); this.webServer = factory.getWebServer(blockingHandler); this.webServer.start(); - Mono> request = getWebClient().build().get().retrieve().toBodilessEntity(); + Mono> request = getWebClient(this.webServer.getPort()).build().get().retrieve() + .toBodilessEntity(); AtomicReference> responseReference = new AtomicReference<>(); CountDownLatch responseLatch = new CountDownLatch(1); request.subscribe((response) -> { @@ -437,7 +439,7 @@ public abstract class AbstractReactiveWebServerFactoryTests { .tcpConfiguration((tcpClient) -> tcpClient.doOnConnected( (connection) -> connection.channel().pipeline().addBefore(NettyPipeline.HttpDecompressor, "CompressionTest", new CompressionDetectionHandler()))); - return getWebClient(client).build(); + return getWebClient(client, this.webServer.getPort()).build(); } protected void assertResponseIsCompressed(ResponseEntity response) { @@ -451,8 +453,8 @@ public abstract class AbstractReactiveWebServerFactoryTests { protected void assertForwardHeaderIsUsed(AbstractReactiveWebServerFactory factory) { this.webServer = factory.getWebServer(new XForwardedHandler()); this.webServer.start(); - String body = getWebClient().build().get().header("X-Forwarded-Proto", "https").retrieve() - .bodyToMono(String.class).block(Duration.ofSeconds(30)); + String body = getWebClient(this.webServer.getPort()).build().get().header("X-Forwarded-Proto", "https") + .retrieve().bodyToMono(String.class).block(Duration.ofSeconds(30)); assertThat(body).isEqualTo("https"); } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/server/AbstractServletWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/server/AbstractServletWebServerFactoryTests.java index a78be6e166..6a493abde5 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/server/AbstractServletWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/server/AbstractServletWebServerFactoryTests.java @@ -1041,7 +1041,8 @@ public abstract class AbstractServletWebServerFactoryTests { registration.addMapping("/blocking"); }); this.webServer.start(); - Future request = initiateGetRequest("/blocking"); + int port = this.webServer.getPort(); + Future request = initiateGetRequest(port, "/blocking"); blockingServlet.awaitQueue(); long start = System.currentTimeMillis(); assertThat(this.webServer.shutDownGracefully()).isFalse(); @@ -1066,7 +1067,8 @@ public abstract class AbstractServletWebServerFactoryTests { registration.setAsyncSupported(true); }); this.webServer.start(); - Future request = initiateGetRequest("/blocking"); + int port = this.webServer.getPort(); + Future request = initiateGetRequest(port, "/blocking"); blockingServlet.awaitQueue(); long start = System.currentTimeMillis(); Future shutdownResult = initiateGracefulShutdown(); @@ -1090,7 +1092,8 @@ public abstract class AbstractServletWebServerFactoryTests { registration.setAsyncSupported(true); }); this.webServer.start(); - Future request = initiateGetRequest("/blockingAsync"); + int port = this.webServer.getPort(); + Future request = initiateGetRequest(port, "/blockingAsync"); blockingAsyncServlet.awaitQueue(); long start = System.currentTimeMillis(); assertThat(this.webServer.shutDownGracefully()).isFalse(); @@ -1115,7 +1118,8 @@ public abstract class AbstractServletWebServerFactoryTests { registration.setAsyncSupported(true); }); this.webServer.start(); - Future request = initiateGetRequest("/blockingAsync"); + int port = this.webServer.getPort(); + Future request = initiateGetRequest(port, "/blockingAsync"); blockingAsyncServlet.awaitQueue(); long start = System.currentTimeMillis(); Future shutdownResult = initiateGracefulShutdown(); @@ -1133,15 +1137,14 @@ public abstract class AbstractServletWebServerFactoryTests { return future; } - protected Future initiateGetRequest(String path) { - return initiateGetRequest(HttpClients.createDefault(), path); + protected Future initiateGetRequest(int port, String path) { + return initiateGetRequest(HttpClients.createMinimal(), port, path); } - protected Future initiateGetRequest(HttpClient httpClient, String path) { + protected Future initiateGetRequest(HttpClient httpClient, int port, String path) { RunnableFuture getRequest = new FutureTask<>(() -> { try { - HttpResponse response = httpClient - .execute(new HttpGet("http://localhost:" + this.webServer.getPort() + path)); + HttpResponse response = httpClient.execute(new HttpGet("http://localhost:" + port + path)); response.getEntity().getContent().close(); return response; }