Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spring Boot 3.4: TaskExecutor no longer auto-configured due to other Executor beans from AbstractMessageBrokerConfiguration #43295

Open
SebastianS90 opened this issue Nov 26, 2024 · 4 comments
Labels
status: feedback-provided Feedback has been provided status: waiting-for-triage An issue we've not yet triaged

Comments

@SebastianS90
Copy link

After upgrading to Spring Boot 3.4, the application does not start:

(one of my own classes) required a bean of type 'org.springframework.core.task.TaskExecutor' that could not be found.

The reason why this bean is missing and not created by org.springframework.boot.autoconfigure.task.TaskExecutorConfigurations:

TaskExecutorConfigurations.TaskExecutorConfiguration:
      Did not match:
         - @ConditionalOnMissingBean (types: java.util.concurrent.Executor; SearchStrategy: all) found beans of type 'java.util.concurrent.Executor' clientInboundChannelExecutor, clientOutboundChannelExecutor, brokerChannelExecutor (OnBeanCondition)

Auto configuration is here:

class TaskExecutorConfigurations {
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(Executor.class)
static class TaskExecutorConfiguration {

One of the existing beans is created here.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Nov 26, 2024
@wilkinsona
Copy link
Member

Thanks for the report.

Unfortunately, it's not clear to me why you believe the Executor beans in AbstractMessageBrokerConfiguration to be the cause. Those beans were also defined in Spring Framework 6.1 (Boot 3.2 and 3.3) albeit as a TaskExecutor rather than an Executor. TaskExecutor extends Executor so that should make no difference to the behavior of TaskExecutorConfiguration which I don't believe has changed in Boot 3.4.

If you would like us to spend some more time investigating, and to help us to understand what's happening in your application, please spend some time providing a complete yet minimal sample that reproduces the problem. You can share it with us by pushing it to a separate repository on GitHub or by zipping it up and attaching it to this issue.

@wilkinsona wilkinsona added the status: waiting-for-feedback We need additional information before we can continue label Nov 26, 2024
SebastianS90 added a commit to SebastianS90/spring-boot-issue-43295 that referenced this issue Nov 26, 2024
@SebastianS90
Copy link
Author

Please see here for a minimal reproduction. In particular, removing this line resolves the issue of not finding the TaskExecutor bean, but obviously is not a solution.

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Nov 26, 2024
@wilkinsona
Copy link
Member

Thanks for the sample.

In terms of auto-configuration, the behavior hasn't changed. This is with Spring Boot 3.4.0:

   TaskExecutorConfigurations.TaskExecutorConfiguration:
      Did not match:
         - @ConditionalOnMissingBean (types: java.util.concurrent.Executor; SearchStrategy: all) found beans of type 'java.util.concurrent.Executor' clientInboundChannelExecutor, clientOutboundChannelExecutor, brokerChannelExecutor (OnBeanCondition)

And this is from Spring Boot 3.3.6:

   TaskExecutorConfigurations.TaskExecutorConfiguration:
      Did not match:
         - @ConditionalOnMissingBean (types: java.util.concurrent.Executor; SearchStrategy: all) found beans of type 'java.util.concurrent.Executor' clientInboundChannelExecutor, clientOutboundChannelExecutor, brokerChannelExecutor (OnBeanCondition)

What has changed is the type of those beans that prevents the auto-configuration of a TaskExecutor. In Spring Boot 3.3.x, they're TaskExecutor instances, but in 3.4.x, they're just defined as Executor instances. This means they can't be injected and the app fails to start.

If I downgrade your sample to Spring Boot 3.3.6, it still fails to start, but for a different reason:

Parameter 0 of constructor in com.example.demo.DemoComponent required a single bean, but 3 were found:
        - clientInboundChannelExecutor: defined by method 'clientInboundChannelExecutor' in org.springframework.web.socket.config.annotation.DelegatingWebSocketMessageBrokerConfiguration
        - clientOutboundChannelExecutor: defined by method 'clientOutboundChannelExecutor' in org.springframework.web.socket.config.annotation.DelegatingWebSocketMessageBrokerConfiguration
        - brokerChannelExecutor: defined by method 'brokerChannelExecutor' in org.springframework.web.socket.config.annotation.DelegatingWebSocketMessageBrokerConfiguration

In your real app, how were you selecting which executor to use? I'm also wondering if you really intended to be using a WebSocket-related executor for presumably more general purposes.

@wilkinsona wilkinsona added status: waiting-for-feedback We need additional information before we can continue and removed status: feedback-provided Feedback has been provided labels Nov 26, 2024
@SebastianS90
Copy link
Author

Thanks for the investigation.

In my real app, the code was originally written with Spring Boot 2.6.7 and the dependency was a constructor parameter AsyncListenableTaskExecutor applicationTaskExecutor. As far as I can remember, the parameter name was important at that time to disambiguate.
With the upgrade to Spring Boot 3.0, the constructor parameter changed to AsyncTaskExecutor applicationTaskExecutor and was not touched ever since.

Further investigation showed that you are right that it is not the upgrade to Spring Boot 3.4 that causes the issue: I have another bean with a org.springframework.scheduling.TaskScheduler taskScheduler dependency that I got rid of during the upgrade. While the other bean has that dependency, the AsyncTaskExecutor applicationTaskExecutor dependency gets provided with an instance of org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler. When I remove the TaskScheduler dependency from the other bean, then I end up with required a bean of type 'org.springframework.core.task.AsyncTaskExecutor' that could not be found, even in Spring Boot 3.3.6. Sorry for the confusion there, I really thought that it must have been the update causing it.

However, I am unable to reproduce this in a minimal environment. It might depend on the order that classes are discovered by component scanning.

So to wrap things up, the question is whether TaskExecutionAutoConfiguration should create its Executor even when there are special instances already present. If you decide against it and keep the @ConditionalOnMissingBean(Executor.class) annotation, then the workaround is to copy these lines into a custom @Configuration class:

@Bean(name = { TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME,
AsyncAnnotationBeanPostProcessor.DEFAULT_TASK_EXECUTOR_BEAN_NAME })
@ConditionalOnThreading(Threading.VIRTUAL)
SimpleAsyncTaskExecutor applicationTaskExecutorVirtualThreads(SimpleAsyncTaskExecutorBuilder builder) {
return builder.build();
}
@Lazy
@Bean(name = { TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME,
AsyncAnnotationBeanPostProcessor.DEFAULT_TASK_EXECUTOR_BEAN_NAME })
@ConditionalOnThreading(Threading.PLATFORM)
ThreadPoolTaskExecutor applicationTaskExecutor(ThreadPoolTaskExecutorBuilder threadPoolTaskExecutorBuilder) {
return threadPoolTaskExecutorBuilder.build();
}

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Nov 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: feedback-provided Feedback has been provided status: waiting-for-triage An issue we've not yet triaged
Projects
None yet
Development

No branches or pull requests

3 participants