Skip to content

Commit 5408a49

Browse files
committed
Merge pull request #45155 from quaff
* pr/45155: Polish contribution Add support for SimpleTaskExecutor#reject-tasks-when-limit-reached Closes gh-45155
2 parents 10b15e3 + 29a07ba commit 5408a49

File tree

5 files changed

+68
-18
lines changed

5 files changed

+68
-18
lines changed

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

+13
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,25 @@ public void setThreadNamePrefix(String threadNamePrefix) {
7777

7878
public static class Simple {
7979

80+
/**
81+
* Whether to reject tasks when the concurrency limit has been reached.
82+
*/
83+
private boolean rejectTasksWhenLimitReached;
84+
8085
/**
8186
* Set the maximum number of parallel accesses allowed. -1 indicates no
8287
* concurrency limit at all.
8388
*/
8489
private Integer concurrencyLimit;
8590

91+
public boolean isRejectTasksWhenLimitReached() {
92+
return this.rejectTasksWhenLimitReached;
93+
}
94+
95+
public void setRejectTasksWhenLimitReached(boolean rejectTasksWhenLimitReached) {
96+
this.rejectTasksWhenLimitReached = rejectTasksWhenLimitReached;
97+
}
98+
8699
public Integer getConcurrencyLimit() {
87100
return this.concurrencyLimit;
88101
}

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

+1
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ private SimpleAsyncTaskExecutorBuilder builder() {
135135
builder = builder.customizers(this.taskExecutorCustomizers.orderedStream()::iterator);
136136
builder = builder.taskDecorator(this.taskDecorator.getIfUnique());
137137
TaskExecutionProperties.Simple simple = this.properties.getSimple();
138+
builder = builder.rejectTasksWhenLimitReached(simple.isRejectTasksWhenLimitReached());
138139
builder = builder.concurrencyLimit(simple.getConcurrencyLimit());
139140
TaskExecutionProperties.Shutdown shutdown = this.properties.getShutdown();
140141
if (shutdown.isAwaitTermination()) {

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

+2
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,12 @@ void shouldSupplyBeans() {
8383
void simpleAsyncTaskExecutorBuilderShouldReadProperties() {
8484
this.contextRunner
8585
.withPropertyValues("spring.task.execution.thread-name-prefix=mytest-",
86+
"spring.task.execution.simple.reject-tasks-when-limit-reached=true",
8687
"spring.task.execution.simple.concurrency-limit=1",
8788
"spring.task.execution.shutdown.await-termination=true",
8889
"spring.task.execution.shutdown.await-termination-period=30s")
8990
.run(assertSimpleAsyncTaskExecutor((taskExecutor) -> {
91+
assertThat(taskExecutor).hasFieldOrPropertyWithValue("rejectTasksWhenLimitReached", true);
9092
assertThat(taskExecutor.getConcurrencyLimit()).isEqualTo(1);
9193
assertThat(taskExecutor.getThreadNamePrefix()).isEqualTo("mytest-");
9294
assertThat(taskExecutor).hasFieldOrPropertyWithValue("taskTerminationTimeout", 30000L);

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

+45-18
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
* @author Stephane Nicoll
4242
* @author Filip Hrisafov
4343
* @author Moritz Halbritter
44+
* @author Yanming Zhou
4445
* @since 3.2.0
4546
*/
4647
public class SimpleAsyncTaskExecutorBuilder {
@@ -49,6 +50,8 @@ public class SimpleAsyncTaskExecutorBuilder {
4950

5051
private final String threadNamePrefix;
5152

53+
private final boolean rejectTasksWhenLimitReached;
54+
5255
private final Integer concurrencyLimit;
5356

5457
private final TaskDecorator taskDecorator;
@@ -58,14 +61,15 @@ public class SimpleAsyncTaskExecutorBuilder {
5861
private final Duration taskTerminationTimeout;
5962

6063
public SimpleAsyncTaskExecutorBuilder() {
61-
this(null, null, null, null, null, null);
64+
this(null, null, false, null, null, null, null);
6265
}
6366

64-
private SimpleAsyncTaskExecutorBuilder(Boolean virtualThreads, String threadNamePrefix, Integer concurrencyLimit,
65-
TaskDecorator taskDecorator, Set<SimpleAsyncTaskExecutorCustomizer> customizers,
66-
Duration taskTerminationTimeout) {
67+
private SimpleAsyncTaskExecutorBuilder(Boolean virtualThreads, String threadNamePrefix,
68+
boolean rejectTasksWhenLimitReached, Integer concurrencyLimit, TaskDecorator taskDecorator,
69+
Set<SimpleAsyncTaskExecutorCustomizer> customizers, Duration taskTerminationTimeout) {
6770
this.virtualThreads = virtualThreads;
6871
this.threadNamePrefix = threadNamePrefix;
72+
this.rejectTasksWhenLimitReached = rejectTasksWhenLimitReached;
6973
this.concurrencyLimit = concurrencyLimit;
7074
this.taskDecorator = taskDecorator;
7175
this.customizers = customizers;
@@ -78,8 +82,9 @@ private SimpleAsyncTaskExecutorBuilder(Boolean virtualThreads, String threadName
7882
* @return a new builder instance
7983
*/
8084
public SimpleAsyncTaskExecutorBuilder threadNamePrefix(String threadNamePrefix) {
81-
return new SimpleAsyncTaskExecutorBuilder(this.virtualThreads, threadNamePrefix, this.concurrencyLimit,
82-
this.taskDecorator, this.customizers, this.taskTerminationTimeout);
85+
return new SimpleAsyncTaskExecutorBuilder(this.virtualThreads, threadNamePrefix,
86+
this.rejectTasksWhenLimitReached, this.concurrencyLimit, this.taskDecorator, this.customizers,
87+
this.taskTerminationTimeout);
8388
}
8489

8590
/**
@@ -88,8 +93,24 @@ public SimpleAsyncTaskExecutorBuilder threadNamePrefix(String threadNamePrefix)
8893
* @return a new builder instance
8994
*/
9095
public SimpleAsyncTaskExecutorBuilder virtualThreads(Boolean virtualThreads) {
91-
return new SimpleAsyncTaskExecutorBuilder(virtualThreads, this.threadNamePrefix, this.concurrencyLimit,
92-
this.taskDecorator, this.customizers, this.taskTerminationTimeout);
96+
return new SimpleAsyncTaskExecutorBuilder(virtualThreads, this.threadNamePrefix,
97+
this.rejectTasksWhenLimitReached, this.concurrencyLimit, this.taskDecorator, this.customizers,
98+
this.taskTerminationTimeout);
99+
}
100+
101+
/**
102+
* Set whether to reject tasks when the concurrency limit has been reached. By default
103+
* {@code false} to block the caller until the submission can be accepted. Switch to
104+
* {@code true} for immediate rejection instead.
105+
* @param rejectTasksWhenLimitReached whether to reject tasks when the concurrency
106+
* limit has been reached
107+
* @return a new builder instance
108+
* @since 3.5.0
109+
*/
110+
public SimpleAsyncTaskExecutorBuilder rejectTasksWhenLimitReached(boolean rejectTasksWhenLimitReached) {
111+
return new SimpleAsyncTaskExecutorBuilder(this.virtualThreads, this.threadNamePrefix,
112+
rejectTasksWhenLimitReached, this.concurrencyLimit, this.taskDecorator, this.customizers,
113+
this.taskTerminationTimeout);
93114
}
94115

95116
/**
@@ -98,8 +119,9 @@ public SimpleAsyncTaskExecutorBuilder virtualThreads(Boolean virtualThreads) {
98119
* @return a new builder instance
99120
*/
100121
public SimpleAsyncTaskExecutorBuilder concurrencyLimit(Integer concurrencyLimit) {
101-
return new SimpleAsyncTaskExecutorBuilder(this.virtualThreads, this.threadNamePrefix, concurrencyLimit,
102-
this.taskDecorator, this.customizers, this.taskTerminationTimeout);
122+
return new SimpleAsyncTaskExecutorBuilder(this.virtualThreads, this.threadNamePrefix,
123+
this.rejectTasksWhenLimitReached, concurrencyLimit, this.taskDecorator, this.customizers,
124+
this.taskTerminationTimeout);
103125
}
104126

105127
/**
@@ -108,8 +130,9 @@ public SimpleAsyncTaskExecutorBuilder concurrencyLimit(Integer concurrencyLimit)
108130
* @return a new builder instance
109131
*/
110132
public SimpleAsyncTaskExecutorBuilder taskDecorator(TaskDecorator taskDecorator) {
111-
return new SimpleAsyncTaskExecutorBuilder(this.virtualThreads, this.threadNamePrefix, this.concurrencyLimit,
112-
taskDecorator, this.customizers, this.taskTerminationTimeout);
133+
return new SimpleAsyncTaskExecutorBuilder(this.virtualThreads, this.threadNamePrefix,
134+
this.rejectTasksWhenLimitReached, this.concurrencyLimit, taskDecorator, this.customizers,
135+
this.taskTerminationTimeout);
113136
}
114137

115138
/**
@@ -119,8 +142,9 @@ public SimpleAsyncTaskExecutorBuilder taskDecorator(TaskDecorator taskDecorator)
119142
* @since 3.2.1
120143
*/
121144
public SimpleAsyncTaskExecutorBuilder taskTerminationTimeout(Duration taskTerminationTimeout) {
122-
return new SimpleAsyncTaskExecutorBuilder(this.virtualThreads, this.threadNamePrefix, this.concurrencyLimit,
123-
this.taskDecorator, this.customizers, taskTerminationTimeout);
145+
return new SimpleAsyncTaskExecutorBuilder(this.virtualThreads, this.threadNamePrefix,
146+
this.rejectTasksWhenLimitReached, this.concurrencyLimit, this.taskDecorator, this.customizers,
147+
taskTerminationTimeout);
124148
}
125149

126150
/**
@@ -149,8 +173,9 @@ public SimpleAsyncTaskExecutorBuilder customizers(SimpleAsyncTaskExecutorCustomi
149173
public SimpleAsyncTaskExecutorBuilder customizers(
150174
Iterable<? extends SimpleAsyncTaskExecutorCustomizer> customizers) {
151175
Assert.notNull(customizers, "'customizers' must not be null");
152-
return new SimpleAsyncTaskExecutorBuilder(this.virtualThreads, this.threadNamePrefix, this.concurrencyLimit,
153-
this.taskDecorator, append(null, customizers), this.taskTerminationTimeout);
176+
return new SimpleAsyncTaskExecutorBuilder(this.virtualThreads, this.threadNamePrefix,
177+
this.rejectTasksWhenLimitReached, this.concurrencyLimit, this.taskDecorator, append(null, customizers),
178+
this.taskTerminationTimeout);
154179
}
155180

156181
/**
@@ -177,8 +202,9 @@ public SimpleAsyncTaskExecutorBuilder additionalCustomizers(SimpleAsyncTaskExecu
177202
public SimpleAsyncTaskExecutorBuilder additionalCustomizers(
178203
Iterable<? extends SimpleAsyncTaskExecutorCustomizer> customizers) {
179204
Assert.notNull(customizers, "'customizers' must not be null");
180-
return new SimpleAsyncTaskExecutorBuilder(this.virtualThreads, this.threadNamePrefix, this.concurrencyLimit,
181-
this.taskDecorator, append(this.customizers, customizers), this.taskTerminationTimeout);
205+
return new SimpleAsyncTaskExecutorBuilder(this.virtualThreads, this.threadNamePrefix,
206+
this.rejectTasksWhenLimitReached, this.concurrencyLimit, this.taskDecorator,
207+
append(this.customizers, customizers), this.taskTerminationTimeout);
182208
}
183209

184210
/**
@@ -217,6 +243,7 @@ public <T extends SimpleAsyncTaskExecutor> T configure(T taskExecutor) {
217243
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
218244
map.from(this.virtualThreads).to(taskExecutor::setVirtualThreads);
219245
map.from(this.threadNamePrefix).whenHasText().to(taskExecutor::setThreadNamePrefix);
246+
map.from(this.rejectTasksWhenLimitReached).to(taskExecutor::setRejectTasksWhenLimitReached);
220247
map.from(this.concurrencyLimit).to(taskExecutor::setConcurrencyLimit);
221248
map.from(this.taskDecorator).to(taskExecutor::setTaskDecorator);
222249
map.from(this.taskTerminationTimeout).as(Duration::toMillis).to(taskExecutor::setTaskTerminationTimeout);

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

+7
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
* @author Stephane Nicoll
4141
* @author Filip Hrisafov
4242
* @author Moritz Halbritter
43+
* @author Yanming Zhou
4344
*/
4445
class SimpleAsyncTaskExecutorBuilderTests {
4546

@@ -58,6 +59,12 @@ void virtualThreadsShouldApply() {
5859
SimpleAsyncTaskExecutorAssert.assertThat(executor).usesVirtualThreads();
5960
}
6061

62+
@Test
63+
void rejectTasksWhenLimitReachedShouldApply() {
64+
SimpleAsyncTaskExecutor executor = this.builder.rejectTasksWhenLimitReached(true).build();
65+
assertThat(executor).extracting("rejectTasksWhenLimitReached").isEqualTo(true);
66+
}
67+
6168
@Test
6269
void concurrencyLimitShouldApply() {
6370
SimpleAsyncTaskExecutor executor = this.builder.concurrencyLimit(1).build();

0 commit comments

Comments
 (0)