#Scheduled and #Async are sharing same threadpool in spring-boot - spring-boot

I have configured two different thread pools, one for #Scheduled and other for #Async. However, I notice that the thread-pool for #Async is not being used.
Here is the Scheduler configuration
#Configuration
#EnableScheduling
public class SchedulerConfig implements SchedulingConfigurer {
private final int POOL_SIZE = 10;
#Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.setPoolSize(POOL_SIZE);
threadPoolTaskScheduler.setThreadNamePrefix("my-sched-pool-");
threadPoolTaskScheduler.initialize();
scheduledTaskRegistrar.setTaskScheduler(threadPoolTaskScheduler);
}
}
Here is the Configuration for Async
#Configuration
#EnableAsync
public class AppConfig {
#Bean(name = "asyncTaskExecutor")
public TaskExecutor asyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(15);
executor.setMaxPoolSize(15);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("my-async-pool-");
executor.initialize();
return executor;
}
}
Here is how I invoke them
#Scheduled(fixedRateString = "2000" )
public void schedule() {
log.debug("here is the message from schedule");
asyncMethod();
}
#Async("asyncTaskExecutor")
public void asyncMethod(){
log.info("here is the message from async");
}
Here are the logs
{"thread":"my-sched-pool-1","level":"DEBUG","description":"here is the message from schedule"}
{"thread":"my-sched-pool-1","level":"INFO","description":"here is the message from async"}
As you can notice, both logs are having same pool of that scheduler. but I expect to see the second one to come from async

If you call #Async methods from the same class they are declared you are effectively bypassing Spring's proxy mechanism and that is why your example is not working. Try calling the method from a separate class annotated with #Service or any of the other #Component types.
#Service
SomeScheduledClass {
private final SomeAsyncClass someAsyncClass;
public SomeScheduledClass(SomeAsyncClass someAsyncClass) {
this.someAsyncClass = someAsyncClass;
}
#Scheduled(fixedRateString = "2000" )
public void schedule() {
log.debug("here is the message from schedule");
someAsyncClass.asyncMethod();
}
}
#Service
SomeAsyncClass {
#Async("asyncTaskExecutor")
public void asyncMethod(){
log.info("here is the message from async");
}
}

Related

How to use Async in Spring Boot?

Below is my code.
With my below code, different thread ids are not getting created.
The output has same thread id.
#Controller
#RequestMapping(value = "/Main")
public class MyController
{
#Autowired
private MyService myService;
#PostMapping("/Sub")
#ResponseBody
public String readInput(#RequestBody String name)
{
for (int i = 0;i<5;i++)
{
myService.asyncMethod();
}
return "Success";
}
}
With my below code, different thread ids are not getting created.
#Repository
#Configuration
#EnableAsync
public class MyService {
#Bean(name = "threadPoolTaskExecutor")
public Executor threadPoolTaskExecutor() {
return new ThreadPoolTaskExecutor();
}
#Async("threadPoolTaskExecutor")
public void asyncMethod() {
System.out.println("Thread " + Thread.currentThread().getId()+ " is running");
}
}
First of all, it is impossible to judge whether the thread pool is used by the thread id. You can set the thread prefix and judge by the log
Configure thread pool
#Slf4j
#Configuration
public class ThreadExecutorConfig {
#Autowired
private ThreadPoolProperties threadPoolProperties;
#Bean(name = "taskExecutor")
public ExecutorService executorService() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(threadPoolProperties.getCorePoolSize());
executor.setMaxPoolSize(threadPoolProperties.getMaxPoolSize());
executor.setQueueCapacity(threadPoolProperties.getQueueSize());
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setThreadNamePrefix("myThread-");
executor.initialize();
log.info("threadPoolConfig;corePoolSize:[{}];maxPoolSize:[{}];queueSize:[{}]",
threadPoolProperties.getCorePoolSize(),
threadPoolProperties.getMaxPoolSize(),
threadPoolProperties.getQueueSize());
return executor.getThreadPoolExecutor();
}
}
Use #Async annotations on methods
#Async(value = "taskExecutor")
#Override
public void asyncSave(OperationLogModel entity) {
if (log.isDebugEnabled()) {
log.debug("thread:{};entity:{}", Thread.currentThread().getName(), entity.toString());
}
entity.setCreateTime(LocalDateTime.now());
super.save(entity);
}
View log
Good question! The answer is in ThreadPoolTaskExecutor. Its default corePoolSize is one.
#Bean(name = "threadPoolTaskExecutor")
public Executor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setCorePoolSize(3);//or any (positive) integer that suits you.
return threadPoolTaskExecutor;
}
..will behave more as we expect:
Thread 127 is running
Thread 128 is running
Thread 128 is running
Thread 129 is running
Thread 127 is running

How to use threadPoolExecutor for async spring

I have a requirement to use same thread for multiple request in async spring.
Here is the code which i am using :
Here is the Executor configuration file
#Configuration
#EnableAsync
public class ExecutorConfig {
#Bean(name = "threadPoolExecutor")
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(7);
executor.setMaxPoolSize(42);
executor.setQueueCapacity(11);
executor.setThreadNamePrefix("threadPoolExecutor-");
executor.initialize();
return executor;
}
}
Here is the service file
public interface QueueService {
public void createQueue();
public void sendData();
}
Here is the Service Implementation
#Service
public class QueueServiceImpl implements QueueService {
#Override
#Async("threadPoolExecutor")
public void createQueue() {
System.out.println(Thread.currentThread().getName());
}
#Override
#Async("threadPoolExecutor")
public void sendData() {
// Need to use the same thread which created the queue
// Thread.currentThread() should be same for both methods
System.out.println(Thread.currentThread().getName());
}
}
Here is the controller class
#RestController
public class Controller {
#Autowired
QueueService queueService;
#RequestMapping(value="/create", method = RequestMethod.GET)
public void createQueue()
{
queueService.createQueue();
}
#RequestMapping(value="/send", method = RequestMethod.GET)
public void sendDataToQueue()
{
queueService.sendData();
}
}
Here is the Spring boot main application
#EnableAsync
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Please let me know how to use #Async in 2 separate request to do the job done by same thread.

Microservice return response first and then process the request

I am working on a solution for which i am trying to create a microservice which returns response immediately and then processes the request.
I am trying to use Java 8 and Spring for this.
This can be achieved in several ways.
In order to return a result from the current thread (a controller in this case) while still doing some long-running operation, you will need another thread.
Use Executor directly.
A controller:
#Controller
public class AsyncController {
private AsyncService asyncService;
#Autowired
public void setAsyncService(AsyncService asyncService) {
this.asyncService = asyncService;
}
private ResponseEntity asyncMethod(#RequestBody Object request) {
asyncService.process(new MyLongRunningRunnable());
// returns immediately
return ResponseEntity.ok("ok");
}
}
And a service:
#Service
public class AsyncService {
private ExecutorService executorService;
#PostConstruct
private void create() {
executorService = Executors.newSingleThreadExecutor();
}
public void process(Runnable operation) {
// no result operation
executorService.submit(operation);
}
#PreDestroy
private void destroy() {
executorService.shutdown();
}
}
More details can be found here https://docs.oracle.com/javase/tutorial/essential/concurrency/runthread.html
Another way is to use Spring built-in async capabilities
You can simply annotate a method with #Async, having void or Future return type.
If you still want to supply your own executor, you may implement AsyncConfigurer interface in your spring configuration bean.
This approach also requires #EnableAsync annotation.
#Configuration
#EnableAsync
public class AsyncConfiguration implements AsyncConfigurer {
#Override
public Executor getAsyncExecutor() {
return Executors.newSingleThreadExecutor();
}
}
More on this topic https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/scheduling/annotation/Async.html
Here is an example with ExecutorService:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.annotation.PreDestroy;
import javax.servlet.http.HttpServletRequest;
#RestController
public class MyController {
// Instantiate an executor service
private ExecutorService executor = Executors.newSingleThreadExecutor();
#PreDestroy
public void shutdonw() {
// needed to avoid resource leak
executor.shutdown();
}
#GetMapping
public Object gerUrl(HttpServletRequest request) {
// execute the async action, you can use a Runnable or Callable instances
executor.submit(() -> doStuff());
return "ok";
}
private void doStuff(){}
}
You can use the Executors factory class to build a ExecutorService. Those methods might help you:
java.util.concurrent.Executors
Executors.newSingleThreadExecutor() // jobs are queued and executed by a single thread
Executors.newCachedThreadPool() // new threads are instantiated as needed and cached
Executors.newFixedThreadPool(int nThreads) // user defined number of threads
.
#EnableAsync
#SpringBootApplication
public class MyApplication extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(MyApplication.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(MyApplication.class, args);
}
}
import javax.annotation.PreDestroy;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurerSupport;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
#Configuration
public class AsyncConfiguration extends AsyncConfigurerSupport {
private ThreadPoolTaskExecutor executor;
#Override
public Executor getAsyncExecutor() {
executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(20);
executor.setMaxPoolSize(50);
executor.setQueueCapacity(1000);
executor.initialize();
return executor;
}
#PreDestroy
public void shutdownExecutors() {
executor.shutdown();
}
}
#Service
public class MyService {
#Async
public void doStuff(){
// Async method
}
}
Both techniques are quite good, but the first one with ExecutorService give you more control.

#EventListener with #Async in Spring

Trying to enable async event handling combining the #Async and #EventListener annotations, but I still see that the listener is running in the publishing thread.
The example you can find here:
#SpringBootApplication
#EnableAsync
class AsyncEventListenerExample {
static final Logger logger = LoggerFactory.getLogger(AsyncEventListenerExample.class);
#Bean
TaskExecutor taskExecutor() {
return new SimpleAsyncTaskExecutor();
}
static class MedicalRecordUpdatedEvent {
private String id;
public MedicalRecordUpdatedEvent(String id) {
this.id = id;
}
#Override
public String toString() {
return "MedicalRecordUpdatedEvent{" +
"id='" + id + '\'' +
'}';
}
}
#Component
static class Receiver {
#EventListener
void handleSync(MedicalRecordUpdatedEvent event) {
logger.info("thread '{}' handling '{}' event", Thread.currentThread(), event);
}
#Async
#EventListener
void handleAsync(MedicalRecordUpdatedEvent event) {
logger.info("thread '{}' handling '{}' event", Thread.currentThread(), event);
}
}
#Component
static class Producer {
private final ApplicationEventPublisher publisher;
public Producer(ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
public void create(String id) {
publisher.publishEvent(new MedicalRecordUpdatedEvent(id));
}
#Async
public void asynMethod() {
logger.info("running async method with thread '{}'", Thread.currentThread());
}
}
}
and my test case:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = AsyncEventListenerExample.class)
public class AsyncEventListenerExampleTests {
#Autowired
Producer producer;
#Test
public void createEvent() throws InterruptedException {
producer.create("foo");
//producer.asynMethod();
// A chance to see the logging messages before the JVM exists.
Thread.sleep(2000);
}
}
However in logs I see that both #EventListeners run in the main thread.
2016-05-12 08:52:43.184 INFO 18671 --- [ main] c.z.e.async2.AsyncEventListenerExample : thread 'Thread[main,5,main]' handling 'MedicalRecordUpdatedEvent{id='foo'}' event
2016-05-12 08:52:43.186 INFO 18671 --- [ main] c.z.e.async2.AsyncEventListenerExample : thread 'Thread[main,5,main]' handling 'MedicalRecordUpdatedEvent{id='foo'}' event
The async infrastructure is initialised with #EnableAsync with an asynchronous TaskExecutor.
Not sure what I am doing wrong. Could you help?
Thanks.
Using Spring Boot 1.4.2.M2, so Spring 4.3.0.RC1
There was a regression in Spring Framework 4.3.0.RC1 that leads to that very issue you're having. If you use the SNAPSHOT, your project runs fine.
onTicketUpdatedEvent runs in also main Thread with Spring Framework 4.2.4 Release as follows.
But it runs in SimpleAsyncTaskExecutor if AsyncConfigurer is not implemented.
#EnableAsync(proxyTargetClass = true)
#Component
#Slf4j
public class ExampleEventListener implements AsyncConfigurer {
#Async
#EventListener
public void onTicketUpdatedEvent(TicketEvent ticketEvent) {
log.debug("received ticket updated event");
}
#Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setMaxPoolSize(100);
executor.initialize();
return executor;
}
#Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return null;
}
}
I resolved my issue by configuring task-executor bean as follows.
#Bean(name = "threadPoolTaskExecutor")
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setMaxPoolSize(100);
executor.initialize();
return executor;
}
#Async("threadPoolTaskExecutor")
#EventListener
public void onTicketUpdatedEvent(TicketEvent ticketEvent) {
log.debug("received ticket updated event");
}

Spring : #Scheduled task triggered through the #Controller and Websocket

I have an #Scheduled task which send data to a client every sec throught a websocket.
My need is to start running my scheduled task only when the client ask for it.
Instead of, my task starts when my server starts. it's not the behavior i want.
currently, I have a bean of my scheduled task which is declared in my SchedulingConfigurer :
#Configuration
#EnableScheduling
public class SchedulingConfigurer implements org.springframework.scheduling.annotation.SchedulingConfigurer {
#Bean
public ThreadPoolTaskScheduler taskScheduler() {
return new ThreadPoolTaskScheduler();
}
#Bean
public ScheduledTask scheduledTask() {
return new ScheduledTask();
}
#Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setTaskScheduler(taskScheduler());
}
}
Here is my spring controller code :
#MessageMapping("/hello")
public void greeting() throws Exception {
//How do I start my scheduled task here ?
}
Maybe isn't possible to do that with #Scheduled annotation and i have to use the TaskScheduler interface ?
remove #Scheduled declaration from ScheduledTask class
implements Runnable interface instead of
#Component
//#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class ScheduledTask implements Runnable {
private static final Logger log = LoggerFactory.getLogger(ScheduledTask.class);
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
public void doWork() {
printMessage();
// TODO real work
}
private void printMessage() {
log.info("time to work: {}", dateFormat.format(new Date()));
}
#Override
public void run() {
doWork();
}
}
schedule Your task in controller area like this
#Controller
public class ScheduledTaskController {
#Autowired
private TaskScheduler taskScheduler;
#Autowired
private ScheduledTask scheduledTask;
#RequestMapping(value = "/task/run", method = RequestMethod.GET)
public String runTask() {
// start to run task every 5 sec.
taskScheduler.schedule(scheduledTask, new CronTrigger("0/5 * * * * ?"));
// ok, redirect
return "redirect:/task";
}
}
#Schedule is the declarative way, so not the point you're trying to achieve here.
You could create a Bean using one of the TaskScheduler implementations, such as ThreadPoolTaskScheduler and inject that bean in your application.
It has all the necessary methods to dynamically schedule tasks.

Resources