RestEasy Async Controller Proper Usage - java

I am trying to create a Async REST Service using RestEasy, but I can't find any documentation that shows a clean way of doing so. The only example I found is here:
https://github.com/resteasy/Resteasy/blob/master/jaxrs/async-http-servlet-3.0/async-http-servlet-3.0-test/src/main/java/org/jboss/resteasy/test/async/JaxrsResource.java
#GET
#Produces("text/plain")
public void get(#Suspended final AsyncResponse response) throws Exception
{
response.setTimeout(2000, TimeUnit.MILLISECONDS);
Thread t = new Thread()
{
#Override
public void run()
{
try
{
System.out.println("STARTED!!!!");
Thread.sleep(100);
Response jaxrs = Response.ok("hello").type(MediaType.TEXT_PLAIN).build();
response.resume(jaxrs);
}
catch (Exception e)
{
e.printStackTrace();
}
}
};
t.start();
}
Creating a new thread in the method doesn't seem like the best way to do things in a production environment. I feel like I should be getting a thread from a thread pool or something.
Any suggestions or links to better examples would be very helpful.

You are right about using Thread pool. Let Spring take care of it for you.
Assuming you are using Spring as a choice for your application you could do something like.
You can define an Configuration class for Async Executors.
#EnableAsync
#Configuration
public class AsyncConfiguration implements AsyncConfigurer {
#Inject
private Environment env;
#Bean
#Override
#Singleton
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(env.getProperty("controller.threadPoolTaskExecutor.corePoolSize", Integer.class, 10));
taskExecutor.setMaxPoolSize(env.getProperty("controller.threadPoolTaskExecutor.maxPoolSize", Integer.class, 100));
taskExecutor.setKeepAliveSeconds(env.getProperty("controller.threadPoolTaskExecutor.keepAliveSeconds", Integer.class, 60*5));
taskExecutor.setQueueCapacity(env.getProperty("controller.threadPoolTaskExecutor.queueCapacity", Integer.class, 10000));
taskExecutor.setThreadNamePrefix("controller-async-task-executor");
return taskExecutor;
}
#Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new AsyncExceptionHandler();
}
}
Here is how you can define the Exception Handler:
public class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
private static final Logger logger = LoggerFactory.getLogger(AsyncExceptionHandler.class);
#Override
public void handleUncaughtException(Throwable ex, Method method, Object... params) {
logger.error("Error processing async request in method: " + method.getName(), ex);
}
}
Here is how your controller could look like:
#Inject
private AsyncTaskExecutor asyncTaskExecutor;
#GET
#Produces("text/plain")
public void get(#Suspended final AsyncResponse response) throws Exception
{
response.setTimeout(2000, TimeUnit.MILLISECONDS);
asyncTaskExecutor.submit(() -> {
System.out.println("STARTED!!!!");
Thread.sleep(100);
Response jaxrs = Response.ok("hello").type(MediaType.TEXT_PLAIN).build();
response.resume(jaxrs);
});
}

Related

Run a process asynchronously after completion of initial process in Spring boot

I have a requirement. I have 2 processes
Contact creation and
Associating contact to the Department
Currently I have a spring boot API which has a REST POST call to perform both in one thread. Since process 2 is taking more time I wanted to run that in the
background immediately after finishing the step 1.
#PostMapping(value = "/processDeptContact", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<PayloadResponse> processDeptContact(#RequestBody String payload) {
ResponseEntity response = new ResponseEntity(new ErrorResponse("Exception"),
new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR);
try {
response = myService.processPayload(payload);
} catch (Exception e) {
logger.error("Exception in the controller");
}
return response;
}
I want to return the response to the user as soon as step 1 is done and performing step 2 at the background. How do I achieve that
Thanks in advance
In your main class, or a #Configuration class, use #EnableAsync to bootstrap a thread pool:
#EnableAsync
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
You can optionally set Thread Pool properties under spring.task.execution.pool property. Example:
spring:
task:
execution:
pool:
core-size: 8
max-size 16
Here's a stack post detailing what each property means: Core pool size vs maximum pool size in ThreadPoolExecutor
Inside your controller:
#RestController
public class TestController {
private final ContactService contactService;
private final DepartmentService departmentService;
// Constructor Injection
public TestController(ContactService contactService, DepartmentService departmentService) {
this.contactService = contactService;
this.departmentService = departmentService;
}
#PostMapping(value = "/processDeptContact", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<PayloadResponse> processDeptContact(#RequestBody String payload) {
List<Contact> contacts = contactService.processPayload(payload);
departmentService.associateContacts(contacts); // This is an asynchronous call
return ResponseEntity.ok(new PayloadResponse(contacts));
}
}
I've removed the try/catch from the controller method since error handling is a cross cutting concern and is handled by AOP. More on that here: Baeldung
And finally in your DepartmentService, you use the #Async annotation to turn it into an asynchronous method:
#Service
public class DepartmentService {
#Async
public void associateContacts(List<Contact> contacts) {
// method
}
}
I see other answers are basically saying the same thing and are correct, but not complete so I felt the need to put everything together for you.
Spring framework provides support for asynchronous processing out of the box. Spring can create & manage threads for us by providing support for various TaskExecutor abstraction.
We can create a method in a new class that will do the second process (associate contact to the Department) and annotate that method with #Aysnc. The annotation ensures the spring executes this method as a Runnable/Future depending on return type.
Sample Implementation (We have to add #EnableAsync in any of our configuration class)
#Component
class ContactManager {
#Async
public void associateContactToDepartment(){
//method implementation goes here
}
}
class MyService {
#Autowired
private ContactManager contactManager;
public PayloadResponse processPayload(String payload){
payloadResponse payloadResponse = createContact();//first process
contactManager.associateContactToDepartment() // this call will be executed asynchronously.
return payloadResponse;
}
}
Refer this for quick intro to async methods.
Follow the below steps:
Add #EnableAsync annotation and Add TaskExecutor Bean to main spring boot application class
#SpringBootApplication
#EnableAsync
public class AsynchronousSpringBootApplication {
private static final Logger logger = LoggerFactory.getLogger(SpringBootApplication.class);
#Bean(name="processExecutor")
public TaskExecutor workExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setThreadNamePrefix("Async-");
threadPoolTaskExecutor.setCorePoolSize(3);
threadPoolTaskExecutor.setMaxPoolSize(3);
threadPoolTaskExecutor.setQueueCapacity(600);
threadPoolTaskExecutor.afterPropertiesSet();
logger.info("ThreadPoolTaskExecutor set");
return threadPoolTaskExecutor;
}
public static void main(String[] args) throws Exception {
SpringApplication.run(SpringBootApplication.class,args);
}
Add the contact to department method as below:
#Service
public class DepartmentProcess {
private static final Logger logger = LoggerFactory.getLogger(ProcessServiceImpl.class);
#Async("processExecutor")
#Override
public void processDepartment() {
logger.info("Received request to process in DepartmentProcess.processDepartment()");
try {
Thread.sleep(15 * 1000);
logger.info("Processing complete");
}
catch (InterruptedException ie) {
logger.error("Error in ProcessServiceImpl.process(): {}", ie.getMessage());
}
}
}
Call the method from the controller as below:
#PostMapping(value = "/processDeptContact", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<PayloadResponse> processDeptContact(#RequestBody String payload) {
ResponseEntity response = new ResponseEntity(new ErrorResponse("Exception"),
new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR);
try {
response = myService.processPayload(payload);
myService.processDepartment();//async method
} catch (Exception e) {
logger.error("Exception in the controller");
}
return response;
}
Points 1 and 2 are not here but it doesn't matter, let's call them foo1() and foo2().
In myService.processPayload() you want to do:
ResponseEntity result = foo1();
Runnable runnable = () -> {
foo2()
};
Thread thread = new Thread(runnable);
thread.start(); // the logic in foo2 will happen in a background thread so it will not block on this line, consider using a thread pool instead
return result;
BTW, this sounds like premature optimization and you should think about race conditions with parallel threads but this is not what the question was asking.
One more thing, move this to the catch because it's a waste of instantiations if the try will succeed, which should happen most of the time.
ResponseEntity response = new ResponseEntity(new ErrorResponse("Exception"),
new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR);

Spring #Async propagate context information

I've a Spring Boot 2.2 application. I created a service like this:
#Async
#PreAuthorize("hasAnyRole('ROLE_PBX')")
#PlanAuthorization(allowedPlans = {PlanType.BUSINESS, PlanType.ENTERPRISE})
public Future<AuditCdr> saveCDR(Cdr3CXDto cdrRecord) {
log.debug("Current tenant {}", TenantContext.getCurrentTenantId());
return new AsyncResult<AuditCdr>(auditCdrRepository.save(cdr3CXMapper.cdr3CXDtoToAuditCdr(cdrRecord)));
}
this is my #Async configuration:
#Configuration
#EnableAsync
public class AsyncConfiguration implements AsyncConfigurer {
#Override
public Executor getAsyncExecutor() {
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(500);
executor.setThreadNamePrefix("threadAsync");
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.initialize();
return executor;
}
}
Using SecurityContextHolder.MODE_INHERITABLETHREADLOCAL I see the Security context is passed to the #Async method.
In my multi-tenant application I use a ThreadLocal to set the tenant's id:
public class TenantContext {
public final static String TENANT_DEFAULT = "empty";
private static final ThreadLocal<String> code = new ThreadLocal<>();
public static void setCurrentTenantId(String code) {
if (code != null)
TenantContext.code.set(code);
}
public static String getCurrentTenantId() {
String tenantId = code.get();
if (StringUtils.isNotBlank(tenantId)) {
return tenantId;
}
return TENANT_DEFAULT;
}
public static void clear() {
code.remove();
}
}
Because ThreadLocal is related to the thread, it's not available in the #Async method. Furthemore my custom #PlanAuthorization aop needs it to perform verifications of the tenant's plan.
Is there a clean way to set TenantContext in any #Async method in my application?
I ended up to use a TaskDecorator:
#Log4j2
public class MdcTaskDecorator implements TaskDecorator {
#Override
public Runnable decorate(Runnable runnable) {
// Right now: Web thread context !
// (Grab the current thread MDC data)
String tenantId = TenantContext.getCurrentTenantId();
Long storeId = StoreContext.getCurrentStoreId();
SecurityContext securityContext = SecurityContextHolder.getContext();
Map<String, String> contextMap = MDC.getCopyOfContextMap();
log.info("Saving tenant information for async thread...");
return () -> {
try {
// Right now: #Async thread context !
// (Restore the Web thread context's MDC data)
TenantContext.setCurrentTenantId(tenantId);
StoreContext.setCurrentStoreId(storeId);
SecurityContextHolder.setContext(securityContext);
MDC.setContextMap(contextMap);
log.info("Restoring tenant information for async thread...");
runnable.run();
} catch (Throwable e) {
log.error("Error in async task", e);
} finally {
MDC.clear();
}
};
}
}
and I used it in this way:
#Configuration
#EnableAsync
public class AsyncConfiguration implements AsyncConfigurer {
#Override
public Executor getAsyncExecutor() {
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(1);
executor.setMaxPoolSize(100);
executor.setQueueCapacity(500);
executor.setThreadNamePrefix("threadAsync");
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setTaskDecorator(new MdcTaskDecorator());
executor.initialize();
return executor;
}
}
It works and it seems also a neat solution.
The solution for such case is to :
configure custom thread pool so that you override it's execute method to sets up your thread local (or
executes any task from your main context), decorate the task and submit decorated task for execution instead of original one
instruct #Async annotation to use concrete thread pool
#Bean("tenantExecutor")
public Executor threadLocalAwareThreadPool() {
final CustomizableThreadFactory threadNameAwareFactory =
new CustomizableThreadFactory("threadAsync");
final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2, 10,
0L, TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<>(500), threadNameAwareFactory) {
// override original method of thread pool
#Override
public void execute(Runnable originalTask) {
final String tenantId = tenantThreadLocal.get(); // read data from current before passing the task to async thread
// decorate the actual task by creating new task (Runnable) where you first set up the thread local and then execute your actual task
super.execute(() -> {
tenantThreadLocal.set(tenantId); // set data in actual async thread
originalTask.run();
});
}
};
return threadPoolExecutor;
}
Now we tell spring use our custom executor
#Async("tenantExecutor")
public Future<AuditCdr> saveCDR(Cdr3CXDto cdrRecord) {
// your code....
}
Instead of ThreadLocal you must use InheritableThreadLocal. Then you will see the values from the parent thread.
API Doc: https://docs.oracle.com/javase/8/docs/api/java/lang/InheritableThreadLocal.html
Here is an article about this in combination with Spring: https://medium.com/#hariohmprasath/async-process-using-spring-and-injecting-user-context-6f1af16e9759

Spring Boot REST - requests are not executing with ThreadPoolTaskExecutor configuration

I am trying to develop a spring boot app. I have written all core implementations in core java without spring framework. I am using that jar in this spring boot app. I would like to manage the concurrency of my rest controller. So, configured ThreadPoolTaskExecutor accordingly in the main class. Ideally, I want only 2 concurrent requests to get into the execute() method, which I annotated Async. I was testing for 2 concurrent requests at a time but I see in the log that my requests are entering execute() all at once. All the tasks are memory intensive. So those are failing with heap memory issues. I am trying to figure out the ideal concurrency number. I would like to know if my configuration is correct or am I missing something? Thank you.
Here's my main class:
#SpringBootApplication
#EnableAsync
public class RestapiApplication implements AsyncConfigurer {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(RestapiApplication.class, args);
System.out.println("Rightdata Middleware ready to accept requests:");
}
#Bean(name = "executor1")
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setMaxPoolSize(2);
taskExecutor.setCorePoolSize(2);
taskExecutor.setThreadNamePrefix("LULExecutor-");
taskExecutor.setQueueCapacity(100);
taskExecutor.initialize();
return taskExecutor;
}
#Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new SimpleAsyncUncaughtExceptionHandler();
}
}
And here's my REST controller:
#RestController
#RequestMapping("/end2end")
public class End2EndRestController {
/**
* The log.
*/
private final Logger log = LoggerFactory.getLogger(this.getClass());
#RequestMapping(method = RequestMethod.POST)
public JSONObjectPOJO process(#RequestBody String end2EndScenarioString) throws InterruptedException, ExecutionException {
final JSONObjectPOJO jsonObjectPOJO = convertToJavaObject(end2EndScenarioString);
final ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(new Runnable() {
#Override
public void run() {
try {
execute(jsonObjectPOJO);
} catch (Exception e) {
e.getMessage();
}
}});
executor.shutdown();
return jsonObjectPOJO;
}
#Async("executor1")
private void execute(JSONObjectPOJO jsonObjectPOJO) throws Exception {
ExecutorService executorService = Executors.newFixedThreadPool(2);
Future<?> futureTarget;
Future<?> futureSource;
futureSource = processSource(executorService);
futureTarget = processTarget(executorService);
manageSourceProcessingResults(futureSource);
manageTargetProcessingResults(futureTarget);
executorService.shutdown();
//Do rest of the tasks.
}
#SuppressWarnings({"unchecked", "rawtypes"})
protected Future<?> processSource(executorService){
//Get appropriate class instance with call() - coreActionClass.
Future<?> futureSource = executorService.submit(coreActionClass);
return futureSource;
}
#SuppressWarnings({"unchecked", "rawtypes"})
protected Future<?> processTarget(executorService){
//Get appropriate class instance with call() - coreActionClass.
Future<?> futureTarget = executorService.submit(coreActionClass); //callable method in core.
return futureTarget;
}
private void manageSourceProcessingResults(Future<?> futureSource) {
try{
futureSource.get();
} catch(Exception e){
e.printStackTrace();
}
}
private void manageTargetProcessingResults(Future<?> futureTarget) {
try{
futureTarget.get();
} catch(Exception e){
e.printStackTrace();
}
}
}
UPDATE- 1:
I have now changed the code to following:
#RestController
#RequestMapping("/end2end")
public class End2EndRestController {
/**
* The log.
*/
private final Logger log = LoggerFactory.getLogger(this.getClass());
#RequestMapping(method = RequestMethod.POST)
public JSONObjectPOJO process(#RequestBody String end2EndScenarioString) throws InterruptedException, ExecutionException {
final JSONObjectPOJO jsonObjectPOJO = convertToJavaObject(end2EndScenarioString);
final ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(new Runnable() {
#Override
public void run() {
try {
execute(jsonObjectPOJO);
} catch (Exception e) {
e.getMessage();
}
}});
executor.shutdown();
return jsonObjectPOJO;
}
}
And AsyncService class:
public class AsyncService {
#Async("executor1")
public void execute(JSONObjectPOJO jsonObjectPOJO) throws Exception {
ExecutorService executorService = Executors.newFixedThreadPool(2);
Future<?> futureTarget;
Future<?> futureSource;
futureSource = processSource(executorService);
futureTarget = processTarget(executorService);
manageSourceProcessingResults(futureSource);
manageTargetProcessingResults(futureTarget);
executorService.shutdown();
//Do rest of the tasks.
}
#SuppressWarnings({"unchecked", "rawtypes"})
protected Future<?> processSource(executorService){
//Get appropriate class instance with call() - coreActionClass.
Future<?> futureSource = executorService.submit(coreActionClass);
return futureSource;
}
#SuppressWarnings({"unchecked", "rawtypes"})
protected Future<?> processTarget(executorService){
//Get appropriate class instance with call() - coreActionClass.
Future<?> futureTarget = executorService.submit(coreActionClass); //callable method in core.
return futureTarget;
}
private void manageSourceProcessingResults(Future<?> futureSource) {
try{
futureSource.get();
} catch(Exception e){
e.printStackTrace();
}
}
private void manageTargetProcessingResults(Future<?> futureTarget) {
try{
futureTarget.get();
} catch(Exception e){
e.printStackTrace();
}
}
}
My understanding is that when I configure maxpoolsize(2) no more
than 2 requests would be in the execute() method at one time. For a
new request to enter, one of the earlier requests has to complete
its execution. Is my understanding correct? Would the async apply
to the inner executor service?
I am of the view that at one time only 2 requests are handled and
each of those requests can spawn 2 different threads and complete
its task. Please clarify.
I see two problems.
1) In your process method you are creating a new ExecutorService. This is not needed. Instead just call the execute method after the jsonObjectPOJO is retrieved.
2) You cannot use #Async int he same class that it is implemented. You'll need to create a new class, lets called MyAsyncService to contain the #Async method. This is because of the aspect orientated programming that is going on under the covers.
Check out this link for more info. Below is a quote from the link.
First – let’s go over the rules – #Async has two limitations:
it must be applied to public methods only
self-invocation – calling the async method from within the same class – won’t work
The reasons are simple – the method needs to be public so that it can be proxied. And self-invocation doesn’t work because it bypasses the proxy and calls the underlying method directly.
EDIT 1:
#RestController
#RequestMapping("/end2end")
public class End2EndRestController {
#AutoWired
AsyncService asyncService;
private final Logger log = LoggerFactory.getLogger(this.getClass());
#RequestMapping(method = RequestMethod.POST)
public JSONObjectPOJO process(#RequestBody String end2EndScenarioString) throws InterruptedException, ExecutionException {
final JSONObjectPOJO jsonObjectPOJO = convertToJavaObject(end2EndScenarioString);
asyncService.execute(jsonObjectPOJO);
return jsonObjectPOJO;
}
public class AsyncService {
#Async("executor1")
public void execute(JSONObjectPOJO jsonObjectPOJO) throws Exception {
//No Futures, no ExecutorServices, just process that request.
}
}
By creating and configuring the ThreadPoolTaskExecutor to use only 2 threads, you have accomplished your goal.
EDIT2: Spring #Async limit number of threads

Spring Boot #Async method executing synchronously

This is very similar to the other question here: Spring Boot #Async method in controller is executing synchronously. However my #Service method annotated with #Async is still executing synchronously. I've tried all methods from different forums to no use. Hopefully someone could help me figure out why. A simple spring boot project as below doesn't work.
AsyncConfiguration.java
#Configuration
#EnableAsync
public class AsyncConfiguration(){}
SomeService.java
#Service
public class SomeService() {
#Async
public void doSomething() {
try {
Thread.sleep(5000L);
} catch (Exception ignore){}
}
}
SomeController.java
#Controller
public class SomeController() {
#Inject SomeService someService;
#RequestMapping(value="/", method=RequestMethod.POST)
public String doStuff() {
someService.doSomething();
return "mytemplate";
}
}
Here is a simple example with #Async. Follow these steps to get #Async to work in your Spring Boot application:
Step 1: Add #EnableAsync annotation and Add TaskExecutor Bean to Application Class.
Example:
#SpringBootApplication
#EnableAsync
public class AsynchronousSpringBootApplication {
private static final Logger logger = LoggerFactory.getLogger(AsynchronousSpringBootApplication.class);
#Bean(name="processExecutor")
public TaskExecutor workExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setThreadNamePrefix("Async-");
threadPoolTaskExecutor.setCorePoolSize(3);
threadPoolTaskExecutor.setMaxPoolSize(3);
threadPoolTaskExecutor.setQueueCapacity(600);
threadPoolTaskExecutor.afterPropertiesSet();
logger.info("ThreadPoolTaskExecutor set");
return threadPoolTaskExecutor;
}
public static void main(String[] args) throws Exception {
SpringApplication.run(AsynchronousSpringBootApplication.class,args);
}
}
Step 2: Add Method which executes an Asynchronous Process
#Service
public class ProcessServiceImpl implements ProcessService {
private static final Logger logger = LoggerFactory.getLogger(ProcessServiceImpl.class);
#Async("processExecutor")
#Override
public void process() {
logger.info("Received request to process in ProcessServiceImpl.process()");
try {
Thread.sleep(15 * 1000);
logger.info("Processing complete");
}
catch (InterruptedException ie) {
logger.error("Error in ProcessServiceImpl.process(): {}", ie.getMessage());
}
}
}
Step 3: Add an API in the Controller to execute the asynchronous processing
#Autowired
private ProcessService processService;
#RequestMapping(value = "ping/async", method = RequestMethod.GET)
public ResponseEntity<Map<String, String>> async() {
processService.process();
Map<String, String> response = new HashMap<>();
response.put("message", "Request is under process");
return new ResponseEntity<>(response, HttpStatus.OK);
}
I have also written a blog and a working application on GitHub with these steps. Please check:
http://softwaredevelopercentral.blogspot.com/2017/07/asynchronous-processing-async-in-spring.html
Sorry for my English.
The same problem happened to me.
The solution was to add
#Autowired
private SomeService someService;
In the Controller class, in this way it allows the class to contain the Beam Configurations associated with "SomeService", thus being able to execute the asynchronous method perfectly.
Here is a project with a functional asynchronous method:
https://github.com/JColmenares/async-method-api-rest.git

How to manage/stop spring 4 ConcurrentTaskScheduler

I am using Spring 4. I use this for execute a task periodically for web sockets:
private TaskScheduler scheduler = new ConcurrentTaskScheduler();
In my class:
#Configuration
#EnableWebSocketMessageBroker
#EnableScheduling
#Component
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
#Autowired
private SimpMessagingTemplate template;
private TaskScheduler scheduler = new ConcurrentTaskScheduler();
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/simplemessages").withSockJS();
}
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic/", "/queue/");
config.setApplicationDestinationPrefixes("/app");
}
#PostConstruct
private void broadcastTimePeriodically() {
scheduler.scheduleAtFixedRate(new Runnable() {
public void run() {
String statStr = "Server Response" + new Date();
System.out.println("thread schedular run time :" + Hello.printTime());
try {
template.convertAndSend("/topic/simplemessagesresponse", statStr);
} catch (MessagingException e) {
System.err.println("!!!!!! websocket timer error :>" + e.toString());
}
}
}, 4000));
}
#PreDestroy
private void destroyServices() {
scheduler = null; // how to destroy ?
}
public void configureClientInboundChannel(ChannelRegistration registration) {
}
public void configureClientOutboundChannel(ChannelRegistration registration) {
registration.taskExecutor().corePoolSize(4).maxPoolSize(10);
}
public boolean configureMessageConverters(List < MessageConverter > arg0) {
// TODO Auto-generated method stub
return true;
}
#Override
public void configureWebSocketTransport(WebSocketTransportRegistration arg0) {
}
}
I want to know to things:
I found that the scheduler is running twice within 4000 milliseconds. How is it happening and how can I stop it?
I run this application in tomcat. As you can see, the method destroyServices() needs to destroy the schedular. Here the problem is, even the tomcat is restarted again, previously running thread is still running. So when the tomcat is going to down, that thread also should be terminated. I need to know How I can destroy it on tomcat is going to down or any system crash?
The following code snippet is from documentation of #EnableScheduling:
#Configuration
#EnableScheduling
public class AppConfig implements SchedulingConfigurer {
#Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskExecutor());
}
#Bean(destroyMethod="shutdown")
public Executor taskExecutor() {
return Executors.newScheduledThreadPool(100);
}
}
I think you should get the bean named taskExecutor (in this case) and call shutdown (in fact depending on your configuration) method of it.

Categories

Resources