Polish "Add support for task executor shutdown related properties"

Closes gh-15951
pull/15987/head
Stephane Nicoll 6 years ago
parent 3b47ba21a8
commit d2cbf08f09

@ -22,6 +22,7 @@ import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.task.TaskExecutionProperties.Shutdown;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.task.TaskExecutorBuilder;
import org.springframework.boot.task.TaskExecutorCustomizer;
@ -74,10 +75,10 @@ public class TaskExecutionAutoConfiguration {
builder = builder.maxPoolSize(pool.getMaxSize());
builder = builder.allowCoreThreadTimeOut(pool.isAllowCoreThreadTimeout());
builder = builder.keepAlive(pool.getKeepAlive());
Shutdown shutdown = this.properties.getShutdown();
builder = builder.awaitTermination(shutdown.isAwaitTermination());
builder = builder.awaitTerminationPeriod(shutdown.getAwaitTerminationPeriod());
builder = builder.threadNamePrefix(this.properties.getThreadNamePrefix());
builder = builder.awaitTermination(this.properties.getAwaitTermination());
builder = builder.waitForTasksToCompleteOnShutdown(
this.properties.isWaitForTasksToCompleteOnShutdown());
builder = builder.customizers(this.taskExecutorCustomizers);
builder = builder.taskDecorator(this.taskDecorator.getIfUnique());
return builder;

@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 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.
@ -17,10 +17,8 @@
package org.springframework.boot.autoconfigure.task;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.convert.DurationUnit;
/**
* Configuration properties for task execution.
@ -34,29 +32,21 @@ public class TaskExecutionProperties {
private final Pool pool = new Pool();
private final Shutdown shutdown = new Shutdown();
/**
* Prefix to use for the names of newly created threads.
*/
private String threadNamePrefix = "task-";
/**
* Maximum number of time that the executor is supposed to block on shutdown waiting
* for remaining tasks to complete. This is particularly useful if your remaining
* tasks are likely to need access to other resources that are also managed by the
* container. If a duration suffix is not specified, seconds will be used.
*/
@DurationUnit(ChronoUnit.SECONDS)
private Duration awaitTermination;
/**
* Whether the executor should wait for scheduled tasks to complete on shutdown.
*/
private boolean waitForTasksToCompleteOnShutdown = false;
public Pool getPool() {
return this.pool;
}
public Shutdown getShutdown() {
return this.shutdown;
}
public String getThreadNamePrefix() {
return this.threadNamePrefix;
}
@ -65,23 +55,6 @@ public class TaskExecutionProperties {
this.threadNamePrefix = threadNamePrefix;
}
public Duration getAwaitTermination() {
return this.awaitTermination;
}
public void setAwaitTermination(Duration awaitTermination) {
this.awaitTermination = awaitTermination;
}
public boolean isWaitForTasksToCompleteOnShutdown() {
return this.waitForTasksToCompleteOnShutdown;
}
public void setWaitForTasksToCompleteOnShutdown(
boolean waitForTasksToCompleteOnShutdown) {
this.waitForTasksToCompleteOnShutdown = waitForTasksToCompleteOnShutdown;
}
public static class Pool {
/**
@ -155,4 +128,34 @@ public class TaskExecutionProperties {
}
public static class Shutdown {
/**
* Whether the executor should wait for scheduled tasks to complete on shutdown.
*/
private boolean awaitTermination;
/**
* Maximum time the executor should wait for remaining tasks to complete.
*/
private Duration awaitTerminationPeriod;
public boolean isAwaitTermination() {
return this.awaitTermination;
}
public void setAwaitTermination(boolean awaitTermination) {
this.awaitTermination = awaitTermination;
}
public Duration getAwaitTerminationPeriod() {
return this.awaitTerminationPeriod;
}
public void setAwaitTerminationPeriod(Duration awaitTerminationPeriod) {
this.awaitTerminationPeriod = awaitTerminationPeriod;
}
}
}

@ -63,15 +63,15 @@ public class TaskExecutionAutoConfigurationTests {
@Test
public void taskExecutorBuilderShouldApplyCustomSettings() {
this.contextRunner.withPropertyValues(
"spring.task.execution.pool.queue-capacity=10",
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.thread-name-prefix=mytest-",
"spring.task.execution.await-termination=30s",
"spring.task.execution.wait-for-tasks-to-complete-on-shutdown=true")
"spring.task.execution.shutdown.await-termination=true",
"spring.task.execution.shutdown.await-termination-period=30s",
"spring.task.execution.thread-name-prefix=mytest-")
.run(assertTaskExecutor((taskExecutor) -> {
assertThat(taskExecutor).hasFieldOrPropertyWithValue("queueCapacity",
10);
@ -80,11 +80,11 @@ public class TaskExecutionAutoConfigurationTests {
assertThat(taskExecutor)
.hasFieldOrPropertyWithValue("allowCoreThreadTimeOut", true);
assertThat(taskExecutor.getKeepAliveSeconds()).isEqualTo(5);
assertThat(taskExecutor.getThreadNamePrefix()).isEqualTo("mytest-");
assertThat(taskExecutor)
.hasFieldOrPropertyWithValue("awaitTerminationSeconds", 30);
assertThat(taskExecutor).hasFieldOrPropertyWithValue(
"waitForTasksToCompleteOnShutdown", true);
assertThat(taskExecutor)
.hasFieldOrPropertyWithValue("awaitTerminationSeconds", 30);
assertThat(taskExecutor.getThreadNamePrefix()).isEqualTo("mytest-");
}));
}

@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 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.
@ -55,11 +55,11 @@ public class TaskExecutorBuilder {
private final Duration keepAlive;
private final String threadNamePrefix;
private final Boolean awaitTermination;
private final Duration awaitTermination;
private final Duration awaitTerminationPeriod;
private final Boolean waitForTasksToCompleteOnShutdown;
private final String threadNamePrefix;
private final TaskDecorator taskDecorator;
@ -71,26 +71,26 @@ public class TaskExecutorBuilder {
this.maxPoolSize = null;
this.allowCoreThreadTimeOut = null;
this.keepAlive = null;
this.threadNamePrefix = null;
this.awaitTermination = null;
this.waitForTasksToCompleteOnShutdown = null;
this.awaitTerminationPeriod = null;
this.threadNamePrefix = null;
this.taskDecorator = null;
this.customizers = null;
}
private TaskExecutorBuilder(Integer queueCapacity, Integer corePoolSize,
Integer maxPoolSize, Boolean allowCoreThreadTimeOut, Duration keepAlive,
String threadNamePrefix, Duration awaitTermination,
Boolean waitForTasksToCompleteOnShutdown, TaskDecorator taskDecorator,
Boolean awaitTermination, Duration awaitTerminationPeriod,
String threadNamePrefix, TaskDecorator taskDecorator,
Set<TaskExecutorCustomizer> customizers) {
this.queueCapacity = queueCapacity;
this.corePoolSize = corePoolSize;
this.maxPoolSize = maxPoolSize;
this.allowCoreThreadTimeOut = allowCoreThreadTimeOut;
this.keepAlive = keepAlive;
this.threadNamePrefix = threadNamePrefix;
this.awaitTermination = awaitTermination;
this.waitForTasksToCompleteOnShutdown = waitForTasksToCompleteOnShutdown;
this.awaitTerminationPeriod = awaitTerminationPeriod;
this.threadNamePrefix = threadNamePrefix;
this.taskDecorator = taskDecorator;
this.customizers = customizers;
}
@ -103,9 +103,9 @@ public class TaskExecutorBuilder {
*/
public TaskExecutorBuilder queueCapacity(int queueCapacity) {
return new TaskExecutorBuilder(queueCapacity, this.corePoolSize, this.maxPoolSize,
this.allowCoreThreadTimeOut, this.keepAlive, this.threadNamePrefix,
this.awaitTermination, this.waitForTasksToCompleteOnShutdown,
this.taskDecorator, this.customizers);
this.allowCoreThreadTimeOut, this.keepAlive, this.awaitTermination,
this.awaitTerminationPeriod, this.threadNamePrefix, this.taskDecorator,
this.customizers);
}
/**
@ -119,9 +119,9 @@ public class TaskExecutorBuilder {
*/
public TaskExecutorBuilder corePoolSize(int corePoolSize) {
return new TaskExecutorBuilder(this.queueCapacity, corePoolSize, this.maxPoolSize,
this.allowCoreThreadTimeOut, this.keepAlive, this.threadNamePrefix,
this.awaitTermination, this.waitForTasksToCompleteOnShutdown,
this.taskDecorator, this.customizers);
this.allowCoreThreadTimeOut, this.keepAlive, this.awaitTermination,
this.awaitTerminationPeriod, this.threadNamePrefix, this.taskDecorator,
this.customizers);
}
/**
@ -135,9 +135,9 @@ public class TaskExecutorBuilder {
*/
public TaskExecutorBuilder maxPoolSize(int maxPoolSize) {
return new TaskExecutorBuilder(this.queueCapacity, this.corePoolSize, maxPoolSize,
this.allowCoreThreadTimeOut, this.keepAlive, this.threadNamePrefix,
this.awaitTermination, this.waitForTasksToCompleteOnShutdown,
this.taskDecorator, this.customizers);
this.allowCoreThreadTimeOut, this.keepAlive, this.awaitTermination,
this.awaitTerminationPeriod, this.threadNamePrefix, this.taskDecorator,
this.customizers);
}
/**
@ -149,9 +149,8 @@ public class TaskExecutorBuilder {
public TaskExecutorBuilder allowCoreThreadTimeOut(boolean allowCoreThreadTimeOut) {
return new TaskExecutorBuilder(this.queueCapacity, this.corePoolSize,
this.maxPoolSize, allowCoreThreadTimeOut, this.keepAlive,
this.threadNamePrefix, this.awaitTermination,
this.waitForTasksToCompleteOnShutdown, this.taskDecorator,
this.customizers);
this.awaitTermination, this.awaitTerminationPeriod, this.threadNamePrefix,
this.taskDecorator, this.customizers);
}
/**
@ -162,54 +161,51 @@ public class TaskExecutorBuilder {
public TaskExecutorBuilder keepAlive(Duration keepAlive) {
return new TaskExecutorBuilder(this.queueCapacity, this.corePoolSize,
this.maxPoolSize, this.allowCoreThreadTimeOut, keepAlive,
this.threadNamePrefix, this.awaitTermination,
this.waitForTasksToCompleteOnShutdown, this.taskDecorator,
this.customizers);
this.awaitTermination, this.awaitTerminationPeriod, this.threadNamePrefix,
this.taskDecorator, this.customizers);
}
/**
* Set the prefix to use for the names of newly created threads.
* @param threadNamePrefix the thread name prefix to set
* Set whether the executor should wait for scheduled tasks to complete on shutdown,
* not interrupting running tasks and executing all tasks in the queue.
* @param awaitTermination whether the executor needs to wait for the tasks to
* complete on shutdown
* @return a new builder instance
* @see #awaitTerminationPeriod(Duration)
*/
public TaskExecutorBuilder threadNamePrefix(String threadNamePrefix) {
public TaskExecutorBuilder awaitTermination(boolean awaitTermination) {
return new TaskExecutorBuilder(this.queueCapacity, this.corePoolSize,
this.maxPoolSize, this.allowCoreThreadTimeOut, this.keepAlive,
threadNamePrefix, this.awaitTermination,
this.waitForTasksToCompleteOnShutdown, this.taskDecorator,
this.customizers);
awaitTermination, this.awaitTerminationPeriod, this.threadNamePrefix,
this.taskDecorator, this.customizers);
}
/**
* Set the maximum number of time that the executor is supposed to block on shutdown
* in order to wait for remaining tasks to complete their execution before the rest of
* the container continues to shut down. This is particularly useful if your remaining
* tasks are likely to need access to other resources that are also managed by the
* container.
* @param awaitTermination the await termination to set
* Set the maximum time the executor is supposed to block on shutdown. When set, the
* executor blocks on shutdown in order to wait for remaining tasks to complete their
* execution before the rest of the container continues to shut down. This is
* particularly useful if your remaining tasks are likely to need access to other
* resources that are also managed by the container.
* @param awaitTerminationPeriod the await termination period to set
* @return a new builder instance
*/
public TaskExecutorBuilder awaitTermination(Duration awaitTermination) {
public TaskExecutorBuilder awaitTerminationPeriod(Duration awaitTerminationPeriod) {
return new TaskExecutorBuilder(this.queueCapacity, this.corePoolSize,
this.maxPoolSize, this.allowCoreThreadTimeOut, this.keepAlive,
this.threadNamePrefix, awaitTermination,
this.waitForTasksToCompleteOnShutdown, this.taskDecorator,
this.customizers);
this.awaitTermination, awaitTerminationPeriod, this.threadNamePrefix,
this.taskDecorator, this.customizers);
}
/**
* Set whether the executor should wait for scheduled tasks to complete on shutdown,
* not interrupting running tasks and executing all tasks in the queue.
* @param waitForTasksToCompleteOnShutdown if executor needs to wait for the tasks to
* complete on shutdown
* Set the prefix to use for the names of newly created threads.
* @param threadNamePrefix the thread name prefix to set
* @return a new builder instance
*/
public TaskExecutorBuilder waitForTasksToCompleteOnShutdown(
boolean waitForTasksToCompleteOnShutdown) {
public TaskExecutorBuilder threadNamePrefix(String threadNamePrefix) {
return new TaskExecutorBuilder(this.queueCapacity, this.corePoolSize,
this.maxPoolSize, this.allowCoreThreadTimeOut, this.keepAlive,
this.threadNamePrefix, this.awaitTermination,
waitForTasksToCompleteOnShutdown, this.taskDecorator, this.customizers);
this.awaitTermination, this.awaitTerminationPeriod, threadNamePrefix,
this.taskDecorator, this.customizers);
}
/**
@ -220,8 +216,8 @@ public class TaskExecutorBuilder {
public TaskExecutorBuilder taskDecorator(TaskDecorator taskDecorator) {
return new TaskExecutorBuilder(this.queueCapacity, this.corePoolSize,
this.maxPoolSize, this.allowCoreThreadTimeOut, this.keepAlive,
this.threadNamePrefix, this.awaitTermination,
this.waitForTasksToCompleteOnShutdown, taskDecorator, this.customizers);
this.awaitTermination, this.awaitTerminationPeriod, this.threadNamePrefix,
taskDecorator, this.customizers);
}
/**
@ -251,9 +247,8 @@ public class TaskExecutorBuilder {
Assert.notNull(customizers, "Customizers must not be null");
return new TaskExecutorBuilder(this.queueCapacity, this.corePoolSize,
this.maxPoolSize, this.allowCoreThreadTimeOut, this.keepAlive,
this.threadNamePrefix, this.awaitTermination,
this.waitForTasksToCompleteOnShutdown, this.taskDecorator,
append(null, customizers));
this.awaitTermination, this.awaitTerminationPeriod, this.threadNamePrefix,
this.taskDecorator, append(null, customizers));
}
/**
@ -283,9 +278,8 @@ public class TaskExecutorBuilder {
Assert.notNull(customizers, "Customizers must not be null");
return new TaskExecutorBuilder(this.queueCapacity, this.corePoolSize,
this.maxPoolSize, this.allowCoreThreadTimeOut, this.keepAlive,
this.threadNamePrefix, this.awaitTermination,
this.waitForTasksToCompleteOnShutdown, this.taskDecorator,
append(this.customizers, customizers));
this.awaitTermination, this.awaitTerminationPeriod, this.threadNamePrefix,
this.taskDecorator, append(this.customizers, customizers));
}
/**
@ -328,12 +322,12 @@ public class TaskExecutorBuilder {
map.from(this.keepAlive).asInt(Duration::getSeconds)
.to(taskExecutor::setKeepAliveSeconds);
map.from(this.allowCoreThreadTimeOut).to(taskExecutor::setAllowCoreThreadTimeOut);
map.from(this.awaitTermination)
.to(taskExecutor::setWaitForTasksToCompleteOnShutdown);
map.from(this.awaitTerminationPeriod).asInt(Duration::getSeconds)
.to(taskExecutor::setAwaitTerminationSeconds);
map.from(this.threadNamePrefix).whenHasText()
.to(taskExecutor::setThreadNamePrefix);
map.from(this.awaitTermination).asInt(Duration::getSeconds)
.to(taskExecutor::setAwaitTerminationSeconds);
map.from(this.waitForTasksToCompleteOnShutdown)
.to(taskExecutor::setWaitForTasksToCompleteOnShutdown);
map.from(this.taskDecorator).to(taskExecutor::setTaskDecorator);
if (!CollectionUtils.isEmpty(this.customizers)) {
this.customizers.forEach((customizer) -> customizer.customize(taskExecutor));

@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 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.
@ -56,24 +56,23 @@ public class TaskExecutorBuilderTests {
}
@Test
public void threadNamePrefixShouldApply() {
ThreadPoolTaskExecutor executor = this.builder.threadNamePrefix("test-").build();
assertThat(executor.getThreadNamePrefix()).isEqualTo("test-");
public void awaitTerminationShouldApply() {
ThreadPoolTaskExecutor executor = this.builder.awaitTermination(true).build();
assertThat(executor)
.hasFieldOrPropertyWithValue("waitForTasksToCompleteOnShutdown", true);
}
@Test
public void awaitTerminationShouldApply() {
public void awaitTerminationPeriodShouldApply() {
ThreadPoolTaskExecutor executor = this.builder
.awaitTermination(Duration.ofMinutes(1)).build();
.awaitTerminationPeriod(Duration.ofMinutes(1)).build();
assertThat(executor).hasFieldOrPropertyWithValue("awaitTerminationSeconds", 60);
}
@Test
public void waitForTasksToCompleteOnShutdownShouldApply() {
ThreadPoolTaskExecutor executor = this.builder
.waitForTasksToCompleteOnShutdown(true).build();
assertThat(executor)
.hasFieldOrPropertyWithValue("waitForTasksToCompleteOnShutdown", true);
public void threadNamePrefixShouldApply() {
ThreadPoolTaskExecutor executor = this.builder.threadNamePrefix("test-").build();
assertThat(executor.getThreadNamePrefix()).isEqualTo("test-");
}
@Test
@ -113,17 +112,17 @@ public class TaskExecutorBuilderTests {
ThreadPoolTaskExecutor executor = spy(new ThreadPoolTaskExecutor());
this.builder.queueCapacity(10).corePoolSize(4).maxPoolSize(8)
.allowCoreThreadTimeOut(true).keepAlive(Duration.ofMinutes(1))
.threadNamePrefix("test-").awaitTermination(Duration.ofSeconds(30))
.waitForTasksToCompleteOnShutdown(true).taskDecorator(taskDecorator)
.awaitTermination(true).awaitTerminationPeriod(Duration.ofSeconds(30))
.threadNamePrefix("test-").taskDecorator(taskDecorator)
.additionalCustomizers((taskExecutor) -> {
verify(taskExecutor).setQueueCapacity(10);
verify(taskExecutor).setCorePoolSize(4);
verify(taskExecutor).setMaxPoolSize(8);
verify(taskExecutor).setAllowCoreThreadTimeOut(true);
verify(taskExecutor).setKeepAliveSeconds(60);
verify(taskExecutor).setThreadNamePrefix("test-");
verify(taskExecutor).setAwaitTerminationSeconds(30);
verify(taskExecutor).setWaitForTasksToCompleteOnShutdown(true);
verify(taskExecutor).setAwaitTerminationSeconds(30);
verify(taskExecutor).setThreadNamePrefix("test-");
verify(taskExecutor).setTaskDecorator(taskDecorator);
});
this.builder.configure(executor);

Loading…
Cancel
Save