Skip to content

Commit b7ea794

Browse files
committed
Add configuration property "spring.task.execution.pool.shutdown.accept-tasks-after-context-close"
ExecutorConfigurationSupport::setAcceptTasksAfterContextClose is introduced since Spring Framework 6.1
1 parent c4be302 commit b7ea794

File tree

5 files changed

+93
-37
lines changed

5 files changed

+93
-37
lines changed

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

+26-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2023 the original author or authors.
2+
* Copyright 2012-2024 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.
@@ -25,6 +25,7 @@
2525
*
2626
* @author Stephane Nicoll
2727
* @author Filip Hrisafov
28+
* @author Yanming Zhou
2829
* @since 2.1.0
2930
*/
3031
@ConfigurationProperties("spring.task.execution")
@@ -110,6 +111,8 @@ public static class Pool {
110111
*/
111112
private Duration keepAlive = Duration.ofSeconds(60);
112113

114+
private final Shutdown shutdown = new Shutdown();
115+
113116
public int getQueueCapacity() {
114117
return this.queueCapacity;
115118
}
@@ -150,6 +153,28 @@ public void setKeepAlive(Duration keepAlive) {
150153
this.keepAlive = keepAlive;
151154
}
152155

156+
public Shutdown getShutdown() {
157+
return this.shutdown;
158+
}
159+
160+
public static class Shutdown {
161+
162+
/**
163+
* Whether to accept further tasks after the application context close phase
164+
* has begun.
165+
*/
166+
private boolean acceptTasksAfterContextClose;
167+
168+
public boolean isAcceptTasksAfterContextClose() {
169+
return this.acceptTasksAfterContextClose;
170+
}
171+
172+
public void setAcceptTasksAfterContextClose(boolean acceptTasksAfterContextClose) {
173+
this.acceptTasksAfterContextClose = acceptTasksAfterContextClose;
174+
}
175+
176+
}
177+
153178
}
154179

155180
public static class Shutdown {

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2023 the original author or authors.
2+
* Copyright 2012-2024 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.
@@ -43,6 +43,7 @@
4343
*
4444
* @author Andy Wilkinson
4545
* @author Moritz Halbritter
46+
* @author Yanming Zhou
4647
*/
4748
class TaskExecutorConfigurations {
4849

@@ -119,6 +120,7 @@ ThreadPoolTaskExecutorBuilder threadPoolTaskExecutorBuilder(TaskExecutionPropert
119120
builder = builder.maxPoolSize(pool.getMaxSize());
120121
builder = builder.allowCoreThreadTimeOut(pool.isAllowCoreThreadTimeout());
121122
builder = builder.keepAlive(pool.getKeepAlive());
123+
builder = builder.acceptTasksAfterContextClose(pool.getShutdown().isAcceptTasksAfterContextClose());
122124
TaskExecutionProperties.Shutdown shutdown = properties.getShutdown();
123125
builder = builder.awaitTermination(shutdown.isAwaitTermination());
124126
builder = builder.awaitTerminationPeriod(shutdown.getAwaitTerminationPeriod());

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

+10-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2023 the original author or authors.
2+
* Copyright 2012-2024 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.
@@ -60,6 +60,7 @@
6060
* @author Stephane Nicoll
6161
* @author Camille Vienot
6262
* @author Moritz Halbritter
63+
* @author Yanming Zhou
6364
*/
6465
@ExtendWith(OutputCaptureExtension.class)
6566
@SuppressWarnings("removal")
@@ -124,19 +125,20 @@ void simpleAsyncTaskExecutorBuilderShouldReadProperties() {
124125

125126
@Test
126127
void threadPoolTaskExecutorBuilderShouldApplyCustomSettings() {
127-
this.contextRunner
128-
.withPropertyValues("spring.task.execution.pool.queue-capacity=10",
129-
"spring.task.execution.pool.core-size=2", "spring.task.execution.pool.max-size=4",
130-
"spring.task.execution.pool.allow-core-thread-timeout=true",
131-
"spring.task.execution.pool.keep-alive=5s", "spring.task.execution.shutdown.await-termination=true",
132-
"spring.task.execution.shutdown.await-termination-period=30s",
133-
"spring.task.execution.thread-name-prefix=mytest-")
128+
this.contextRunner.withPropertyValues("spring.task.execution.pool.queue-capacity=10",
129+
"spring.task.execution.pool.core-size=2", "spring.task.execution.pool.max-size=4",
130+
"spring.task.execution.pool.allow-core-thread-timeout=true", "spring.task.execution.pool.keep-alive=5s",
131+
"spring.task.execution.pool.shutdown.accept-tasks-after-context-close=true",
132+
"spring.task.execution.shutdown.await-termination=true",
133+
"spring.task.execution.shutdown.await-termination-period=30s",
134+
"spring.task.execution.thread-name-prefix=mytest-")
134135
.run(assertThreadPoolTaskExecutor((taskExecutor) -> {
135136
assertThat(taskExecutor).hasFieldOrPropertyWithValue("queueCapacity", 10);
136137
assertThat(taskExecutor.getCorePoolSize()).isEqualTo(2);
137138
assertThat(taskExecutor.getMaxPoolSize()).isEqualTo(4);
138139
assertThat(taskExecutor).hasFieldOrPropertyWithValue("allowCoreThreadTimeOut", true);
139140
assertThat(taskExecutor.getKeepAliveSeconds()).isEqualTo(5);
141+
assertThat(taskExecutor).hasFieldOrPropertyWithValue("acceptTasksAfterContextClose", true);
140142
assertThat(taskExecutor).hasFieldOrPropertyWithValue("waitForTasksToCompleteOnShutdown", true);
141143
assertThat(taskExecutor).hasFieldOrPropertyWithValue("awaitTerminationMillis", 30000L);
142144
assertThat(taskExecutor.getThreadNamePrefix()).isEqualTo("mytest-");

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

+46-26
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2023 the original author or authors.
2+
* Copyright 2012-2024 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.
@@ -40,6 +40,7 @@
4040
*
4141
* @author Stephane Nicoll
4242
* @author Filip Hrisafov
43+
* @author Yanming Zhou
4344
* @since 3.2.0
4445
*/
4546
public class ThreadPoolTaskExecutorBuilder {
@@ -54,6 +55,8 @@ public class ThreadPoolTaskExecutorBuilder {
5455

5556
private final Duration keepAlive;
5657

58+
private final Boolean acceptTasksAfterContextClose;
59+
5760
private final Boolean awaitTermination;
5861

5962
private final Duration awaitTerminationPeriod;
@@ -70,6 +73,7 @@ public ThreadPoolTaskExecutorBuilder() {
7073
this.maxPoolSize = null;
7174
this.allowCoreThreadTimeOut = null;
7275
this.keepAlive = null;
76+
this.acceptTasksAfterContextClose = null;
7377
this.awaitTermination = null;
7478
this.awaitTerminationPeriod = null;
7579
this.threadNamePrefix = null;
@@ -78,14 +82,15 @@ public ThreadPoolTaskExecutorBuilder() {
7882
}
7983

8084
private ThreadPoolTaskExecutorBuilder(Integer queueCapacity, Integer corePoolSize, Integer maxPoolSize,
81-
Boolean allowCoreThreadTimeOut, Duration keepAlive, Boolean awaitTermination,
82-
Duration awaitTerminationPeriod, String threadNamePrefix, TaskDecorator taskDecorator,
83-
Set<ThreadPoolTaskExecutorCustomizer> customizers) {
85+
Boolean allowCoreThreadTimeOut, Duration keepAlive, Boolean acceptTasksAfterContextClose,
86+
Boolean awaitTermination, Duration awaitTerminationPeriod, String threadNamePrefix,
87+
TaskDecorator taskDecorator, Set<ThreadPoolTaskExecutorCustomizer> customizers) {
8488
this.queueCapacity = queueCapacity;
8589
this.corePoolSize = corePoolSize;
8690
this.maxPoolSize = maxPoolSize;
8791
this.allowCoreThreadTimeOut = allowCoreThreadTimeOut;
8892
this.keepAlive = keepAlive;
93+
this.acceptTasksAfterContextClose = acceptTasksAfterContextClose;
8994
this.awaitTermination = awaitTermination;
9095
this.awaitTerminationPeriod = awaitTerminationPeriod;
9196
this.threadNamePrefix = threadNamePrefix;
@@ -101,8 +106,8 @@ private ThreadPoolTaskExecutorBuilder(Integer queueCapacity, Integer corePoolSiz
101106
*/
102107
public ThreadPoolTaskExecutorBuilder queueCapacity(int queueCapacity) {
103108
return new ThreadPoolTaskExecutorBuilder(queueCapacity, this.corePoolSize, this.maxPoolSize,
104-
this.allowCoreThreadTimeOut, this.keepAlive, this.awaitTermination, this.awaitTerminationPeriod,
105-
this.threadNamePrefix, this.taskDecorator, this.customizers);
109+
this.allowCoreThreadTimeOut, this.keepAlive, this.acceptTasksAfterContextClose, this.awaitTermination,
110+
this.awaitTerminationPeriod, this.threadNamePrefix, this.taskDecorator, this.customizers);
106111
}
107112

108113
/**
@@ -116,8 +121,8 @@ public ThreadPoolTaskExecutorBuilder queueCapacity(int queueCapacity) {
116121
*/
117122
public ThreadPoolTaskExecutorBuilder corePoolSize(int corePoolSize) {
118123
return new ThreadPoolTaskExecutorBuilder(this.queueCapacity, corePoolSize, this.maxPoolSize,
119-
this.allowCoreThreadTimeOut, this.keepAlive, this.awaitTermination, this.awaitTerminationPeriod,
120-
this.threadNamePrefix, this.taskDecorator, this.customizers);
124+
this.allowCoreThreadTimeOut, this.keepAlive, this.acceptTasksAfterContextClose, this.awaitTermination,
125+
this.awaitTerminationPeriod, this.threadNamePrefix, this.taskDecorator, this.customizers);
121126
}
122127

123128
/**
@@ -131,8 +136,8 @@ public ThreadPoolTaskExecutorBuilder corePoolSize(int corePoolSize) {
131136
*/
132137
public ThreadPoolTaskExecutorBuilder maxPoolSize(int maxPoolSize) {
133138
return new ThreadPoolTaskExecutorBuilder(this.queueCapacity, this.corePoolSize, maxPoolSize,
134-
this.allowCoreThreadTimeOut, this.keepAlive, this.awaitTermination, this.awaitTerminationPeriod,
135-
this.threadNamePrefix, this.taskDecorator, this.customizers);
139+
this.allowCoreThreadTimeOut, this.keepAlive, this.acceptTasksAfterContextClose, this.awaitTermination,
140+
this.awaitTerminationPeriod, this.threadNamePrefix, this.taskDecorator, this.customizers);
136141
}
137142

138143
/**
@@ -143,8 +148,8 @@ public ThreadPoolTaskExecutorBuilder maxPoolSize(int maxPoolSize) {
143148
*/
144149
public ThreadPoolTaskExecutorBuilder allowCoreThreadTimeOut(boolean allowCoreThreadTimeOut) {
145150
return new ThreadPoolTaskExecutorBuilder(this.queueCapacity, this.corePoolSize, this.maxPoolSize,
146-
allowCoreThreadTimeOut, this.keepAlive, this.awaitTermination, this.awaitTerminationPeriod,
147-
this.threadNamePrefix, this.taskDecorator, this.customizers);
151+
allowCoreThreadTimeOut, this.keepAlive, this.acceptTasksAfterContextClose, this.awaitTermination,
152+
this.awaitTerminationPeriod, this.threadNamePrefix, this.taskDecorator, this.customizers);
148153
}
149154

150155
/**
@@ -154,8 +159,21 @@ public ThreadPoolTaskExecutorBuilder allowCoreThreadTimeOut(boolean allowCoreThr
154159
*/
155160
public ThreadPoolTaskExecutorBuilder keepAlive(Duration keepAlive) {
156161
return new ThreadPoolTaskExecutorBuilder(this.queueCapacity, this.corePoolSize, this.maxPoolSize,
157-
this.allowCoreThreadTimeOut, keepAlive, this.awaitTermination, this.awaitTerminationPeriod,
158-
this.threadNamePrefix, this.taskDecorator, this.customizers);
162+
this.allowCoreThreadTimeOut, keepAlive, this.acceptTasksAfterContextClose, this.awaitTermination,
163+
this.awaitTerminationPeriod, this.threadNamePrefix, this.taskDecorator, this.customizers);
164+
}
165+
166+
/**
167+
* Set whether to accept further tasks after the application context close phase has
168+
* begun.
169+
* @param acceptTasksAfterContextClose to accept further tasks after the application
170+
* context close phase has begun
171+
* @return a new builder instance
172+
*/
173+
public ThreadPoolTaskExecutorBuilder acceptTasksAfterContextClose(boolean acceptTasksAfterContextClose) {
174+
return new ThreadPoolTaskExecutorBuilder(this.queueCapacity, this.corePoolSize, this.maxPoolSize,
175+
this.allowCoreThreadTimeOut, this.keepAlive, acceptTasksAfterContextClose, this.awaitTermination,
176+
this.awaitTerminationPeriod, this.threadNamePrefix, this.taskDecorator, this.customizers);
159177
}
160178

161179
/**
@@ -168,8 +186,8 @@ public ThreadPoolTaskExecutorBuilder keepAlive(Duration keepAlive) {
168186
*/
169187
public ThreadPoolTaskExecutorBuilder awaitTermination(boolean awaitTermination) {
170188
return new ThreadPoolTaskExecutorBuilder(this.queueCapacity, this.corePoolSize, this.maxPoolSize,
171-
this.allowCoreThreadTimeOut, this.keepAlive, awaitTermination, this.awaitTerminationPeriod,
172-
this.threadNamePrefix, this.taskDecorator, this.customizers);
189+
this.allowCoreThreadTimeOut, this.keepAlive, this.acceptTasksAfterContextClose, awaitTermination,
190+
this.awaitTerminationPeriod, this.threadNamePrefix, this.taskDecorator, this.customizers);
173191
}
174192

175193
/**
@@ -183,8 +201,8 @@ public ThreadPoolTaskExecutorBuilder awaitTermination(boolean awaitTermination)
183201
*/
184202
public ThreadPoolTaskExecutorBuilder awaitTerminationPeriod(Duration awaitTerminationPeriod) {
185203
return new ThreadPoolTaskExecutorBuilder(this.queueCapacity, this.corePoolSize, this.maxPoolSize,
186-
this.allowCoreThreadTimeOut, this.keepAlive, this.awaitTermination, awaitTerminationPeriod,
187-
this.threadNamePrefix, this.taskDecorator, this.customizers);
204+
this.allowCoreThreadTimeOut, this.keepAlive, this.acceptTasksAfterContextClose, this.awaitTermination,
205+
awaitTerminationPeriod, this.threadNamePrefix, this.taskDecorator, this.customizers);
188206
}
189207

190208
/**
@@ -194,8 +212,8 @@ public ThreadPoolTaskExecutorBuilder awaitTerminationPeriod(Duration awaitTermin
194212
*/
195213
public ThreadPoolTaskExecutorBuilder threadNamePrefix(String threadNamePrefix) {
196214
return new ThreadPoolTaskExecutorBuilder(this.queueCapacity, this.corePoolSize, this.maxPoolSize,
197-
this.allowCoreThreadTimeOut, this.keepAlive, this.awaitTermination, this.awaitTerminationPeriod,
198-
threadNamePrefix, this.taskDecorator, this.customizers);
215+
this.allowCoreThreadTimeOut, this.keepAlive, this.acceptTasksAfterContextClose, this.awaitTermination,
216+
this.awaitTerminationPeriod, threadNamePrefix, this.taskDecorator, this.customizers);
199217
}
200218

201219
/**
@@ -205,8 +223,8 @@ public ThreadPoolTaskExecutorBuilder threadNamePrefix(String threadNamePrefix) {
205223
*/
206224
public ThreadPoolTaskExecutorBuilder taskDecorator(TaskDecorator taskDecorator) {
207225
return new ThreadPoolTaskExecutorBuilder(this.queueCapacity, this.corePoolSize, this.maxPoolSize,
208-
this.allowCoreThreadTimeOut, this.keepAlive, this.awaitTermination, this.awaitTerminationPeriod,
209-
this.threadNamePrefix, taskDecorator, this.customizers);
226+
this.allowCoreThreadTimeOut, this.keepAlive, this.acceptTasksAfterContextClose, this.awaitTermination,
227+
this.awaitTerminationPeriod, this.threadNamePrefix, taskDecorator, this.customizers);
210228
}
211229

212230
/**
@@ -235,8 +253,8 @@ public ThreadPoolTaskExecutorBuilder customizers(ThreadPoolTaskExecutorCustomize
235253
public ThreadPoolTaskExecutorBuilder customizers(Iterable<? extends ThreadPoolTaskExecutorCustomizer> customizers) {
236254
Assert.notNull(customizers, "Customizers must not be null");
237255
return new ThreadPoolTaskExecutorBuilder(this.queueCapacity, this.corePoolSize, this.maxPoolSize,
238-
this.allowCoreThreadTimeOut, this.keepAlive, this.awaitTermination, this.awaitTerminationPeriod,
239-
this.threadNamePrefix, this.taskDecorator, append(null, customizers));
256+
this.allowCoreThreadTimeOut, this.keepAlive, this.acceptTasksAfterContextClose, this.awaitTermination,
257+
this.awaitTerminationPeriod, this.threadNamePrefix, this.taskDecorator, append(null, customizers));
240258
}
241259

242260
/**
@@ -264,8 +282,9 @@ public ThreadPoolTaskExecutorBuilder additionalCustomizers(
264282
Iterable<? extends ThreadPoolTaskExecutorCustomizer> customizers) {
265283
Assert.notNull(customizers, "Customizers must not be null");
266284
return new ThreadPoolTaskExecutorBuilder(this.queueCapacity, this.corePoolSize, this.maxPoolSize,
267-
this.allowCoreThreadTimeOut, this.keepAlive, this.awaitTermination, this.awaitTerminationPeriod,
268-
this.threadNamePrefix, this.taskDecorator, append(this.customizers, customizers));
285+
this.allowCoreThreadTimeOut, this.keepAlive, this.acceptTasksAfterContextClose, this.awaitTermination,
286+
this.awaitTerminationPeriod, this.threadNamePrefix, this.taskDecorator,
287+
append(this.customizers, customizers));
269288
}
270289

271290
/**
@@ -307,6 +326,7 @@ public <T extends ThreadPoolTaskExecutor> T configure(T taskExecutor) {
307326
map.from(this.maxPoolSize).to(taskExecutor::setMaxPoolSize);
308327
map.from(this.keepAlive).asInt(Duration::getSeconds).to(taskExecutor::setKeepAliveSeconds);
309328
map.from(this.allowCoreThreadTimeOut).to(taskExecutor::setAllowCoreThreadTimeOut);
329+
map.from(this.acceptTasksAfterContextClose).to(taskExecutor::setAcceptTasksAfterContextClose);
310330
map.from(this.awaitTermination).to(taskExecutor::setWaitForTasksToCompleteOnShutdown);
311331
map.from(this.awaitTerminationPeriod).as(Duration::toMillis).to(taskExecutor::setAwaitTerminationMillis);
312332
map.from(this.threadNamePrefix).whenHasText().to(taskExecutor::setThreadNamePrefix);

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

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2023 the original author or authors.
2+
* Copyright 2012-2024 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.
@@ -36,6 +36,7 @@
3636
*
3737
* @author Stephane Nicoll
3838
* @author Filip Hrisafov
39+
* @author Yanming Zhou
3940
*/
4041
class ThreadPoolTaskExecutorBuilderTests {
4142

@@ -56,6 +57,12 @@ void poolSettingsShouldApply() {
5657
assertThat(executor.getKeepAliveSeconds()).isEqualTo(60);
5758
}
5859

60+
@Test
61+
void acceptTasksAfterContextCloseShouldApply() {
62+
ThreadPoolTaskExecutor executor = this.builder.acceptTasksAfterContextClose(true).build();
63+
assertThat(executor).hasFieldOrPropertyWithValue("acceptTasksAfterContextClose", true);
64+
}
65+
5966
@Test
6067
void awaitTerminationShouldApply() {
6168
ThreadPoolTaskExecutor executor = this.builder.awaitTermination(true).build();

0 commit comments

Comments
 (0)