Is there a way to intercept SimpleAsyncTaskExecutor? Basically I am trying to intercept every time SimpleAsyncTaskExecutor is invoked.
On top of that what I am really trying to do is pass on a RequestScope bean. I found How to enable request scope in async task executor, but the problem is that I cannot reuse threads. I need a new thread created every time.
Any idea how I could forward Request Scoped beans to an async thread or how I could intercept #Async for a SimpleAsyncTaskExecutor?
Thanks,
Brian
I'm not sure this is the best way to accomplish what I am trying to accomplish but it seems to work.
Config:
#Configuration
#EnableAsync
public class Config extends AsyncConfigurerSupport implements WebMvcConfigurer {
#Override
#Bean
public Executor getAsyncExecutor() {
return new SimpleAsyncTaskExecutor(new MyThreadFactory());
}
}
MyThreadFactory:
public class MyThreadFactory implements ThreadFactory {
#Override
public Thread newThread(Runnable r) {
RequestContextHolder.setRequestAttributes(RequestContextHolder.getRequestAttributes(), true);
return new Thread(r);
}
}
So I also tried another solution using ThreadPoolTaskExecutor.
Basically I used this solution: http://www.chrisport.ch/java/2016/10/12/java-spring-context-aware.html and switched MDC context stuff to final RequestAttributes originalContextCopy = RequestContextHolder.getRequestAttributes(); and RequestContextHolder.resetRequestAttributes();
Related
I have a controller in Spring Boot/Spring Data Rest where my handler downloads a file like this
#RequestMapping(method = GET, value = "/orderAttachments/{id}/download")
#ResponseStatus(HttpStatus.OK)
public ResponseEntity<StreamingResponseBody> downloadAttachment(#PathVariable("id") Long attachmentID, HttpServletRequest request)
throws IOException {
InputStream inputStream = fileManager.getInputStream(orderAttachment);
StreamingResponseBody responseBody = outputStream -> {
int numberOfBytesToWrite;
byte[] data = new byte[1024];
while ((numberOfBytesToWrite = inputStream.read(data, 0, data.length)) != -1) {
outputStream.write(data, 0, numberOfBytesToWrite);
}
inputStream.close();
};
return ResponseEntity
.ok()
.contentLength(orderAttachment.getFileSize())
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + orderAttachment.getFileName()+ "\"")
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(responseBody);
}
I got this error in the console
!!!
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.
-------------------------------
Request URI: '/api/v1/orderAttachments/163/download'
!!!
But everything works, I can download the file from calling the API
For starters it is a warning and not an error. If it was an error your application wouldn't start or work. It is a warning telling you that the default used SimpleAsyncTaskExecutor shouldn't be used in production.
The SimpleAsyncTaskExecutor creates a new Thread when something needs to be processed asynchronously. Each thread takes up 1MB of memory by default (and some processing power). Now imagine someone issuing 100000 calls to this API. This would also mean 100000 threads (times the memory and each a little cpu power). It would cripple your application and maybe even kill it.
NOTE: If you are on Spring Boot 2.1.x or higher a default TaskExecutor will be configured and used for you. However if you have something in your configuration that disables the auto-configuration (like an #EnableWebMvc on an #Configuration class for instance). To configure that executor (with threads etc) check the Spring Boot Reference Guide.
You can also manually create a TaskExecutor and associate that with Spring MVC.
#Configuration
public class WebMvcConfig implements WebMvcConfigurer {
#Bean
public ThreadPoolTaskExecutor mvcTaskExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(10);
taskExecutor.setMaxPoolSize(10);
return taskExecutor;
}
public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
configurer.setTaskExecutor(mvcTaskExecutor());
}
}
Now this dedicated TaskExecutor will be used for the async handling in Spring MVC. However as mentioned this should already be pre-configured by Spring Boot if you haven't disabled auto-configuration (maybe even by accident!).
It is just a warning (that is why you still are able to download requested file) and Spring's suggestion to define your own TaskExecutor rather than using the SimpleAsyncTaskExecutor which, as the message states, is not suitable under load.
SimpleAsyncTaskExecutor fires up a new Thread for each task and does not reuse them. If you haven't configured limit on concurrent threads, it is by default unlimited.
#Configuration
class AsyncConfiguration implements AsyncConfigurer {
#Bean
protected WebMvcConfigurer webMvcConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
configurer.setTaskExecutor([your task executor]);
}
};
}
}
Use the above configuration to define your own TaskExecutor that suits your needs and get rid of the warning.
Spring boot in 2.1.0 provides auto configuration for task executors and uses for #EnableAsync and Spring MVC Async support.
There is no task executor bean / webMvcConfigurer configuration is needed from application. If you have one please remove it and you should be good.
If you like to control the values you can adjust using applicaion properties/yml file with spring.task.execution.*. Full listing can be found here
More details here and here
For me, the following did the trick:
#Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
#Override
public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(1);
executor.setMaxPoolSize(10);
executor.setThreadNamePrefix("mvc-task-executor-");
executor.initialize();
configurer.setTaskExecutor(executor);
}
}
By this means a ThreadPoolTaskExecutor is specified for the MVC context.
Make sure your application picks up the #Configuration class! If your main class is annotated with #SpringBootApplication, this should happen automatically.
Also, make sure to configure your ThreadPoolTaskExecutor appropriately to your needs.
I want to implement Server Sent Events in Spring Boot. The data is there in SQL database, It is resulting in blocking connection. Web Flux is an option but it is supported only for some NoSQL database.
Yes, you right WebFlux framework doesn't SQL databases in the non blocking mode because reactive drivers does not exist.
But WebFlux provides some instruments to avoid blocking our main threads while we are making blocking long queries to a database.
1) Create configuration with Scheduler where count of threads equals to pool size:
#Configuration
public class SchedulerConfiguration {
#Value("${spring.datasource.maximum-pool-size}
private final Integer connectionPoolSize;
#Bean
#Qualifier("jdbcScheduler")
public Scheduler jdbcScheduler() {
return Schedulers.fromExecutor(Executors.newFixedThreadPool(connectionPoolSize));
}
}
2) Inject your "jdbcScheduler" to the service class:
#Service
public class DataService {
#Autowired
private final DataRepository jdbcRepository;
#Autowired #Qualifier("jdbcScheduler")
private final Scheduler scheduler;
public Mono<String> findById(long id) {
return async(() -> repository.findById(id));
}
private <T> Mono<T> async(Callable<T> callable) {
return Mono.fromCallable(callable).publishOn(scheduler);
}
}
Wrap your blocking method by Mono.fromCallable and delegate from main thread to your "scheduler" via Mono.publishOn
More about schedulers you can read here: Threading and Schedulers
Yes you can achieve asynchronous processing in spring without flux by using their inbuilt #Async processing, here how you can achieve it.
Step1: Enable Aysnc and define a bean for Executor. You can define separate configuration or directly under Main application class.
#SpringBootApplication
#EnableAsync
public class Application {
public static void main(String[] args) {
// close the application context to shut down the custom ExecutorService
SpringApplication.run(Application.class, args).close();
}
#Bean
public Executor asyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(2);
executor.setQueueCapacity(500);
executor.setThreadNamePrefix("GithubLookup-");
executor.initialize();
return executor;
}
STEP2:
Following is the simple way to configure a method with void return type to run asynchronously, You can also invoke method by retrieve the result of the asynchronous process using the Future object.
#Async
public void asyncMethodWithVoidReturnType() {
System.out.println("Execute method asynchronously. "
+ Thread.currentThread().getName());
}
For more information, You can visit Spring official guide Spring Async
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/
These days im working on a Web project and i just want to clarify couple of things regarding Spring bean scopes and best practices for Spring based developments. Here i am using a scenario using a sample code
I have a Web Controller as below
#Controller
Public class JobController{
private JobService jobService;
#Autowired
public void setJobService(JobService jobService ) {
this.jobService = jobService ;
}
public void run(){
Job job = new Job();
-- Setting the properties for the Object
jobService.run(job);
}
}
Then I have the Service as below
#Service
Public class JobService {
public void run(Job job){
-- perform the business logic
}
}
In Here i want to make the JobService class stateless so i can define JobService as singleton hence reduce the unnecessary object creation. As per my understanding in-order make a class stateless we do not want to keep instance properties.In This scenario i pass different Job objects to the service. Does this make this JobService statefull because JObservice process different different job objects? Can you please help me to understand
Thanks,
Keth
Passing different objects does not make your service stateful.
Consider this for example.
#Service
Public class JobService {
private Job currentJob;
public void setJob(Job job) {
currentJob = job;
}
public void run(){
-- perform the business logic on currentJob
}
}
This would make the bean 'stateful' and cause unexplained behavior.
The execution of the method in your singleton by multiple controller/threads will not collide and can be assumed to be safe.
I'm connecting to PubNub in a Spring Boot application. From the documentation, it's ok to re-use PubNub objects but it's better to have one per thread. What's the appropriate method to store and retrieve one object per thread in Spring Boot?
This is how you'd store and retrieve an object per thread in Spring using ThreadLocal, this example is based on Spring's own ThreadLocalSecurityContextHolderStrategy which is used to store SecurityContext per thread.
Also, take a look at InheritableThreadLocal especially if your code spins up new thread, e.g. Spring's #Async annotation, it has mechanisms to propagate existing or create new thread local values when creating child threads.
import org.springframework.util.Assert;
final class ThreadLocalPubNubHolder {
private static final ThreadLocal<PubNub> contextHolder = new ThreadLocal<PubNub>();
public void clearContext() {
contextHolder.remove();
}
public PubNub getContext() {
PubNub ctx = contextHolder.get();
if (ctx == null) {
ctx = createEmptyContext();
contextHolder.set(ctx);
}
return ctx;
}
public void setContext(PubNub context) {
Assert.notNull(context, "Only non-null PubNub instances are permitted");
contextHolder.set(context);
}
public PubNub createEmptyContext() {
// TODO - insert code for creating a new PubNub object here
return new PubNubImpl();
}
}
You can use Java ThreadLocal support as mentioned above by #SergeyB. Another way to do it is to use Thread Scope for your beans:
#Configuration
public class AppConfig {
//Register thread scope for your application
#Bean
public BeanFactoryPostProcessor beanFactoryPostProcessor() {
return beanFactory -> beanFactory.registerScope("thread", new SimpleThreadScope());
}
}
Then you can create a bean with a thread scope (proxy mode will be explained below):
#Scope(value = "thread", proxyMode = ScopedProxyMode.TARGET_CLASS)
#Component
public class PubSubContext {
private PubSub pubSub;
public PubSub getPubSub() {
return pubSub;
}
public void setPubSub(PubSub pubSub) {
this.pubSub = pubSub;
}
#PostConstruct
private void init() {
// TODO: your code for initializing PubSub object
log.info("RequiredMessageHeaders started in thread " + Thread.currentThread().getId());
}
#PreDestroy
private void destroy() {
// TODO: your code for cleaning resources if needed
log.info("RequiredMessageHeaders destroyed in thread " + Thread.currentThread().getId());
}
}
The last step is to inject PubSubContext where you need it:
#Controller
public class YourController {
// Spring will inject here different objects specific for each thread.
// Note that because we marked PubSubContext with proxyMode = ScopedProxyMode.TARGET_CLASS we do not need to use applicationContext.get(PubSubContext.class) to obtain a new bean for each thread - it will be handled by Spring automatically.
#Autowired
private PubSubContext pubSubContext;
#GetMapping
public String yourMethod(){
...
PubSub pubSub = pubSubContext.getPubSub();
...
}
}
With this approach, you could go even further and mark your PubSubContext as #Lazy, so it won't be created until it's requested inside yourMethod :
#Controller
public class YourController {
#Lazy
#Autowired
private PubSubContext pubSubContext;
...
}
As you see PubSubContext does basically what ThreadLocal does but leveraged by Spring capabilities.
Hope it helps!
First of all,
As it is safe to use single PubNub object in multiple threads,
You need multiple PubNub objects ONLY if you need performance increase
If that is your case - my suggestion will be to organize pool of PubNub objects (the use case is quite close to DB connection use case).