Add support for gracefully shutting down the web server
This commit adds support for gracefully shutting down the embedded web server. When a grace period is configured (server.shutdown.grace-period), upon shutdown, the web server will no longer permit new requests and will wait for up to the grace period for active requests to complete. Closes gh-4657
This commit is contained in:
@@ -36,6 +36,7 @@ import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||
import org.springframework.boot.convert.DurationUnit;
|
||||
import org.springframework.boot.web.server.Compression;
|
||||
import org.springframework.boot.web.server.Http2;
|
||||
import org.springframework.boot.web.server.Shutdown;
|
||||
import org.springframework.boot.web.server.Ssl;
|
||||
import org.springframework.boot.web.servlet.server.Encoding;
|
||||
import org.springframework.boot.web.servlet.server.Jsp;
|
||||
@@ -114,6 +115,9 @@ public class ServerProperties {
|
||||
@NestedConfigurationProperty
|
||||
private final Http2 http2 = new Http2();
|
||||
|
||||
@NestedConfigurationProperty
|
||||
private final Shutdown shutdown = new Shutdown();
|
||||
|
||||
private final Servlet servlet = new Servlet();
|
||||
|
||||
private final Tomcat tomcat = new Tomcat();
|
||||
@@ -199,6 +203,10 @@ public class ServerProperties {
|
||||
return this.http2;
|
||||
}
|
||||
|
||||
public Shutdown getShutdown() {
|
||||
return this.shutdown;
|
||||
}
|
||||
|
||||
public Servlet getServlet() {
|
||||
return this.servlet;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2020 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.
|
||||
@@ -52,6 +52,7 @@ public class ReactiveWebServerFactoryCustomizer
|
||||
map.from(this.serverProperties::getSsl).to(factory::setSsl);
|
||||
map.from(this.serverProperties::getCompression).to(factory::setCompression);
|
||||
map.from(this.serverProperties::getHttp2).to(factory::setHttp2);
|
||||
map.from(this.serverProperties.getShutdown()).to(factory::setShutdown);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2020 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.
|
||||
@@ -60,6 +60,7 @@ public class ServletWebServerFactoryCustomizer
|
||||
map.from(this.serverProperties::getHttp2).to(factory::setHttp2);
|
||||
map.from(this.serverProperties::getServerHeader).to(factory::setServerHeader);
|
||||
map.from(this.serverProperties.getServlet()::getContextParameters).to(factory::setInitParameters);
|
||||
map.from(this.serverProperties.getShutdown()).to(factory::setShutdown);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2020 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.
|
||||
@@ -17,14 +17,18 @@
|
||||
package org.springframework.boot.autoconfigure.web.reactive;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.time.Duration;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
import org.springframework.boot.web.reactive.server.ConfigurableReactiveWebServerFactory;
|
||||
import org.springframework.boot.web.server.Shutdown;
|
||||
import org.springframework.boot.web.server.Ssl;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
@@ -71,4 +75,14 @@ class ReactiveWebServerFactoryCustomizerTests {
|
||||
verify(factory).setSsl(ssl);
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenGracePeriodPropertyIsSetThenGracePeriodIsCustomized() {
|
||||
this.properties.getShutdown().setGracePeriod(Duration.ofSeconds(30));
|
||||
ConfigurableReactiveWebServerFactory factory = mock(ConfigurableReactiveWebServerFactory.class);
|
||||
this.customizer.customize(factory);
|
||||
ArgumentCaptor<Shutdown> shutdownCaptor = ArgumentCaptor.forClass(Shutdown.class);
|
||||
verify(factory).setShutdown(shutdownCaptor.capture());
|
||||
assertThat(shutdownCaptor.getValue().getGracePeriod()).isEqualTo(Duration.ofSeconds(30));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.boot.autoconfigure.web.servlet;
|
||||
|
||||
import java.io.File;
|
||||
import java.time.Duration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -29,6 +30,7 @@ import org.springframework.boot.context.properties.bind.Bindable;
|
||||
import org.springframework.boot.context.properties.bind.Binder;
|
||||
import org.springframework.boot.context.properties.source.ConfigurationPropertySource;
|
||||
import org.springframework.boot.context.properties.source.MapConfigurationPropertySource;
|
||||
import org.springframework.boot.web.server.Shutdown;
|
||||
import org.springframework.boot.web.server.Ssl;
|
||||
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
|
||||
import org.springframework.boot.web.servlet.server.Jsp;
|
||||
@@ -154,6 +156,18 @@ class ServletWebServerFactoryCustomizerTests {
|
||||
assertThat(sessionCaptor.getValue().getStoreDir()).isEqualTo(new File("myfolder"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenGracePeriodPropertyIsSetThenGracePeriodIsCustomized() {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("server.shutdown.grace-period", "30s");
|
||||
bindProperties(map);
|
||||
ConfigurableServletWebServerFactory factory = mock(ConfigurableServletWebServerFactory.class);
|
||||
this.customizer.customize(factory);
|
||||
ArgumentCaptor<Shutdown> shutdownCaptor = ArgumentCaptor.forClass(Shutdown.class);
|
||||
verify(factory).setShutdown(shutdownCaptor.capture());
|
||||
assertThat(shutdownCaptor.getValue().getGracePeriod()).isEqualTo(Duration.ofSeconds(30));
|
||||
}
|
||||
|
||||
private void bindProperties(Map<String, String> map) {
|
||||
ConfigurationPropertySource source = new MapConfigurationPropertySource(map);
|
||||
new Binder(source).bind("server", Bindable.ofInstance(this.properties));
|
||||
|
||||
Reference in New Issue
Block a user