I'm using Spring Boot and have configured a ThreadPoolTaskExecutor as follows:
#Data
#Configuration
public class WorkflowThreadConfig {
#Value("${threadConfig.corePoolSize}")
private Integer corePoolSize;
#Value("${threadConfig.maxPoolSize}")
private Integer maxPoolSize;
#Bean
#Qualifier("threadPoolTaskExecutor")
public TaskExecutor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setCorePoolSize(corePoolSize);
threadPoolTaskExecutor.setMaxPoolSize(maxPoolSize);
log.debug("threadPoolTaskExecutor maxPoolSize is : " + threadPoolTaskExecutor.getMaxPoolSize());
threadPoolTaskExecutor.setThreadNamePrefix("workflow_thread_");
threadPoolTaskExecutor.initialize();
return threadPoolTaskExecutor;
}
}
When I #Autowire the #Bean into another class using a #Qualifier, I see the default number of Threads in the max pool size instead of the number I provided (10) from my configuration even after commenting out most of my code and just using a #PostConstruct:
#Component
public class WorkflowTaskScheduler {
//#Autowired
//private WorkflowThreadManager workflowThreadManager;
#Autowired
#Qualifier("threadPoolTaskExecutor")
private TaskExecutor taskExecutor;
#PostConstruct
public void workflowTaskScheduler(){
ThreadPoolTaskExecutor threadPool = (ThreadPoolTaskExecutor) taskExecutor;
log.debug(" Max Thread Pool count is : " + threadPool.getMaxPoolSize());
}
}
Logs:
SpanId="">threadPoolTaskExecutor maxPoolSize is : 10</L_MSG>
SpanId=""> Max Thread Pool count is : 2147483647</L_MSG>
Another interesting point to make is when i remove the #Qualifier annotation from both the threadPoolTaskExecutor #Bean and the #Autowired TaskExecutor I get the following error:
Field taskExecutor in com.package.WorkflowTaskScheduler required a single bean, but 2 were found:
- threadPoolTaskExecutor: defined by method 'threadPoolTaskExecutor' in class path resource [com/package/WorkflowThreadConfig.class]
- taskScheduler: defined in null
Two options:
1. Use a different qualifier then the camelcase. myThreadPoolTaskExecutor
Use #primary on your ThreadPoolTaskExecutor. SO it will be the one getting bundled by default
Related
I am using Spring Async by implementing AsyncConfigurer and overriding the getAsyncExecutor to define my Executor.
Now I would like to expose an endpoint, to return the current queue size, number of threads ...etc, of the Executor that is used by Async.
But I could not find a way to find or autowire the current executor that is used by Async.
I was thinking I can define a bean, that will be both used by the getAsyncExecutor method, and my reporting service.
But I was wondering if there is an easier/more appropriate way I can interact with async to get the current Executor.
My current config:
#Configuration
#EnableAsync
public class AsyncConfiguration implements AsyncConfigurer {
#Override
public Executor getAsyncExecutor() {
final ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setThreadNamePrefix("async-thread-");
threadPoolTaskExecutor.setCorePoolSize(2);
threadPoolTaskExecutor.setMaxPoolSize(2);
threadPoolTaskExecutor.setQueueCapacity(100);
threadPoolTaskExecutor.initialize();
return threadPoolTaskExecutor;
}
}
You haven't registered a bean for the ThreadPoolTaskExector.
#Configuration
#EnableAsync
public class AsyncConfiguration implements AsyncConfigurer {
#Override
public Executor getAsyncExecutor() {
return taskExecutor();
}
#Bean
public ThreadPoolTaskExecutor taskExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setThreadNamePrefix("async-thread-");
threadPoolTaskExecutor.setCorePoolSize(2);
threadPoolTaskExecutor.setMaxPoolSize(2);
threadPoolTaskExecutor.setQueueCapacity(100);
return threadPoolTaskExecutor;
}
}
However Spring Boot 2.1 already pre-configures a TaskExecutor for you which you can configure through properties. You can then remove all config and only use #EnableAsync in your configuration.
spring.task.execution.pool.core-size=2
spring.task.execution.pool.max-size=2
spring.task.execution.pool.queue-capacity=100
spring.task.exection.thread-name-prefix=async-thread-
This configuration, together with a single #EnableAsync will achieve the same, without additional configuration.
With either configuration, you can now use #Autowired to get the instance in your service.
In my project I use multiple schema (multiple dataSource)
When I add Spring batch configuration I get error:No qualifying bean of type 'org.springframework.transaction.PlatformTransactionManager' available: expected single matching bean but found 5
but when I remove spring batch configuration the error is removed.
#Configuration
#EnableBatchProcessing
#Import(MyDataSourceClassConfig.class)
public class TestBatchJobConfiguration extends DefaultBatchConfigurer {
#Autowired
private JobBuilderFactory jobBuilderFactory;
#Autowired
private StepBuilderFactory stepBuilderFactory;
....
}
if you also facing same problem, you need to verify two point.
First you have to do not create a bean transaction named transactionManager (this default one used by spring batch)
Second you need to override getTransactionManager to specify which transactionManager you want to use and which dataSource you want to use
#Autowired
#Qualifier("myPersonalTransactionManager")
private PlatformTransactionManager transactionManager;
#Override
public PlatformTransactionManager getTransactionManager() {
return transactionManager;
}
#Override
#Autowired
public void setDataSource(#Qualifier("thirdDataSource") DataSource batchDataSource) {
super.setDataSource(batchDataSource);
}
I am working with a Spring boot application. I have a rest controller that returns Callable.
#GetMapping("/fb-roles")
#Timed
public Callable<List<FbRole>> getAllFbRoles() {
log.debug("REST request to get all FbRoles");
return (() -> { return fbRoleRepository.findAll(); });
}
A ThreadPoolTaskExecutor is configures as follow:
#Configuration
#EnableAsync
#EnableScheduling
public class AsyncConfiguration implements AsyncConfigurer {
private final Logger log = LoggerFactory.getLogger(AsyncConfiguration.class);
private final JHipsterProperties jHipsterProperties;
public AsyncConfiguration(JHipsterProperties jHipsterProperties) {
this.jHipsterProperties = jHipsterProperties;
}
#Override
#Bean(name = "taskExecutor")
public Executor getAsyncExecutor() {
log.debug("Creating Async Task Executor");
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(jHipsterProperties.getAsync().getCorePoolSize());
executor.setMaxPoolSize(jHipsterProperties.getAsync().getMaxPoolSize());
executor.setQueueCapacity(jHipsterProperties.getAsync().getQueueCapacity());
executor.setThreadNamePrefix("fb-quiz-Executor-");
return new ExceptionHandlingAsyncTaskExecutor(executor);
}
#Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new SimpleAsyncUncaughtExceptionHandler();
}
}
2018-09-19 00:43:58.434 WARN 10104 --- [ XNIO-2 task-28] o.s.w.c.request.async.WebAsyncManager :
!!!
An Executor is required to handle java.util.concurrent.Callable return values.
Please, configure a TaskExecutor in the MVC config under "async support".
The SimpleAsyncTaskExecutor currently in use is not suitable under load.
But while accessing the api server is producing the following warning
Spring configuration is a bit confusing in this respect, since it requires separate configuration for MVC Async support, i.e. using a Controller handler method that returns a Callable, and for any Spring bean method annotated with #Async. To configure both of it correctly you can apply something like the configuration below keeping in mind that the AsyncTaskExecutor config might need amending:
#Configuration
#EnableAsync
public class AsyncConfig implements AsyncConfigurer {
#Bean
protected WebMvcConfigurer webMvcConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
configurer.setTaskExecutor(getTaskExecutor());
}
};
}
#Bean
protected ConcurrentTaskExecutor getTaskExecutor() {
return new ConcurrentTaskExecutor(Executors.newFixedThreadPool(5));
}
}
On a side note, you might feel tempted to simply annotate your Controller handler method with #Async. This will only have the desired effect - freeing up web server threads - on fire and forget operations (this observation is based on Spring Boot 2.1.2, possibly they will address this in the future). If you want to leverage the power of Servlet 3.0 Asynchronous Processing, you really have to use Callables and configure them with a WebMvcConfigurer.
Given the warning and your Callable method.
Seems like Spring is not able to identify the Executor bean that you have just set up
in your configuration class.
You might need to annotate your method and specify the executor bean name, so
#GetMapping("/fb-roles")
#Timed
#Async("taskExecutor")
public Callable<List<FbRole>> getAllFbRoles() {
log.debug("REST request to get all FbRoles");
return (() -> { return fbRoleRepository.findAll(); });
}
Hope this helps
Guide can be found here: https://www.baeldung.com/spring-async
From your warning "Please, configure a TaskExecutor in the MVC config under "async support". The SimpleAsyncTaskExecutor currently in use is not suitable under load."
I wonder if you use the spring mvc or not?
With MVC, a few below links might help:
Configuring mvc async task executor in springboot application
Spring Boot - Any shortcuts for setting TaskExecutor?
I had combined mvc configuration (xml + annotations) and for me the following config helped to fix that warning:
mvc-servlet.xml:
<mvc:annotation-driven>
<mvc:async-support default-timeout="30000" task-executor="taskExecutor"
</mvc:annotation-driven>
AsyncConfig.java
#Configuration
#EnableAsync
public class AsyncConfig implements AsyncConfigurer {
#Bean
public AsyncTaskExecutor taskExecutor() {
return new ConcurrentTaskExecutor(Executors.newCachedThreadPool());
}
}
You need to configure an task executor like described by Fritz already. Sadly its solution uses now deprecated WebMvcConfigurerAdapter.
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
#Configuration
public class AsyncWebMvcConfiguration implements WebMvcConfigurer{
#Override
public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
configurer.setTaskExecutor(asyncExecutor());
}
private AsyncTaskExecutor asyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.initialize();
return executor;
}
}
Enhancement for solution from Fritz Duchardt and derived from: https://docs.sentry.io/platforms/java/guides/spring-boot/async/
Just recently started looking into Spring and specifically its latest features, like Java config etc.
I have this somewhat strange issue:
Java config Snippet:
#Configuration
#ImportResource({"classpath*:application-context.xml","classpath:ApplicationContext_Output.xml"})
#Import(SpringJavaConfig.class)
#ComponentScan(excludeFilters={#ComponentScan.Filter(org.springframework.stereotype.Controller.class)},basePackages = " com.xx.xx.x2.beans")
public class ApplicationContextConfig extends WebMvcConfigurationSupport {
private static final Log log = LogFactory.getLog(ApplicationContextConfig.class);
#Autowired
private Environment env;
#Autowired
private IExtendedDataSourceConfig dsconfig;
#PostConstruct
public void initApp() {
...
}
#Bean(name="transactionManagerOracle")
#Lazy
public DataSourceTransactionManager transactionManagerOracle() {
return new DataSourceTransactionManager(dsconfig.oracleDataSource());
}
IExtendedDataSourceConfig has two implementations which are based on spring active profile one or the other in instantiated. For this example let say this is the implementation :
#Configuration
#PropertySources(value = {
#PropertySource("classpath:MYUI.properties")})
#Profile("dev")
public class MYDataSourceConfig implements IExtendedDataSourceConfig {
private static final Log log = LogFactory.getLog(MYDataSourceConfig.class);
#Resource
#Autowired
private Environment env;
public MYDataSourceConfig() {
log.info("creating dev datasource");
}
#Bean
public DataSource oracleDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("oracle.jdbc.driver.OracleDriver");
dataSource.setUrl(env.getProperty("oracle.url"));
dataSource.setUsername(env.getProperty("oracle.user"));
dataSource.setPassword(env.getProperty("oracle.pass"));
return dataSource;
}
The problem is that when transactionManagerOracle bean is called, (even if I try to mark it as lazy) dsconfig variable value appears to be null.
I guess #beans are processed first and then all Autowires, is there a fix for this? How do I either tell spring to inject dsconfig variable before creating beans, or somehow create #beans after dsconfig is injected?
You can just specify DataSource as method parameter for the transaction manager bean. Spring will then automatically inject the datasource, which is configured in the active profile:
#Bean(name="transactionManagerOracle")
#Lazy
public DataSourceTransactionManager transactionManagerOracle(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
If you still want to do this through the configuration class, specify that as parameter:
public DataSourceTransactionManager transactionManagerOracle(IExtendedDataSourceConfig dsconfig) {}
In both ways you declare a direct dependency to another bean, and Spring will make sure, that the dependent bean exists and will be injected.
I have a very strange problem. I'm using Spring 3.2.4 and have a Spring Java Config class which is part of a larger mix of Java and XML configuration files.
The file uses 6 resources defined in other config files to construct an #Async bean. When I add "implements AsyncConfigurer" to the file, some of the #Resource fields appear as null, but when I leave the implementation off, they are populated. This is confusing, since the AsyncConfigurer is just supposed be used for configuring your asynchronous executor, it shouldn't do anything funky like cause your configuration to be loaded asynchronously.
When I set a debugger on the construction method, I can see that the beans are in fact null. It seems to be a race condition of some kind, because out of the 6 beans, the 4th one was once null, and then populated the next time.
My file looks like:
public class UserBackgroundProcessorConfiguration implements AsyncConfigurer {
#Resource(name="bean1")
MyBean bean1;
// in reality there are 6 #Resources defined...
#Resource(name="bean6")
MyBean bean6;
#Bean(name="backgroundProcessor")
public BackgroundProcessor getBackgroundProcessor() {
BackgroundProcessor backgroundProcess = new BackgroundProcessor();
backgroundProcess.setBean1(bean1);
// beans 1-3 are always populated
// bean 4 seems to sometimes be populated, sometimes null
// beans 5&6 are always null
backgroundProcess.setBean6(bean6);
return backgroundProcess;
}
#Override
#Bean(name="executor")
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(40);
executor.setQueueCapacity(25);
executor.setThreadNamePrefix("BackgroundProcessor-");
return executor;
}
}
Again, when I remove "implements AsyncConfigurer" and comment out getAsyncExecutor, the problem goes away.
According to the documentation
Interface to be implemented by #Configuration classes annotated with #EnableAsync that wish to customize the Executor instance used when processing async method invocations.
So I don't see how that cause the behavior I am seeing.
It appears that your backgroundProcessor bean is depending on your 6 resource beans.
Try annotating the method signature with:
#Bean(name="backgroundProcessor")
#DependsOn("bean1","bean2","bean3","bean4","bean5","bean6")
public BackgroundProcessor getBackgroundProcessor() {..}
I solved this problem by removing the #Resource annotations from the Java configuration file:
public class UserBackgroundProcessorConfiguration implements AsyncConfigurer {
#Bean(name="backgroundProcessor")
public BackgroundProcessor getBackgroundProcessor() {
BackgroundProcessor backgroundProcess = new BackgroundProcessor();
return backgroundProcess;
}
#Override
#Bean(name="executor")
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(40);
executor.setQueueCapacity(25);
executor.setThreadNamePrefix("BackgroundProcessor-");
return executor;
}
}
And then adding #Resource annotations to the BackgroundProcessor class:
public class BackgroundProcessor {
#Resource private MyBean bean1;
// 4 more
#Resource private MyBean bean6;
}
For some reason this works fine. I don't like this as much, because I would prefer my classes not have a dependency on the IOC annotations, but I'll go with this solution for now.