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

When virtual threads are enabled, configure Spring Integration's task scheduler to use them #41188

Open
csh0034 opened this issue Jun 21, 2024 · 6 comments
Labels
type: enhancement A general enhancement
Milestone

Comments

@csh0034
Copy link

csh0034 commented Jun 21, 2024

In the PR below, WebSocketMessagingAutoConfiguration has been modified to use a virtual thread executor

#39611

public class WebSocketMessagingAutoConfiguration {
  // ...
  WebSocketMessageConverterConfiguration(ObjectMapper objectMapper,
    Map<String, AsyncTaskExecutor> taskExecutors) {
    this.objectMapper = objectMapper;
    this.executor = determineAsyncTaskExecutor(taskExecutors);
  }

  private static AsyncTaskExecutor determineAsyncTaskExecutor(Map<String, AsyncTaskExecutor> taskExecutors) {
    if (taskExecutors.size() == 1) {
      return taskExecutors.values().iterator().next();
    }
    return taskExecutors.get(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME);
  }

  // ...
}

Upon checking the taskExecutors being injected, it is taskScheduler.
When used with spring-integration, the following Bean is being configured first.
Is it possible to modify it to allow for auto-configuration?

@Configuration(proxyBeanMethods = false)
@ConditionalOnBean(TaskSchedulerBuilder.class)
@ConditionalOnMissingBean(name = IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME)
@SuppressWarnings("removal")
public class IntegrationAutoConfiguration {
  // ..
  protected static class IntegrationTaskSchedulerConfiguration {
    @Bean(name = IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME)
    public ThreadPoolTaskScheduler taskScheduler(TaskSchedulerBuilder taskSchedulerBuilder,
      ObjectProvider<ThreadPoolTaskSchedulerBuilder> threadPoolTaskSchedulerBuilderProvider) {
      // ...
    }
  }
  // ..
}

Below is the configuration added without using auto-configuration.

@Configuration
class ExecutorConfig {
  @Bean(
    name = [
      TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME,
      AsyncAnnotationBeanPostProcessor.DEFAULT_TASK_EXECUTOR_BEAN_NAME
    ]
  )
  fun applicationTaskExecutorVirtualThreads(builder: SimpleAsyncTaskExecutorBuilder): SimpleAsyncTaskExecutor {
    return builder.build()
  }
}

Of course, the bottom properties are also set.

spring:
  threads:
    virtual:
      enabled: true
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jun 21, 2024
@mhalbritter
Copy link
Contributor

mhalbritter commented Jun 21, 2024

Ah, hm, IntegrationAutoConfiguration.IntegrationTaskSchedulerConfiguration#taskScheduler is executed if there's no taskScheduler bean. TaskSchedulingConfigurations.TaskSchedulerConfiguration#taskSchedulerVirtualThreads creates such a bean, but only if @EnableScheduling has been used on the main class.

So I guess we should make IntegrationTaskSchedulerConfiguration virtual threads aware.

The workaround for now is to add @EnableScheduling on the main class (or any other @Configuration class).

@mhalbritter mhalbritter changed the title TaskExecutor Configuration when Using Virtual Threads in WebSocket with spring integration When virtual threads are enabled, configure Spring Integration's task scheduler to use them Jun 21, 2024
@mhalbritter mhalbritter added type: enhancement A general enhancement and removed status: waiting-for-triage An issue we've not yet triaged labels Jun 21, 2024
@mhalbritter mhalbritter added this to the 3.3.x milestone Jun 21, 2024
@csh0034
Copy link
Author

csh0034 commented Jun 21, 2024

@mhalbritter
I understand that IntegrationTaskSchedulerConfiguration needs to recognize virtual threads.

However, even when adding the following configuration, IntegrationTaskSchedulerConfiguration is called before TaskSchedulerConfiguration, and TaskSchedulingConfigurations.TaskSchedulerConfiguration#taskSchedulerVirtualThreads is not called.

@Configuration
@EnableScheduling
class ScheduleConfig

Is there a priority issue?

Additionally, as mentioned in the initial question, the executor assigned to WebSocketMessageConverterConfiguration should be TaskSchedulerConfiguration.TaskSchedulerConfiguration#taskSchedulerVirtualThreads, but this method is not called at all.
WebSocketMessageConverterConfiguration.determineAsyncTaskExecutor only has the taskScheduler created in IntegrationAutoConfiguration.IntegrationTaskSchedulerConfiguration#taskScheduler

e9bf2b3

Should I provide a sample for verification?

@mhalbritter
Copy link
Contributor

Should I provide a sample for verification?

Yes, please.

@csh0034
Copy link
Author

csh0034 commented Jun 21, 2024

websocket-sample.zip

p.s. Even though I'm not using SockJS, I noticed that defaultSockJsSchedulerContainer is added in WebSocketMessageConverterConfiguration.determineAsyncTaskExecutor

It wasn't there in version 3.3.0, but it appears in version 3.3.1. I don't understand the reason for this change.

@csh0034
Copy link
Author

csh0034 commented Jun 24, 2024

It seems that the reason TaskSchedulingConfigurations.TaskSchedulerConfiguration#taskSchedulerVirtualThreads is not being called is due to AbstractMessageBrokerConfiguration#messageBrokerTaskScheduler.

TaskSchedulingConfigurations.TaskSchedulerConfiguration:
      Did not match:
         - @ConditionalOnMissingBean (types: org.springframework.scheduling.TaskScheduler,java.util.concurrent.ScheduledExecutorService; SearchStrategy: all) found beans of type 'org.springframework.scheduling.TaskScheduler' messageBrokerTaskScheduler (OnBeanCondition)

@csh0034
Copy link
Author

csh0034 commented Jun 24, 2024

The AbstractMessageBrokerConfiguration in Spring has been modified to use the executor registered in ChannelRegistration, and WebSocketMessagingAutoConfiguration in Spring Boot has been changed to inject the auto-configured executor into ChannelRegistration.

However, due to the various Beans declared in Spring's AbstractMessageBrokerConfiguration, TaskExecutorConfigurations.TaskExecutorConfiguration in Spring Boot is not called.

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)

I'm adding this comment here because I'm unsure where to raise this issue.

@mhalbritter mhalbritter modified the milestones: 3.3.x, 3.4.x Jun 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

3 participants