Skip to content

Commit

Permalink
Add configuration property "spring.task.execution.shutdown.accept-tas…
Browse files Browse the repository at this point in the history
…ks-after-context-close"

ExecutorConfigurationSupport::setAcceptTasksAfterContextClose is introduced since Spring Framework 6.1
  • Loading branch information
quaff committed Jan 4, 2024
1 parent 735df35 commit 04700f2
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 37 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2024 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.
Expand All @@ -25,6 +25,7 @@
*
* @author Stephane Nicoll
* @author Filip Hrisafov
* @author Yanming Zhou
* @since 2.1.0
*/
@ConfigurationProperties("spring.task.execution")
Expand Down Expand Up @@ -154,6 +155,12 @@ public void setKeepAlive(Duration keepAlive) {

public static class Shutdown {

/**
* Whether to accept further tasks after the application context close phase has
* begun.
*/
private boolean acceptTasksAfterContextClose;

/**
* Whether the executor should wait for scheduled tasks to complete on shutdown.
*/
Expand All @@ -164,6 +171,14 @@ public static class Shutdown {
*/
private Duration awaitTerminationPeriod;

public boolean isAcceptTasksAfterContextClose() {
return this.acceptTasksAfterContextClose;
}

public void setAcceptTasksAfterContextClose(boolean acceptTasksAfterContextClose) {
this.acceptTasksAfterContextClose = acceptTasksAfterContextClose;
}

public boolean isAwaitTermination() {
return this.awaitTermination;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2024 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.
Expand Down Expand Up @@ -43,6 +43,7 @@
*
* @author Andy Wilkinson
* @author Moritz Halbritter
* @author Yanming Zhou
*/
class TaskExecutorConfigurations {

Expand Down Expand Up @@ -120,6 +121,7 @@ ThreadPoolTaskExecutorBuilder threadPoolTaskExecutorBuilder(TaskExecutionPropert
builder = builder.allowCoreThreadTimeOut(pool.isAllowCoreThreadTimeout());
builder = builder.keepAlive(pool.getKeepAlive());
TaskExecutionProperties.Shutdown shutdown = properties.getShutdown();
builder = builder.acceptTasksAfterContextClose(shutdown.isAcceptTasksAfterContextClose());
builder = builder.awaitTermination(shutdown.isAwaitTermination());
builder = builder.awaitTerminationPeriod(shutdown.getAwaitTerminationPeriod());
builder = builder.threadNamePrefix(properties.getThreadNamePrefix());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2024 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.
Expand Down Expand Up @@ -60,6 +60,7 @@
* @author Stephane Nicoll
* @author Camille Vienot
* @author Moritz Halbritter
* @author Yanming Zhou
*/
@ExtendWith(OutputCaptureExtension.class)
@SuppressWarnings("removal")
Expand Down Expand Up @@ -124,19 +125,20 @@ void simpleAsyncTaskExecutorBuilderShouldReadProperties() {

@Test
void threadPoolTaskExecutorBuilderShouldApplyCustomSettings() {
this.contextRunner
.withPropertyValues("spring.task.execution.pool.queue-capacity=10",
"spring.task.execution.pool.core-size=2", "spring.task.execution.pool.max-size=4",
"spring.task.execution.pool.allow-core-thread-timeout=true",
"spring.task.execution.pool.keep-alive=5s", "spring.task.execution.shutdown.await-termination=true",
"spring.task.execution.shutdown.await-termination-period=30s",
"spring.task.execution.thread-name-prefix=mytest-")
this.contextRunner.withPropertyValues("spring.task.execution.pool.queue-capacity=10",
"spring.task.execution.pool.core-size=2", "spring.task.execution.pool.max-size=4",
"spring.task.execution.pool.allow-core-thread-timeout=true", "spring.task.execution.pool.keep-alive=5s",
"spring.task.execution.shutdown.accept-tasks-after-context-close=true",
"spring.task.execution.shutdown.await-termination=true",
"spring.task.execution.shutdown.await-termination-period=30s",
"spring.task.execution.thread-name-prefix=mytest-")
.run(assertThreadPoolTaskExecutor((taskExecutor) -> {
assertThat(taskExecutor).hasFieldOrPropertyWithValue("queueCapacity", 10);
assertThat(taskExecutor.getCorePoolSize()).isEqualTo(2);
assertThat(taskExecutor.getMaxPoolSize()).isEqualTo(4);
assertThat(taskExecutor).hasFieldOrPropertyWithValue("allowCoreThreadTimeOut", true);
assertThat(taskExecutor.getKeepAliveSeconds()).isEqualTo(5);
assertThat(taskExecutor).hasFieldOrPropertyWithValue("acceptTasksAfterContextClose", true);
assertThat(taskExecutor).hasFieldOrPropertyWithValue("waitForTasksToCompleteOnShutdown", true);
assertThat(taskExecutor).hasFieldOrPropertyWithValue("awaitTerminationMillis", 30000L);
assertThat(taskExecutor.getThreadNamePrefix()).isEqualTo("mytest-");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2024 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.
Expand Down Expand Up @@ -40,6 +40,7 @@
*
* @author Stephane Nicoll
* @author Filip Hrisafov
* @author Yanming Zhou
* @since 3.2.0
*/
public class ThreadPoolTaskExecutorBuilder {
Expand All @@ -54,6 +55,8 @@ public class ThreadPoolTaskExecutorBuilder {

private final Duration keepAlive;

private final Boolean acceptTasksAfterContextClose;

private final Boolean awaitTermination;

private final Duration awaitTerminationPeriod;
Expand All @@ -70,6 +73,7 @@ public ThreadPoolTaskExecutorBuilder() {
this.maxPoolSize = null;
this.allowCoreThreadTimeOut = null;
this.keepAlive = null;
this.acceptTasksAfterContextClose = null;
this.awaitTermination = null;
this.awaitTerminationPeriod = null;
this.threadNamePrefix = null;
Expand All @@ -78,14 +82,15 @@ public ThreadPoolTaskExecutorBuilder() {
}

private ThreadPoolTaskExecutorBuilder(Integer queueCapacity, Integer corePoolSize, Integer maxPoolSize,
Boolean allowCoreThreadTimeOut, Duration keepAlive, Boolean awaitTermination,
Duration awaitTerminationPeriod, String threadNamePrefix, TaskDecorator taskDecorator,
Set<ThreadPoolTaskExecutorCustomizer> customizers) {
Boolean allowCoreThreadTimeOut, Duration keepAlive, Boolean acceptTasksAfterContextClose,
Boolean awaitTermination, Duration awaitTerminationPeriod, String threadNamePrefix,
TaskDecorator taskDecorator, Set<ThreadPoolTaskExecutorCustomizer> customizers) {
this.queueCapacity = queueCapacity;
this.corePoolSize = corePoolSize;
this.maxPoolSize = maxPoolSize;
this.allowCoreThreadTimeOut = allowCoreThreadTimeOut;
this.keepAlive = keepAlive;
this.acceptTasksAfterContextClose = acceptTasksAfterContextClose;
this.awaitTermination = awaitTermination;
this.awaitTerminationPeriod = awaitTerminationPeriod;
this.threadNamePrefix = threadNamePrefix;
Expand All @@ -101,8 +106,8 @@ private ThreadPoolTaskExecutorBuilder(Integer queueCapacity, Integer corePoolSiz
*/
public ThreadPoolTaskExecutorBuilder queueCapacity(int queueCapacity) {
return new ThreadPoolTaskExecutorBuilder(queueCapacity, this.corePoolSize, this.maxPoolSize,
this.allowCoreThreadTimeOut, this.keepAlive, this.awaitTermination, this.awaitTerminationPeriod,
this.threadNamePrefix, this.taskDecorator, this.customizers);
this.allowCoreThreadTimeOut, this.keepAlive, this.acceptTasksAfterContextClose, this.awaitTermination,
this.awaitTerminationPeriod, this.threadNamePrefix, this.taskDecorator, this.customizers);
}

/**
Expand All @@ -116,8 +121,8 @@ public ThreadPoolTaskExecutorBuilder queueCapacity(int queueCapacity) {
*/
public ThreadPoolTaskExecutorBuilder corePoolSize(int corePoolSize) {
return new ThreadPoolTaskExecutorBuilder(this.queueCapacity, corePoolSize, this.maxPoolSize,
this.allowCoreThreadTimeOut, this.keepAlive, this.awaitTermination, this.awaitTerminationPeriod,
this.threadNamePrefix, this.taskDecorator, this.customizers);
this.allowCoreThreadTimeOut, this.keepAlive, this.acceptTasksAfterContextClose, this.awaitTermination,
this.awaitTerminationPeriod, this.threadNamePrefix, this.taskDecorator, this.customizers);
}

/**
Expand All @@ -131,8 +136,8 @@ public ThreadPoolTaskExecutorBuilder corePoolSize(int corePoolSize) {
*/
public ThreadPoolTaskExecutorBuilder maxPoolSize(int maxPoolSize) {
return new ThreadPoolTaskExecutorBuilder(this.queueCapacity, this.corePoolSize, maxPoolSize,
this.allowCoreThreadTimeOut, this.keepAlive, this.awaitTermination, this.awaitTerminationPeriod,
this.threadNamePrefix, this.taskDecorator, this.customizers);
this.allowCoreThreadTimeOut, this.keepAlive, this.acceptTasksAfterContextClose, this.awaitTermination,
this.awaitTerminationPeriod, this.threadNamePrefix, this.taskDecorator, this.customizers);
}

/**
Expand All @@ -143,8 +148,8 @@ public ThreadPoolTaskExecutorBuilder maxPoolSize(int maxPoolSize) {
*/
public ThreadPoolTaskExecutorBuilder allowCoreThreadTimeOut(boolean allowCoreThreadTimeOut) {
return new ThreadPoolTaskExecutorBuilder(this.queueCapacity, this.corePoolSize, this.maxPoolSize,
allowCoreThreadTimeOut, this.keepAlive, this.awaitTermination, this.awaitTerminationPeriod,
this.threadNamePrefix, this.taskDecorator, this.customizers);
allowCoreThreadTimeOut, this.keepAlive, this.acceptTasksAfterContextClose, this.awaitTermination,
this.awaitTerminationPeriod, this.threadNamePrefix, this.taskDecorator, this.customizers);
}

/**
Expand All @@ -154,8 +159,21 @@ public ThreadPoolTaskExecutorBuilder allowCoreThreadTimeOut(boolean allowCoreThr
*/
public ThreadPoolTaskExecutorBuilder keepAlive(Duration keepAlive) {
return new ThreadPoolTaskExecutorBuilder(this.queueCapacity, this.corePoolSize, this.maxPoolSize,
this.allowCoreThreadTimeOut, keepAlive, this.awaitTermination, this.awaitTerminationPeriod,
this.threadNamePrefix, this.taskDecorator, this.customizers);
this.allowCoreThreadTimeOut, keepAlive, this.acceptTasksAfterContextClose, this.awaitTermination,
this.awaitTerminationPeriod, this.threadNamePrefix, this.taskDecorator, this.customizers);
}

/**
* Set whether to accept further tasks after the application context close phase has
* begun.
* @param acceptTasksAfterContextClose to accept further tasks after the application
* context close phase has begun
* @return a new builder instance
*/
public ThreadPoolTaskExecutorBuilder acceptTasksAfterContextClose(boolean acceptTasksAfterContextClose) {
return new ThreadPoolTaskExecutorBuilder(this.queueCapacity, this.corePoolSize, this.maxPoolSize,
this.allowCoreThreadTimeOut, this.keepAlive, acceptTasksAfterContextClose, this.awaitTermination,
this.awaitTerminationPeriod, this.threadNamePrefix, this.taskDecorator, this.customizers);
}

/**
Expand All @@ -168,8 +186,8 @@ public ThreadPoolTaskExecutorBuilder keepAlive(Duration keepAlive) {
*/
public ThreadPoolTaskExecutorBuilder awaitTermination(boolean awaitTermination) {
return new ThreadPoolTaskExecutorBuilder(this.queueCapacity, this.corePoolSize, this.maxPoolSize,
this.allowCoreThreadTimeOut, this.keepAlive, awaitTermination, this.awaitTerminationPeriod,
this.threadNamePrefix, this.taskDecorator, this.customizers);
this.allowCoreThreadTimeOut, this.keepAlive, this.acceptTasksAfterContextClose, awaitTermination,
this.awaitTerminationPeriod, this.threadNamePrefix, this.taskDecorator, this.customizers);
}

/**
Expand All @@ -183,8 +201,8 @@ public ThreadPoolTaskExecutorBuilder awaitTermination(boolean awaitTermination)
*/
public ThreadPoolTaskExecutorBuilder awaitTerminationPeriod(Duration awaitTerminationPeriod) {
return new ThreadPoolTaskExecutorBuilder(this.queueCapacity, this.corePoolSize, this.maxPoolSize,
this.allowCoreThreadTimeOut, this.keepAlive, this.awaitTermination, awaitTerminationPeriod,
this.threadNamePrefix, this.taskDecorator, this.customizers);
this.allowCoreThreadTimeOut, this.keepAlive, this.acceptTasksAfterContextClose, this.awaitTermination,
awaitTerminationPeriod, this.threadNamePrefix, this.taskDecorator, this.customizers);
}

/**
Expand All @@ -194,8 +212,8 @@ public ThreadPoolTaskExecutorBuilder awaitTerminationPeriod(Duration awaitTermin
*/
public ThreadPoolTaskExecutorBuilder threadNamePrefix(String threadNamePrefix) {
return new ThreadPoolTaskExecutorBuilder(this.queueCapacity, this.corePoolSize, this.maxPoolSize,
this.allowCoreThreadTimeOut, this.keepAlive, this.awaitTermination, this.awaitTerminationPeriod,
threadNamePrefix, this.taskDecorator, this.customizers);
this.allowCoreThreadTimeOut, this.keepAlive, this.acceptTasksAfterContextClose, this.awaitTermination,
this.awaitTerminationPeriod, threadNamePrefix, this.taskDecorator, this.customizers);
}

/**
Expand All @@ -205,8 +223,8 @@ public ThreadPoolTaskExecutorBuilder threadNamePrefix(String threadNamePrefix) {
*/
public ThreadPoolTaskExecutorBuilder taskDecorator(TaskDecorator taskDecorator) {
return new ThreadPoolTaskExecutorBuilder(this.queueCapacity, this.corePoolSize, this.maxPoolSize,
this.allowCoreThreadTimeOut, this.keepAlive, this.awaitTermination, this.awaitTerminationPeriod,
this.threadNamePrefix, taskDecorator, this.customizers);
this.allowCoreThreadTimeOut, this.keepAlive, this.acceptTasksAfterContextClose, this.awaitTermination,
this.awaitTerminationPeriod, this.threadNamePrefix, taskDecorator, this.customizers);
}

/**
Expand Down Expand Up @@ -235,8 +253,8 @@ public ThreadPoolTaskExecutorBuilder customizers(ThreadPoolTaskExecutorCustomize
public ThreadPoolTaskExecutorBuilder customizers(Iterable<? extends ThreadPoolTaskExecutorCustomizer> customizers) {
Assert.notNull(customizers, "Customizers must not be null");
return new ThreadPoolTaskExecutorBuilder(this.queueCapacity, this.corePoolSize, this.maxPoolSize,
this.allowCoreThreadTimeOut, this.keepAlive, this.awaitTermination, this.awaitTerminationPeriod,
this.threadNamePrefix, this.taskDecorator, append(null, customizers));
this.allowCoreThreadTimeOut, this.keepAlive, this.acceptTasksAfterContextClose, this.awaitTermination,
this.awaitTerminationPeriod, this.threadNamePrefix, this.taskDecorator, append(null, customizers));
}

/**
Expand Down Expand Up @@ -264,8 +282,9 @@ public ThreadPoolTaskExecutorBuilder additionalCustomizers(
Iterable<? extends ThreadPoolTaskExecutorCustomizer> customizers) {
Assert.notNull(customizers, "Customizers must not be null");
return new ThreadPoolTaskExecutorBuilder(this.queueCapacity, this.corePoolSize, this.maxPoolSize,
this.allowCoreThreadTimeOut, this.keepAlive, this.awaitTermination, this.awaitTerminationPeriod,
this.threadNamePrefix, this.taskDecorator, append(this.customizers, customizers));
this.allowCoreThreadTimeOut, this.keepAlive, this.acceptTasksAfterContextClose, this.awaitTermination,
this.awaitTerminationPeriod, this.threadNamePrefix, this.taskDecorator,
append(this.customizers, customizers));
}

/**
Expand Down Expand Up @@ -307,6 +326,7 @@ public <T extends ThreadPoolTaskExecutor> T configure(T taskExecutor) {
map.from(this.maxPoolSize).to(taskExecutor::setMaxPoolSize);
map.from(this.keepAlive).asInt(Duration::getSeconds).to(taskExecutor::setKeepAliveSeconds);
map.from(this.allowCoreThreadTimeOut).to(taskExecutor::setAllowCoreThreadTimeOut);
map.from(this.acceptTasksAfterContextClose).to(taskExecutor::setAcceptTasksAfterContextClose);
map.from(this.awaitTermination).to(taskExecutor::setWaitForTasksToCompleteOnShutdown);
map.from(this.awaitTerminationPeriod).as(Duration::toMillis).to(taskExecutor::setAwaitTerminationMillis);
map.from(this.threadNamePrefix).whenHasText().to(taskExecutor::setThreadNamePrefix);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2024 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.
Expand Down Expand Up @@ -36,6 +36,7 @@
*
* @author Stephane Nicoll
* @author Filip Hrisafov
* @author Yanming Zhou
*/
class ThreadPoolTaskExecutorBuilderTests {

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

@Test
void acceptTasksAfterContextCloseShouldApply() {
ThreadPoolTaskExecutor executor = this.builder.acceptTasksAfterContextClose(true).build();
assertThat(executor).hasFieldOrPropertyWithValue("acceptTasksAfterContextClose", true);
}

@Test
void awaitTerminationShouldApply() {
ThreadPoolTaskExecutor executor = this.builder.awaitTermination(true).build();
Expand Down

0 comments on commit 04700f2

Please sign in to comment.