Hi!
I think there might be a regression problem in camel-platform-http-starter
introduced in 4.9.0 and 4.8.2 related to using Virtual Threads. If
spring.threads.virtual.enabled = true, a Camel application that uses
camel-platform-http-starter fails at startup with
Caused by: java.lang.RuntimeException: No ThreadPoolTaskExecutor configured
at
org.apache.camel.component.platform.http.springboot.SpringBootPlatformHttpAutoConfiguration.lambda$springBootPlatformHttpEngine$1(SpringBootPlatformHttpAutoConfiguration.java:54)
~[camel-platform-http-starter-4.9.0.jar:4.9.0]
at java.base/java.util.Optional.orElseThrow(Optional.java:403) ~[na:na]
at
org.apache.camel.component.platform.http.springboot.SpringBootPlatformHttpAutoConfiguration.springBootPlatformHttpEngine(SpringBootPlatformHttpAutoConfiguration.java:54)
~[camel-platform-http-starter-4.9.0.jar:4.9.0]
at
java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[na:na]
at
org.springframework.beans.factory.support.SimpleInstantiationStrategy.lambda$instantiate$0(SimpleInstantiationStrategy.java:171)
~[spring-beans-6.2.0.jar:6.2.0]
... 24 common frames omitted
unless a ThreadPoolTaskExecutor is explicitly configured.
The problem seems to be caused by
https://github.com/apache/camel-spring-boot/pull/1278/commits/cd4deb0eda78054641056eb948a797b0a5a04560
which now requires a ThreadPoolTaskExecutor to be configured:
@Bean(name = "platform-http-engine")
@ConditionalOnMissingBean(PlatformHttpEngine.class)
public PlatformHttpEngine springBootPlatformHttpEngine(Environment env) {
Executor executor;
if (executors != null && !executors.isEmpty()) {
executor = executors.stream()
.filter(e -> e instanceof ThreadPoolTaskExecutor)
.findFirst()
.orElseThrow(() -> new RuntimeException("No
ThreadPoolTaskExecutor configured"));
} else {
throw new RuntimeException("No Executor configured");
}
int port = Integer.parseInt(env.getProperty("server.port", "8080"));
return new SpringBootPlatformHttpEngine(port, executor);
}
If using virtual threads, the default auto-configuration of an executor
(defined in TaskExecutorConfiguration) instead uses a SimpleAsyncTaskExecutor:
class TaskExecutorConfigurations {
TaskExecutorConfigurations() {
}
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnMissingBean({Executor.class})
static class TaskExecutorConfiguration {
TaskExecutorConfiguration() {
}
@Bean(
name = {"applicationTaskExecutor", "taskExecutor"}
)
@ConditionalOnThreading(Threading.VIRTUAL)
SimpleAsyncTaskExecutor
applicationTaskExecutorVirtualThreads(SimpleAsyncTaskExecutorBuilder builder) {
return builder.build();
}
@Lazy
@Bean(
name = {"applicationTaskExecutor", "taskExecutor"}
)
@ConditionalOnThreading(Threading.PLATFORM)
ThreadPoolTaskExecutor
applicationTaskExecutor(ThreadPoolTaskExecutorBuilder
threadPoolTaskExecutorBuilder) {
return threadPoolTaskExecutorBuilder.build();
}
}
Hence no ThreadPoolTaskExecutor instance exists by default, and therefore the
exception is thrown.
A simple workaround I use know is to explicitly configure a
ThreadPoolTaskExecutor instance (and instruct it to use virtual threads):
@Configuration
public class VirtualThreadPoolTaskExecutorConfig {
@Bean
@ConditionalOnMissingBean(AsyncTaskExecutor.class)
ThreadPoolTaskExecutor threadPoolTaskExecutor(ThreadPoolTaskExecutorBuilder
builder) {
ThreadPoolTaskExecutor threadPoolTaskExecutor = builder.build();
threadPoolTaskExecutor.setVirtualThreads(true);
return threadPoolTaskExecutor;
}
}
But I think the original problem should be fixed, for instance by accepting
both a ThreadPoolTaskExecutor or a SimpleAsyncTaskExecutor in the newly added
code:
public PlatformHttpEngine springBootPlatformHttpEngine(Environment env) {
...
.filter(e -> e instanceof ThreadPoolTaskExecutor || e
instanceof SimpleAsyncTaskExecutor)
…
Not pretty, but works.
Have I misunderstood something?
If you agree it is a problem, I’ll submit a ticket and a pull request with
integration tests triggering the error together with the suggested fix
/Björn