Skip to content

Commit fa49dfc

Browse files
committed
Add support for task scheduling shutdown related properties
See gh-15951
1 parent d2cbf08 commit fa49dfc

File tree

5 files changed

+119
-12
lines changed

5 files changed

+119
-12
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskSchedulingAutoConfiguration.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2018 the original author or authors.
2+
* Copyright 2012-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@
2323
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
2424
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
2525
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
26+
import org.springframework.boot.autoconfigure.task.TaskSchedulingProperties.Shutdown;
2627
import org.springframework.boot.context.properties.EnableConfigurationProperties;
2728
import org.springframework.boot.task.TaskSchedulerBuilder;
2829
import org.springframework.boot.task.TaskSchedulerCustomizer;
@@ -58,6 +59,9 @@ public TaskSchedulerBuilder taskSchedulerBuilder(TaskSchedulingProperties proper
5859
ObjectProvider<TaskSchedulerCustomizer> taskSchedulerCustomizers) {
5960
TaskSchedulerBuilder builder = new TaskSchedulerBuilder();
6061
builder = builder.poolSize(properties.getPool().getSize());
62+
Shutdown shutdown = properties.getShutdown();
63+
builder = builder.awaitTermination(shutdown.isAwaitTermination());
64+
builder = builder.awaitTerminationPeriod(shutdown.getAwaitTerminationPeriod());
6165
builder = builder.threadNamePrefix(properties.getThreadNamePrefix());
6266
builder = builder.customizers(taskSchedulerCustomizers);
6367
return builder;

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskSchedulingProperties.java

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2018 the original author or authors.
2+
* Copyright 2012-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,6 +16,8 @@
1616

1717
package org.springframework.boot.autoconfigure.task;
1818

19+
import java.time.Duration;
20+
1921
import org.springframework.boot.context.properties.ConfigurationProperties;
2022

2123
/**
@@ -29,6 +31,8 @@ public class TaskSchedulingProperties {
2931

3032
private final Pool pool = new Pool();
3133

34+
private final Shutdown shutdown = new Shutdown();
35+
3236
/**
3337
* Prefix to use for the names of newly created threads.
3438
*/
@@ -38,6 +42,10 @@ public Pool getPool() {
3842
return this.pool;
3943
}
4044

45+
public Shutdown getShutdown() {
46+
return this.shutdown;
47+
}
48+
4149
public String getThreadNamePrefix() {
4250
return this.threadNamePrefix;
4351
}
@@ -63,4 +71,34 @@ public void setSize(int size) {
6371

6472
}
6573

74+
public static class Shutdown {
75+
76+
/**
77+
* Whether the executor should wait for scheduled tasks to complete on shutdown.
78+
*/
79+
private boolean awaitTermination;
80+
81+
/**
82+
* Maximum time the executor should wait for remaining tasks to complete.
83+
*/
84+
private Duration awaitTerminationPeriod;
85+
86+
public boolean isAwaitTermination() {
87+
return this.awaitTermination;
88+
}
89+
90+
public void setAwaitTermination(boolean awaitTermination) {
91+
this.awaitTermination = awaitTermination;
92+
}
93+
94+
public Duration getAwaitTerminationPeriod() {
95+
return this.awaitTerminationPeriod;
96+
}
97+
98+
public void setAwaitTerminationPeriod(Duration awaitTerminationPeriod) {
99+
this.awaitTerminationPeriod = awaitTerminationPeriod;
100+
}
101+
102+
}
103+
66104
}

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/task/TaskSchedulingAutoConfigurationTests.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2018 the original author or authors.
2+
* Copyright 2012-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -59,11 +59,18 @@ public void noSchedulingDoesNotExposeTaskScheduler() {
5959
public void enableSchedulingWithNoTaskExecutorAutoConfiguresOne() {
6060
this.contextRunner
6161
.withPropertyValues(
62+
"spring.task.scheduling.shutdown.await-termination=true",
63+
"spring.task.scheduling.shutdown.await-termination-period=30s",
6264
"spring.task.scheduling.thread-name-prefix=scheduling-test-")
6365
.withUserConfiguration(SchedulingConfiguration.class).run((context) -> {
6466
assertThat(context).hasSingleBean(TaskExecutor.class);
67+
TaskExecutor taskExecutor = context.getBean(TaskExecutor.class);
6568
TestBean bean = context.getBean(TestBean.class);
6669
Thread.sleep(15);
70+
assertThat(taskExecutor).hasFieldOrPropertyWithValue(
71+
"waitForTasksToCompleteOnShutdown", true);
72+
assertThat(taskExecutor)
73+
.hasFieldOrPropertyWithValue("awaitTerminationSeconds", 30);
6774
assertThat(bean.threadNames)
6875
.allMatch((name) -> name.contains("scheduling-test-"));
6976
});

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/TaskSchedulerBuilder.java

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2018 the original author or authors.
2+
* Copyright 2012-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.boot.task;
1818

19+
import java.time.Duration;
1920
import java.util.Arrays;
2021
import java.util.Collections;
2122
import java.util.LinkedHashSet;
@@ -42,19 +43,28 @@ public class TaskSchedulerBuilder {
4243

4344
private final Integer poolSize;
4445

46+
private final Boolean awaitTermination;
47+
48+
private final Duration awaitTerminationPeriod;
49+
4550
private final String threadNamePrefix;
4651

4752
private final Set<TaskSchedulerCustomizer> customizers;
4853

4954
public TaskSchedulerBuilder() {
5055
this.poolSize = null;
56+
this.awaitTermination = null;
57+
this.awaitTerminationPeriod = null;
5158
this.threadNamePrefix = null;
5259
this.customizers = null;
5360
}
5461

55-
public TaskSchedulerBuilder(Integer poolSize, String threadNamePrefix,
62+
public TaskSchedulerBuilder(Integer poolSize, Boolean awaitTermination,
63+
Duration awaitTerminationPeriod, String threadNamePrefix,
5664
Set<TaskSchedulerCustomizer> taskSchedulerCustomizers) {
5765
this.poolSize = poolSize;
66+
this.awaitTermination = awaitTermination;
67+
this.awaitTerminationPeriod = awaitTerminationPeriod;
5868
this.threadNamePrefix = threadNamePrefix;
5969
this.customizers = taskSchedulerCustomizers;
6070
}
@@ -65,8 +75,35 @@ public TaskSchedulerBuilder(Integer poolSize, String threadNamePrefix,
6575
* @return a new builder instance
6676
*/
6777
public TaskSchedulerBuilder poolSize(int poolSize) {
68-
return new TaskSchedulerBuilder(poolSize, this.threadNamePrefix,
69-
this.customizers);
78+
return new TaskSchedulerBuilder(poolSize, this.awaitTermination,
79+
this.awaitTerminationPeriod, this.threadNamePrefix, this.customizers);
80+
}
81+
82+
/**
83+
* Set whether the executor should wait for scheduled tasks to complete on shutdown,
84+
* not interrupting running tasks and executing all tasks in the queue.
85+
* @param awaitTermination whether the executor needs to wait for the tasks to
86+
* complete on shutdown
87+
* @return a new builder instance
88+
* @see #awaitTerminationPeriod(Duration)
89+
*/
90+
public TaskSchedulerBuilder awaitTermination(boolean awaitTermination) {
91+
return new TaskSchedulerBuilder(this.poolSize, awaitTermination,
92+
this.awaitTerminationPeriod, this.threadNamePrefix, this.customizers);
93+
}
94+
95+
/**
96+
* Set the maximum time the executor is supposed to block on shutdown. When set, the
97+
* executor blocks on shutdown in order to wait for remaining tasks to complete their
98+
* execution before the rest of the container continues to shut down. This is
99+
* particularly useful if your remaining tasks are likely to need access to other
100+
* resources that are also managed by the container.
101+
* @param awaitTerminationPeriod the await termination period to set
102+
* @return a new builder instance
103+
*/
104+
public TaskSchedulerBuilder awaitTerminationPeriod(Duration awaitTerminationPeriod) {
105+
return new TaskSchedulerBuilder(this.poolSize, this.awaitTermination,
106+
awaitTerminationPeriod, this.threadNamePrefix, this.customizers);
70107
}
71108

72109
/**
@@ -75,8 +112,8 @@ public TaskSchedulerBuilder poolSize(int poolSize) {
75112
* @return a new builder instance
76113
*/
77114
public TaskSchedulerBuilder threadNamePrefix(String threadNamePrefix) {
78-
return new TaskSchedulerBuilder(this.poolSize, threadNamePrefix,
79-
this.customizers);
115+
return new TaskSchedulerBuilder(this.poolSize, this.awaitTermination,
116+
this.awaitTerminationPeriod, threadNamePrefix, this.customizers);
80117
}
81118

82119
/**
@@ -105,7 +142,8 @@ public TaskSchedulerBuilder customizers(TaskSchedulerCustomizer... customizers)
105142
public TaskSchedulerBuilder customizers(
106143
Iterable<TaskSchedulerCustomizer> customizers) {
107144
Assert.notNull(customizers, "Customizers must not be null");
108-
return new TaskSchedulerBuilder(this.poolSize, this.threadNamePrefix,
145+
return new TaskSchedulerBuilder(this.poolSize, this.awaitTermination,
146+
this.awaitTerminationPeriod, this.threadNamePrefix,
109147
append(null, customizers));
110148
}
111149

@@ -134,7 +172,8 @@ public TaskSchedulerBuilder additionalCustomizers(
134172
public TaskSchedulerBuilder additionalCustomizers(
135173
Iterable<TaskSchedulerCustomizer> customizers) {
136174
Assert.notNull(customizers, "Customizers must not be null");
137-
return new TaskSchedulerBuilder(this.poolSize, this.threadNamePrefix,
175+
return new TaskSchedulerBuilder(this.poolSize, this.awaitTermination,
176+
this.awaitTerminationPeriod, this.threadNamePrefix,
138177
append(this.customizers, customizers));
139178
}
140179

@@ -158,6 +197,10 @@ public ThreadPoolTaskScheduler build() {
158197
public <T extends ThreadPoolTaskScheduler> T configure(T taskScheduler) {
159198
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
160199
map.from(this.poolSize).to(taskScheduler::setPoolSize);
200+
map.from(this.awaitTermination)
201+
.to(taskScheduler::setWaitForTasksToCompleteOnShutdown);
202+
map.from(this.awaitTerminationPeriod).asInt(Duration::getSeconds)
203+
.to(taskScheduler::setAwaitTerminationSeconds);
161204
map.from(this.threadNamePrefix).to(taskScheduler::setThreadNamePrefix);
162205
if (!CollectionUtils.isEmpty(this.customizers)) {
163206
this.customizers.forEach((customizer) -> customizer.customize(taskScheduler));

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/task/TaskSchedulerBuilderTests.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2018 the original author or authors.
2+
* Copyright 2012-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.boot.task;
1818

19+
import java.time.Duration;
1920
import java.util.Collections;
2021
import java.util.Set;
2122

@@ -45,6 +46,20 @@ public void poolSettingsShouldApply() {
4546
assertThat(scheduler.getPoolSize()).isEqualTo(4);
4647
}
4748

49+
@Test
50+
public void awaitTerminationShouldApply() {
51+
ThreadPoolTaskScheduler executor = this.builder.awaitTermination(true).build();
52+
assertThat(executor)
53+
.hasFieldOrPropertyWithValue("waitForTasksToCompleteOnShutdown", true);
54+
}
55+
56+
@Test
57+
public void awaitTerminationPeriodShouldApply() {
58+
ThreadPoolTaskScheduler executor = this.builder
59+
.awaitTerminationPeriod(Duration.ofMinutes(1)).build();
60+
assertThat(executor).hasFieldOrPropertyWithValue("awaitTerminationSeconds", 60);
61+
}
62+
4863
@Test
4964
public void threadNamePrefixShouldApply() {
5065
ThreadPoolTaskScheduler scheduler = this.builder.threadNamePrefix("test-")

0 commit comments

Comments
 (0)