diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowReactiveWebServerFactory.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowReactiveWebServerFactory.java index 9faacf0992..27348dd0b1 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowReactiveWebServerFactory.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowReactiveWebServerFactory.java @@ -141,6 +141,7 @@ public class UndertowReactiveWebServerFactory extends AbstractReactiveWebServerF else { builder.addHttpListener(port, getListenAddress()); } + builder.setServerOption(UndertowOptions.SHUTDOWN_TIMEOUT, 0); for (UndertowBuilderCustomizer customizer : this.builderCustomizers) { customizer.customize(builder); } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowServletWebServerFactory.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowServletWebServerFactory.java index 161c2d1f52..dc5813bb04 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowServletWebServerFactory.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowServletWebServerFactory.java @@ -241,6 +241,7 @@ public class UndertowServletWebServerFactory extends AbstractServletWebServerFac else { builder.addHttpListener(port, getListenAddress()); } + builder.setServerOption(UndertowOptions.SHUTDOWN_TIMEOUT, 0); for (UndertowBuilderCustomizer customizer : this.builderCustomizers) { customizer.customize(builder); } 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 6bad7271c3..6f73447206 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 @@ -25,6 +25,7 @@ import java.time.Duration; import java.util.Arrays; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; +import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Future; @@ -423,6 +424,25 @@ public abstract class AbstractReactiveWebServerFactoryTests { assertThat(responseLatch.await(5, TimeUnit.SECONDS)).isTrue(); } + @Test + void whenARequestIsActiveThenStopWillComplete() throws InterruptedException, BrokenBarrierException { + AbstractReactiveWebServerFactory factory = getFactory(); + BlockingHandler blockingHandler = new BlockingHandler(); + this.webServer = factory.getWebServer(blockingHandler); + this.webServer.start(); + Mono> request = getWebClient(this.webServer.getPort()).build().get().retrieve() + .toBodilessEntity(); + AtomicReference> responseReference = new AtomicReference<>(); + CountDownLatch responseLatch = new CountDownLatch(1); + request.subscribe((response) -> { + responseReference.set(response); + responseLatch.countDown(); + }); + blockingHandler.awaitQueue(); + this.webServer.stop(); + blockingHandler.completeOne(); + } + protected WebClient prepareCompressionTest() { Compression compression = new Compression(); compression.setEnabled(true); 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 8f37a1fa93..b7e0042516 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 @@ -1147,6 +1147,25 @@ public abstract class AbstractServletWebServerFactoryTests { assertThat(request.get(30, TimeUnit.SECONDS)).isInstanceOf(HttpResponse.class); } + @Test + void whenARequestIsActiveThenStopWillComplete() throws InterruptedException, BrokenBarrierException { + AbstractServletWebServerFactory factory = getFactory(); + BlockingServlet blockingServlet = new BlockingServlet(); + this.webServer = factory + .getWebServer((context) -> context.addServlet("blockingServlet", blockingServlet).addMapping("/")); + this.webServer.start(); + int port = this.webServer.getPort(); + initiateGetRequest(port, "/"); + blockingServlet.awaitQueue(); + this.webServer.stop(); + try { + blockingServlet.admitOne(); + } + catch (RuntimeException ex) { + + } + } + protected Future initiateGracefulShutdown() { RunnableFuture future = new FutureTask(() -> this.webServer.shutDownGracefully()); new Thread(future).start(); @@ -1524,7 +1543,10 @@ public abstract class AbstractServletWebServerFactoryTests { public void admitOne() { try { - this.barriers.take().await(); + CyclicBarrier barrier = this.barriers.take(); + if (!barrier.isBroken()) { + barrier.await(); + } } catch (InterruptedException ex) { Thread.currentThread().interrupt();