Improve graceful shutdown documentation to remove ambiguity

Closes gh-40108
This commit is contained in:
Phillip Webb
2024-05-20 20:31:40 -07:00
parent f5f02d6df1
commit f743dc82fc
6 changed files with 75 additions and 5 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -268,6 +268,15 @@ public class JettyWebServer implements WebServer {
return 0;
}
/**
* Initiates a graceful shutdown of the Jetty web server. Handling of new requests is
* prevented and the given {@code callback} is invoked at the end of the attempt. The
* attempt can be explicitly ended by invoking {@link #stop}.
* <p>
* Once shutdown has been initiated Jetty will reject any new connections. Requests on
* existing connections will be accepted, however, a {@code Connection: close} header
* will be returned in the response.
*/
@Override
public void shutDownGracefully(GracefulShutdownCallback callback) {
if (this.gracefulShutdown == null) {

View File

@@ -157,6 +157,14 @@ public class NettyWebServer implements WebServer {
return false;
}
/**
* Initiates a graceful shutdown of the Netty web server. Handling of new requests is
* prevented and the given {@code callback} is invoked at the end of the attempt. The
* attempt can be explicitly ended by invoking {@link #stop}.
* <p>
* Once shutdown has been initiated Netty will reject any new connections. Requests +
* on existing idle connections will also be rejected.
*/
@Override
public void shutDownGracefully(GracefulShutdownCallback callback) {
if (this.gracefulShutdown == null) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -383,6 +383,14 @@ public class TomcatWebServer implements WebServer {
return this.tomcat;
}
/**
* Initiates a graceful shutdown of the Tomcat web server. Handling of new requests is
* prevented and the given {@code callback} is invoked at the end of the attempt. The
* attempt can be explicitly ended by invoking {@link #stop}.
* <p>
* Once shutdown has been initiated Tomcat will reject any new connections. Requests
* on existing idle connections will also be rejected.
*/
@Override
public void shutDownGracefully(GracefulShutdownCallback callback) {
if (this.gracefulShutdown == null) {

View File

@@ -289,6 +289,14 @@ public class UndertowWebServer implements WebServer {
return ports.get(0).getNumber();
}
/**
* Initiates a graceful shutdown of the Undertow web server. Handling of new requests
* is prevented and the given {@code callback} is invoked at the end of the attempt.
* The attempt can be explicitly ended by invoking {@link #stop}.
* <p>
* Once shutdown has been initiated Undertow will return an {@code HTTP 503} response
* for any new or existing connections.
*/
@Override
public void shutDownGracefully(GracefulShutdownCallback callback) {
if (this.gracefulShutdown == null) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -36,6 +36,8 @@ import io.undertow.Undertow.Builder;
import io.undertow.servlet.api.DeploymentInfo;
import io.undertow.servlet.api.ServletContainer;
import jakarta.servlet.ServletRegistration.Dynamic;
import org.apache.hc.client5.http.classic.HttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.core5.http.HttpResponse;
import org.apache.jasper.servlet.JspServlet;
import org.awaitility.Awaitility;
@@ -211,6 +213,35 @@ class UndertowServletWebServerFactoryTests extends AbstractServletWebServerFacto
this.webServer.stop();
}
@Test
void whenServerIsShuttingDownARequestOnAnIdleConnectionAreRejectedWithServiceUnavailable() throws Exception {
AbstractServletWebServerFactory factory = getFactory();
factory.setShutdown(Shutdown.GRACEFUL);
BlockingServlet blockingServlet = new BlockingServlet();
this.webServer = factory.getWebServer((context) -> {
Dynamic registration = context.addServlet("blockingServlet", blockingServlet);
registration.addMapping("/blocking");
registration.setAsyncSupported(true);
});
HttpClient httpClient = HttpClients.createMinimal();
this.webServer.start();
int port = this.webServer.getPort();
Future<Object> keepAliveRequest = initiateGetRequest(httpClient, port, "/blocking");
blockingServlet.awaitQueue();
blockingServlet.admitOne();
assertThat(keepAliveRequest.get()).isInstanceOf(HttpResponse.class);
Future<Object> request = initiateGetRequest(port, "/blocking");
blockingServlet.awaitQueue();
this.webServer.shutDownGracefully((result) -> {
});
HttpResponse idleConnectionResponse = (HttpResponse) initiateGetRequest(httpClient, port, "/").get();
assertThat(idleConnectionResponse.getCode()).isEqualTo(503);
blockingServlet.admitOne();
Object response = request.get();
assertThat(response).isInstanceOf(HttpResponse.class);
this.webServer.stop();
}
private void testAccessLog(String prefix, String suffix, String expectedFile)
throws IOException, URISyntaxException {
UndertowServletWebServerFactory factory = getFactory();