Skip to content

Commit 0bb6877

Browse files
committed
Auto-configure a lifecycle processor with configurable timeout
Closes gh-21347
1 parent 2408981 commit 0bb6877

File tree

6 files changed

+182
-3
lines changed

6 files changed

+182
-3
lines changed

buildSrc/src/main/java/org/springframework/boot/build/context/properties/DocumentConfigurationProperties.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,9 @@ void documentConfigurationProperties() throws IOException {
6363
builder.addSection("core")
6464
.withKeyPrefixes("debug", "trace", "logging", "spring.aop", "spring.application",
6565
"spring.autoconfigure", "spring.banner", "spring.beaninfo", "spring.codec", "spring.config",
66-
"spring.info", "spring.jmx", "spring.main", "spring.messages", "spring.pid", "spring.profiles",
67-
"spring.quartz", "spring.reactor", "spring.task", "spring.mandatory-file-encoding", "info",
68-
"spring.output.ansi.enabled")
66+
"spring.info", "spring.jmx", "spring.lifecycle", "spring.main", "spring.messages", "spring.pid",
67+
"spring.profiles", "spring.quartz", "spring.reactor", "spring.task",
68+
"spring.mandatory-file-encoding", "info", "spring.output.ansi.enabled")
6969
.addSection("mail").withKeyPrefixes("spring.mail", "spring.sendgrid").addSection("cache")
7070
.withKeyPrefixes("spring.cache").addSection("server").withKeyPrefixes("server").addSection("web")
7171
.withKeyPrefixes("spring.hateoas", "spring.http", "spring.servlet", "spring.jersey", "spring.mvc",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2012-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.context;
18+
19+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
20+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
21+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
22+
import org.springframework.context.annotation.Bean;
23+
import org.springframework.context.annotation.Configuration;
24+
import org.springframework.context.support.AbstractApplicationContext;
25+
import org.springframework.context.support.DefaultLifecycleProcessor;
26+
27+
/**
28+
* {@link EnableAutoConfiguration Auto-configuration} relating to the application
29+
* context's lifecycle.
30+
*
31+
* @author Andy Wilkinson
32+
* @since 2.3.0
33+
*/
34+
@Configuration(proxyBeanMethods = false)
35+
@EnableConfigurationProperties(LifecycleProperties.class)
36+
public class LifecycleAutoConfiguration {
37+
38+
@Bean(name = AbstractApplicationContext.LIFECYCLE_PROCESSOR_BEAN_NAME)
39+
@ConditionalOnMissingBean(name = AbstractApplicationContext.LIFECYCLE_PROCESSOR_BEAN_NAME)
40+
public DefaultLifecycleProcessor defaultLifecycleProcessor(LifecycleProperties properties) {
41+
DefaultLifecycleProcessor lifecycleProcessor = new DefaultLifecycleProcessor();
42+
lifecycleProcessor.setTimeoutPerShutdownPhase(properties.getTimeoutPerShutdownPhase().toMillis());
43+
return lifecycleProcessor;
44+
}
45+
46+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2012-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.context;
18+
19+
import java.time.Duration;
20+
21+
import org.springframework.boot.context.properties.ConfigurationProperties;
22+
23+
/**
24+
* Configuration properties for lifecycle processing.
25+
*
26+
* @author Andy Wilkinson
27+
* @since 2.3.0
28+
*/
29+
@ConfigurationProperties(prefix = "spring.lifecycle")
30+
public class LifecycleProperties {
31+
32+
/**
33+
* Timeout for the shutdown of any phase (group of SmartLifecycle beans with the same
34+
* 'phase' value).
35+
*/
36+
private Duration timeoutPerShutdownPhase = Duration.ofSeconds(30);
37+
38+
public Duration getTimeoutPerShutdownPhase() {
39+
return this.timeoutPerShutdownPhase;
40+
}
41+
42+
public void setTimeoutPerShutdownPhase(Duration timeoutPerShutdownPhase) {
43+
this.timeoutPerShutdownPhase = timeoutPerShutdownPhase;
44+
}
45+
46+
}

spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
2626
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
2727
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
2828
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
29+
org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration,\
2930
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
3031
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
3132
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Copyright 2012-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.context;
18+
19+
import org.junit.jupiter.api.Test;
20+
21+
import org.springframework.boot.autoconfigure.AutoConfigurations;
22+
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
23+
import org.springframework.context.annotation.Bean;
24+
import org.springframework.context.annotation.Configuration;
25+
import org.springframework.context.support.AbstractApplicationContext;
26+
import org.springframework.context.support.DefaultLifecycleProcessor;
27+
28+
import static org.assertj.core.api.Assertions.assertThat;
29+
30+
/**
31+
* Tests for {@link LifecycleAutoConfiguration}.
32+
*
33+
* @author Andy Wilkinson
34+
*/
35+
public class LifecycleAutoConfigurationTests {
36+
37+
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
38+
.withConfiguration(AutoConfigurations.of(LifecycleAutoConfiguration.class));
39+
40+
@Test
41+
void lifecycleProcessorIsConfiguredWithDefaultTimeout() {
42+
this.contextRunner.run((context) -> {
43+
assertThat(context).hasBean(AbstractApplicationContext.LIFECYCLE_PROCESSOR_BEAN_NAME);
44+
Object processor = context.getBean(AbstractApplicationContext.LIFECYCLE_PROCESSOR_BEAN_NAME);
45+
assertThat(processor).extracting("timeoutPerShutdownPhase").isEqualTo(30000L);
46+
});
47+
}
48+
49+
@Test
50+
void lifecycleProcessorIsConfiguredWithCustomDefaultTimeout() {
51+
this.contextRunner.withPropertyValues("spring.lifecycle.timeout-per-shutdown-phase=15s").run((context) -> {
52+
assertThat(context).hasBean(AbstractApplicationContext.LIFECYCLE_PROCESSOR_BEAN_NAME);
53+
Object processor = context.getBean(AbstractApplicationContext.LIFECYCLE_PROCESSOR_BEAN_NAME);
54+
assertThat(processor).extracting("timeoutPerShutdownPhase").isEqualTo(15000L);
55+
});
56+
}
57+
58+
@Test
59+
void whenUserDefinesALifecycleProcessorBeanThenTheAutoConfigurationBacksOff() {
60+
this.contextRunner.withUserConfiguration(LifecycleProcessorConfiguration.class).run((context) -> {
61+
assertThat(context).hasBean(AbstractApplicationContext.LIFECYCLE_PROCESSOR_BEAN_NAME);
62+
Object processor = context.getBean(AbstractApplicationContext.LIFECYCLE_PROCESSOR_BEAN_NAME);
63+
assertThat(processor).extracting("timeoutPerShutdownPhase").isEqualTo(5000L);
64+
});
65+
}
66+
67+
@Configuration(proxyBeanMethods = false)
68+
static class LifecycleProcessorConfiguration {
69+
70+
@Bean(name = AbstractApplicationContext.LIFECYCLE_PROCESSOR_BEAN_NAME)
71+
DefaultLifecycleProcessor customLifecycleProcessor() {
72+
DefaultLifecycleProcessor processor = new DefaultLifecycleProcessor();
73+
processor.setTimeoutPerShutdownPhase(5000);
74+
return processor;
75+
}
76+
77+
}
78+
79+
}

spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3160,6 +3160,13 @@ To enable graceful shutdown, configure the configprop:server.shutdown[] property
31603160
server.shutdown=graceful
31613161
----
31623162

3163+
To configure the timeout period, configure the configprop:spring.lifecycle.timeout-per-shutdown-phase[] property, as shown in the following example:
3164+
3165+
[source,properties,indent=0,configprops]
3166+
----
3167+
spring.lifecycle.timeout-per-shutdown-phase=20s
3168+
----
3169+
31633170

31643171

31653172
[[boot-features-rsocket]]

0 commit comments

Comments
 (0)