Commit 0bb68771 authored by Andy Wilkinson's avatar Andy Wilkinson

Auto-configure a lifecycle processor with configurable timeout

Closes gh-21347
parent 24089812
......@@ -63,9 +63,9 @@ public class DocumentConfigurationProperties extends AbstractTask {
builder.addSection("core")
.withKeyPrefixes("debug", "trace", "logging", "spring.aop", "spring.application",
"spring.autoconfigure", "spring.banner", "spring.beaninfo", "spring.codec", "spring.config",
"spring.info", "spring.jmx", "spring.main", "spring.messages", "spring.pid", "spring.profiles",
"spring.quartz", "spring.reactor", "spring.task", "spring.mandatory-file-encoding", "info",
"spring.output.ansi.enabled")
"spring.info", "spring.jmx", "spring.lifecycle", "spring.main", "spring.messages", "spring.pid",
"spring.profiles", "spring.quartz", "spring.reactor", "spring.task",
"spring.mandatory-file-encoding", "info", "spring.output.ansi.enabled")
.addSection("mail").withKeyPrefixes("spring.mail", "spring.sendgrid").addSection("cache")
.withKeyPrefixes("spring.cache").addSection("server").withKeyPrefixes("server").addSection("web")
.withKeyPrefixes("spring.hateoas", "spring.http", "spring.servlet", "spring.jersey", "spring.mvc",
......
/*
* 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.context;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.DefaultLifecycleProcessor;
/**
* {@link EnableAutoConfiguration Auto-configuration} relating to the application
* context's lifecycle.
*
* @author Andy Wilkinson
* @since 2.3.0
*/
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(LifecycleProperties.class)
public class LifecycleAutoConfiguration {
@Bean(name = AbstractApplicationContext.LIFECYCLE_PROCESSOR_BEAN_NAME)
@ConditionalOnMissingBean(name = AbstractApplicationContext.LIFECYCLE_PROCESSOR_BEAN_NAME)
public DefaultLifecycleProcessor defaultLifecycleProcessor(LifecycleProperties properties) {
DefaultLifecycleProcessor lifecycleProcessor = new DefaultLifecycleProcessor();
lifecycleProcessor.setTimeoutPerShutdownPhase(properties.getTimeoutPerShutdownPhase().toMillis());
return lifecycleProcessor;
}
}
/*
* 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.context;
import java.time.Duration;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Configuration properties for lifecycle processing.
*
* @author Andy Wilkinson
* @since 2.3.0
*/
@ConfigurationProperties(prefix = "spring.lifecycle")
public class LifecycleProperties {
/**
* Timeout for the shutdown of any phase (group of SmartLifecycle beans with the same
* 'phase' value).
*/
private Duration timeoutPerShutdownPhase = Duration.ofSeconds(30);
public Duration getTimeoutPerShutdownPhase() {
return this.timeoutPerShutdownPhase;
}
public void setTimeoutPerShutdownPhase(Duration timeoutPerShutdownPhase) {
this.timeoutPerShutdownPhase = timeoutPerShutdownPhase;
}
}
......@@ -26,6 +26,7 @@ org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
......
/*
* 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.context;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.DefaultLifecycleProcessor;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link LifecycleAutoConfiguration}.
*
* @author Andy Wilkinson
*/
public class LifecycleAutoConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(LifecycleAutoConfiguration.class));
@Test
void lifecycleProcessorIsConfiguredWithDefaultTimeout() {
this.contextRunner.run((context) -> {
assertThat(context).hasBean(AbstractApplicationContext.LIFECYCLE_PROCESSOR_BEAN_NAME);
Object processor = context.getBean(AbstractApplicationContext.LIFECYCLE_PROCESSOR_BEAN_NAME);
assertThat(processor).extracting("timeoutPerShutdownPhase").isEqualTo(30000L);
});
}
@Test
void lifecycleProcessorIsConfiguredWithCustomDefaultTimeout() {
this.contextRunner.withPropertyValues("spring.lifecycle.timeout-per-shutdown-phase=15s").run((context) -> {
assertThat(context).hasBean(AbstractApplicationContext.LIFECYCLE_PROCESSOR_BEAN_NAME);
Object processor = context.getBean(AbstractApplicationContext.LIFECYCLE_PROCESSOR_BEAN_NAME);
assertThat(processor).extracting("timeoutPerShutdownPhase").isEqualTo(15000L);
});
}
@Test
void whenUserDefinesALifecycleProcessorBeanThenTheAutoConfigurationBacksOff() {
this.contextRunner.withUserConfiguration(LifecycleProcessorConfiguration.class).run((context) -> {
assertThat(context).hasBean(AbstractApplicationContext.LIFECYCLE_PROCESSOR_BEAN_NAME);
Object processor = context.getBean(AbstractApplicationContext.LIFECYCLE_PROCESSOR_BEAN_NAME);
assertThat(processor).extracting("timeoutPerShutdownPhase").isEqualTo(5000L);
});
}
@Configuration(proxyBeanMethods = false)
static class LifecycleProcessorConfiguration {
@Bean(name = AbstractApplicationContext.LIFECYCLE_PROCESSOR_BEAN_NAME)
DefaultLifecycleProcessor customLifecycleProcessor() {
DefaultLifecycleProcessor processor = new DefaultLifecycleProcessor();
processor.setTimeoutPerShutdownPhase(5000);
return processor;
}
}
}
......@@ -3160,6 +3160,13 @@ To enable graceful shutdown, configure the configprop:server.shutdown[] property
server.shutdown=graceful
----
To configure the timeout period, configure the configprop:spring.lifecycle.timeout-per-shutdown-phase[] property, as shown in the following example:
[source,properties,indent=0,configprops]
----
spring.lifecycle.timeout-per-shutdown-phase=20s
----
[[boot-features-rsocket]]
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment