Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ public void setThreadNamePrefix(String threadNamePrefix) {

public static class Simple {

/**
* Whether to cancel remaining tasks on close.
*/
private boolean cancelRemainingTasksOnClose;

/**
* Whether to reject tasks when the concurrency limit has been reached.
*/
Expand All @@ -90,6 +95,14 @@ public static class Simple {
*/
private @Nullable Integer concurrencyLimit;

public boolean isCancelRemainingTasksOnClose() {
return this.cancelRemainingTasksOnClose;
}

public void setCancelRemainingTasksOnClose(boolean cancelRemainingTasksOnClose) {
this.cancelRemainingTasksOnClose = cancelRemainingTasksOnClose;
}

public boolean isRejectTasksWhenLimitReached() {
return this.rejectTasksWhenLimitReached;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ private SimpleAsyncTaskExecutorBuilder builder() {
builder = builder.customizers(this.taskExecutorCustomizers.orderedStream()::iterator);
builder = builder.taskDecorator(getTaskDecorator(this.taskDecorator));
TaskExecutionProperties.Simple simple = this.properties.getSimple();
builder = builder.cancelRemainingTasksOnClose(simple.isCancelRemainingTasksOnClose());
builder = builder.rejectTasksWhenLimitReached(simple.isRejectTasksWhenLimitReached());
builder = builder.concurrencyLimit(simple.getConcurrencyLimit());
TaskExecutionProperties.Shutdown shutdown = this.properties.getShutdown();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,13 @@ void shouldSupplyBeans() {
void simpleAsyncTaskExecutorBuilderShouldReadProperties() {
this.contextRunner
.withPropertyValues("spring.task.execution.thread-name-prefix=mytest-",
"spring.task.execution.simple.cancel-remaining-tasks-on-close=true",
"spring.task.execution.simple.reject-tasks-when-limit-reached=true",
"spring.task.execution.simple.concurrency-limit=1",
"spring.task.execution.shutdown.await-termination=true",
"spring.task.execution.shutdown.await-termination-period=30s")
.run(assertSimpleAsyncTaskExecutor((taskExecutor) -> {
assertThat(taskExecutor).hasFieldOrPropertyWithValue("cancelRemainingTasksOnClose", true);
assertThat(taskExecutor).hasFieldOrPropertyWithValue("rejectTasksWhenLimitReached", true);
assertThat(taskExecutor.getConcurrencyLimit()).isEqualTo(1);
assertThat(taskExecutor.getThreadNamePrefix()).isEqualTo("mytest-");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ public class SimpleAsyncTaskExecutorBuilder {

private final @Nullable String threadNamePrefix;

private final boolean cancelRemainingTasksOnClose;

private final boolean rejectTasksWhenLimitReached;

private final @Nullable Integer concurrencyLimit;
Expand All @@ -63,15 +65,16 @@ public class SimpleAsyncTaskExecutorBuilder {
private final @Nullable Duration taskTerminationTimeout;

public SimpleAsyncTaskExecutorBuilder() {
this(null, null, false, null, null, null, null);
this(null, null, false, false, null, null, null, null);
}

private SimpleAsyncTaskExecutorBuilder(@Nullable Boolean virtualThreads, @Nullable String threadNamePrefix,
boolean rejectTasksWhenLimitReached, @Nullable Integer concurrencyLimit,
@Nullable TaskDecorator taskDecorator, @Nullable Set<SimpleAsyncTaskExecutorCustomizer> customizers,
@Nullable Duration taskTerminationTimeout) {
boolean cancelRemainingTasksOnClose, boolean rejectTasksWhenLimitReached,
@Nullable Integer concurrencyLimit, @Nullable TaskDecorator taskDecorator,
@Nullable Set<SimpleAsyncTaskExecutorCustomizer> customizers, @Nullable Duration taskTerminationTimeout) {
this.virtualThreads = virtualThreads;
this.threadNamePrefix = threadNamePrefix;
this.cancelRemainingTasksOnClose = cancelRemainingTasksOnClose;
this.rejectTasksWhenLimitReached = rejectTasksWhenLimitReached;
this.concurrencyLimit = concurrencyLimit;
this.taskDecorator = taskDecorator;
Expand All @@ -86,8 +89,8 @@ private SimpleAsyncTaskExecutorBuilder(@Nullable Boolean virtualThreads, @Nullab
*/
public SimpleAsyncTaskExecutorBuilder threadNamePrefix(@Nullable String threadNamePrefix) {
return new SimpleAsyncTaskExecutorBuilder(this.virtualThreads, threadNamePrefix,
this.rejectTasksWhenLimitReached, this.concurrencyLimit, this.taskDecorator, this.customizers,
this.taskTerminationTimeout);
this.cancelRemainingTasksOnClose, this.rejectTasksWhenLimitReached, this.concurrencyLimit,
this.taskDecorator, this.customizers, this.taskTerminationTimeout);
}

/**
Expand All @@ -97,8 +100,26 @@ public SimpleAsyncTaskExecutorBuilder threadNamePrefix(@Nullable String threadNa
*/
public SimpleAsyncTaskExecutorBuilder virtualThreads(@Nullable Boolean virtualThreads) {
return new SimpleAsyncTaskExecutorBuilder(virtualThreads, this.threadNamePrefix,
this.rejectTasksWhenLimitReached, this.concurrencyLimit, this.taskDecorator, this.customizers,
this.taskTerminationTimeout);
this.cancelRemainingTasksOnClose, this.rejectTasksWhenLimitReached, this.concurrencyLimit,
this.taskDecorator, this.customizers, this.taskTerminationTimeout);
}

/**
* Set whether to cancel remaining tasks on close. By default {@code false} not
* tracking active threads at all or just interrupting any remaining threads that
* still have not finished after the specified {@link #taskTerminationTimeout
* taskTerminationTimeout}. Switch this to {@code true} for immediate interruption on
* close, either in combination with a subsequent termination timeout or without any
* waiting at all, depending on whether a {@code taskTerminationTimeout} has been
* specified as well.
* @param cancelRemainingTasksOnClose whether to cancel remaining tasks on close
* @return a new builder instance
* @since 4.0.0
*/
public SimpleAsyncTaskExecutorBuilder cancelRemainingTasksOnClose(boolean cancelRemainingTasksOnClose) {
return new SimpleAsyncTaskExecutorBuilder(this.virtualThreads, this.threadNamePrefix,
cancelRemainingTasksOnClose, this.rejectTasksWhenLimitReached, this.concurrencyLimit,
this.taskDecorator, this.customizers, this.taskTerminationTimeout);
}

/**
Expand All @@ -112,8 +133,8 @@ public SimpleAsyncTaskExecutorBuilder virtualThreads(@Nullable Boolean virtualTh
*/
public SimpleAsyncTaskExecutorBuilder rejectTasksWhenLimitReached(boolean rejectTasksWhenLimitReached) {
return new SimpleAsyncTaskExecutorBuilder(this.virtualThreads, this.threadNamePrefix,
rejectTasksWhenLimitReached, this.concurrencyLimit, this.taskDecorator, this.customizers,
this.taskTerminationTimeout);
this.cancelRemainingTasksOnClose, rejectTasksWhenLimitReached, this.concurrencyLimit,
this.taskDecorator, this.customizers, this.taskTerminationTimeout);
}

/**
Expand All @@ -123,8 +144,8 @@ public SimpleAsyncTaskExecutorBuilder rejectTasksWhenLimitReached(boolean reject
*/
public SimpleAsyncTaskExecutorBuilder concurrencyLimit(@Nullable Integer concurrencyLimit) {
return new SimpleAsyncTaskExecutorBuilder(this.virtualThreads, this.threadNamePrefix,
this.rejectTasksWhenLimitReached, concurrencyLimit, this.taskDecorator, this.customizers,
this.taskTerminationTimeout);
this.cancelRemainingTasksOnClose, this.rejectTasksWhenLimitReached, concurrencyLimit,
this.taskDecorator, this.customizers, this.taskTerminationTimeout);
}

/**
Expand All @@ -134,8 +155,8 @@ public SimpleAsyncTaskExecutorBuilder concurrencyLimit(@Nullable Integer concurr
*/
public SimpleAsyncTaskExecutorBuilder taskDecorator(@Nullable TaskDecorator taskDecorator) {
return new SimpleAsyncTaskExecutorBuilder(this.virtualThreads, this.threadNamePrefix,
this.rejectTasksWhenLimitReached, this.concurrencyLimit, taskDecorator, this.customizers,
this.taskTerminationTimeout);
this.cancelRemainingTasksOnClose, this.rejectTasksWhenLimitReached, this.concurrencyLimit,
taskDecorator, this.customizers, this.taskTerminationTimeout);
}

/**
Expand All @@ -146,8 +167,8 @@ public SimpleAsyncTaskExecutorBuilder taskDecorator(@Nullable TaskDecorator task
*/
public SimpleAsyncTaskExecutorBuilder taskTerminationTimeout(@Nullable Duration taskTerminationTimeout) {
return new SimpleAsyncTaskExecutorBuilder(this.virtualThreads, this.threadNamePrefix,
this.rejectTasksWhenLimitReached, this.concurrencyLimit, this.taskDecorator, this.customizers,
taskTerminationTimeout);
this.cancelRemainingTasksOnClose, this.rejectTasksWhenLimitReached, this.concurrencyLimit,
this.taskDecorator, this.customizers, taskTerminationTimeout);
}

/**
Expand Down Expand Up @@ -177,8 +198,8 @@ public SimpleAsyncTaskExecutorBuilder customizers(
Iterable<? extends SimpleAsyncTaskExecutorCustomizer> customizers) {
Assert.notNull(customizers, "'customizers' must not be null");
return new SimpleAsyncTaskExecutorBuilder(this.virtualThreads, this.threadNamePrefix,
this.rejectTasksWhenLimitReached, this.concurrencyLimit, this.taskDecorator, append(null, customizers),
this.taskTerminationTimeout);
this.cancelRemainingTasksOnClose, this.rejectTasksWhenLimitReached, this.concurrencyLimit,
this.taskDecorator, append(null, customizers), this.taskTerminationTimeout);
}

/**
Expand Down Expand Up @@ -206,8 +227,8 @@ public SimpleAsyncTaskExecutorBuilder additionalCustomizers(
Iterable<? extends SimpleAsyncTaskExecutorCustomizer> customizers) {
Assert.notNull(customizers, "'customizers' must not be null");
return new SimpleAsyncTaskExecutorBuilder(this.virtualThreads, this.threadNamePrefix,
this.rejectTasksWhenLimitReached, this.concurrencyLimit, this.taskDecorator,
append(this.customizers, customizers), this.taskTerminationTimeout);
this.cancelRemainingTasksOnClose, this.rejectTasksWhenLimitReached, this.concurrencyLimit,
this.taskDecorator, append(this.customizers, customizers), this.taskTerminationTimeout);
}

/**
Expand Down Expand Up @@ -246,6 +267,7 @@ public <T extends SimpleAsyncTaskExecutor> T configure(T taskExecutor) {
PropertyMapper map = PropertyMapper.get();
map.from(this.virtualThreads).to(taskExecutor::setVirtualThreads);
map.from(this.threadNamePrefix).whenHasText().to(taskExecutor::setThreadNamePrefix);
map.from(this.cancelRemainingTasksOnClose).to(taskExecutor::setCancelRemainingTasksOnClose);
map.from(this.rejectTasksWhenLimitReached).to(taskExecutor::setRejectTasksWhenLimitReached);
map.from(this.concurrencyLimit).to(taskExecutor::setConcurrencyLimit);
map.from(this.taskDecorator).to(taskExecutor::setTaskDecorator);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ void virtualThreadsShouldApply() {
SimpleAsyncTaskExecutorAssert.assertThat(executor).usesVirtualThreads();
}

@Test
void cancelRemainingTasksOnCloseShouldApply() {
SimpleAsyncTaskExecutor executor = this.builder.cancelRemainingTasksOnClose(true).build();
assertThat(executor).extracting("cancelRemainingTasksOnClose").isEqualTo(true);
}

@Test
void rejectTasksWhenLimitReachedShouldApply() {
SimpleAsyncTaskExecutor executor = this.builder.rejectTasksWhenLimitReached(true).build();
Expand Down