Hi

Yes you are welcome to create a JIRA and send a PR thanks

On Mon, Dec 9, 2024 at 7:37 PM Björn Beskow <
bjorn.bes...@callistaenterprise.se> wrote:

> 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
>
>

-- 
Claus Ibsen
-----------------
@davsclaus
Camel in Action 2: https://www.manning.com/ibsen2

Reply via email to