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

Introduce @BatchTaskExecutor to make it easier to configure Spring Batch to use a custom task executor #40040

Closed
commonquail opened this issue Mar 20, 2024 · 9 comments
Assignees
Labels
type: enhancement A general enhancement
Milestone

Comments

@commonquail
Copy link

This is #1655 again, with the catch that BatchConfigurer (BasicBatchConfigurer?) is not available in Spring Boot 3. Therefore, the Spring Boot autoconfigured Spring Batch JobLauncher's TaskExecutor cannot be directly customized at all. Users can only provide an alternative JobLauncher bean, as demonstrated in that issue, or forgo Spring Boot's autoconfiguration entirely.

The practical impact of this does not appear significant. It is evident from inspecting the autoconfiguration that it is aimed at command line runners, where synchronous execution seems reasonable to me. In a web context synchronous execution is possibly an acceptable default (debatable, but all right) but the inability to switch to asynchronous execution is not acceptable, however, the autoconfiguration does not help a web context much at all so opting out of it is a minor issue.

Although I think the executor should be possible to configure I might well argue that the bigger issue is that the Spring Boot reference documentation could be clearer about where the autoconfiguration is useful and where it is preferable to skip it.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Mar 20, 2024
@wilkinsona wilkinsona changed the title Spring Boot 3.2: cannot create asynchronous JobLauncher Making it easier to replace beans that are auto-configured by SpringBootBatchConfiguration Mar 22, 2024
@wilkinsona
Copy link
Member

I think we could achieve this by having SpringBootBatchConfiguration override the @Bean methods that are declared in DefaultBatchConfiguration and marking them as @ConditionalOnMissingBean. This would be similar to what we've done for some Spring MVC-related beans:

@Override
@Bean
@ConditionalOnMissingBean(name = DispatcherServlet.LOCALE_RESOLVER_BEAN_NAME)
public LocaleResolver localeResolver() {
if (this.webProperties.getLocaleResolver() == WebProperties.LocaleResolver.FIXED) {
return new FixedLocaleResolver(this.webProperties.getLocale());
}
AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
localeResolver.setDefaultLocale(this.webProperties.getLocale());
return localeResolver;
}
@Override
@Bean
@ConditionalOnMissingBean(name = DispatcherServlet.THEME_RESOLVER_BEAN_NAME)
@Deprecated(since = "3.0.0", forRemoval = false)
@SuppressWarnings("deprecation")
public org.springframework.web.servlet.ThemeResolver themeResolver() {
return super.themeResolver();
}
@Override
@Bean
@ConditionalOnMissingBean(name = DispatcherServlet.FLASH_MAP_MANAGER_BEAN_NAME)
public FlashMapManager flashMapManager() {
return super.flashMapManager();
}

@wilkinsona wilkinsona added type: enhancement A general enhancement and removed status: waiting-for-triage An issue we've not yet triaged labels Mar 27, 2024
@wilkinsona wilkinsona added this to the 3.x milestone Mar 27, 2024
@micheljung
Copy link

@wilkinsona correct me if I'm wrong, but this won't work because then you'd get duplicate beans: one from the superclass an one from your subclass.

import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@SpringBootApplication
class DemoApplication

fun main(args: Array<String>) {
  val context = SpringApplication.run(DemoApplication::class.java, *args)
  println(context.getBean("text"))
}

@Configuration(proxyBeanMethods = false)
class SuperBeans {
  @Bean
  fun text() = "Hello"
}

@Configuration(proxyBeanMethods = false)
class SubBeans : SuperBeans() {
  @Bean
  override fun text() = "World"
}

Results in

org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'text' defined in class path resource [...] since there is already [...]

@wilkinsona
Copy link
Member

@micheljung this works fine as shown by the Spring MVC example to which I have linked above. The arrangement you've shown isn't the same as we've used in EnableWebMvcConfiguration . You're using component scanning which means that both SubBeans and SuperBeans are registered as configuration classes. In the auto-configuration case, only EnableWebMvcConfiguration is registered. DelegatingWebMvcConfiguration, that it extends, is not registered. In the batch case, SpringBootBatchConfiguration would be registered but DefaultBatchConfiguration would not be.

@fmbenhassine
Copy link
Contributor

This is a valid point. Currently, as a boot user, I can provide a batch datasource and it will be set on the job repository, without having to (re)define the job repository. I should be able to do the same with the task executor of the job launcher, meaning I should be able to specify a task executor to use for batch without having to define the job launcher.

However, in my experience with users mixing web requests and batch workloads (ie running batch jobs in the same JVM as the servlet container), it is common that people do not want to use the same thread pool for web and batch requests (different pool sizes, different prefixes, etc). Therefore, it should be possible to specify a dedicated task executor for batch. What about a new annotation @BatchTaskExecutor similar to the one for the datasource and transaction manager?

@fmbenhassine
Copy link
Contributor

What about a new annotation @BatchTaskExecutor similar to the one for the datasource and transaction manager?

Have you got a chance to think about this? I believe it is the easiest, most straightforward and consistent approach to tackle the problem. If you agree on the idea, is it possible to include it in Boot 3.4 (Batch 5.2)?

@wilkinsona
Copy link
Member

With only a week to go before RC1, Boot 3.5 is the more likely at this point I'm afraid.

@wilkinsona wilkinsona changed the title Making it easier to replace beans that are auto-configured by SpringBootBatchConfiguration Introduce @BatchTaskExecutor to make it easier to configure Spring Batch to use a custom task executor Oct 22, 2024
@wilkinsona wilkinsona self-assigned this Oct 22, 2024
@wilkinsona wilkinsona modified the milestones: 3.x, 3.4.x Oct 22, 2024
@wilkinsona
Copy link
Member

I was a week ahead of myself so we had a bit more time than I thought.

What about a new annotation @BatchTaskExecutor similar to the one for the datasource and transaction manager?

I think this is a good idea. It's less involved than overriding @Bean methods and directly supports the originally raised requirement which is to be able to customize the TaskExecutor that's used by Batch.

I'll see if we can get this into 3.4 after all.

@wilkinsona wilkinsona modified the milestones: 3.4.x, 3.4.0-RC1 Oct 22, 2024
@fmbenhassine
Copy link
Contributor

This is fantastic! Thank you very much, @wilkinsona.

@commonquail
Copy link
Author

Pretty cool!

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

5 participants