Spring Boot REST - requests are not executing with ThreadPoolTaskExecutor configuration - java

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

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

Is creating runnables as a Spring component a bad practice?

It is the first time i use concurrency with Spring and i have a piece of code that makes concurrent calculations using Spring. Here is the code :
#Component
public class AppScheduler {
//#Autowired DAOs or services.
private ThreadPoolExecutor executor;
private AbstractApplicationContext context;
#PostConstruct
public void init() {
executor = new ThreadPoolExecutor(5, 5, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(10));
context = new AnnotationConfigApplicationContext(VtmDispatcherConfig.class);
}
#Scheduled(fixedDelay = 60 * 1000)
//at rejection break the execution.
public void appEntry() {
//fetch some records from db
for (Record rec : records) {
try {
executeTransactionally(rec);
} catch (RejectedExecutionException ex) {
break;
}
}
}
#Transactional
//Creates runnable tasks, makes some db operations and passes task to the thread pool
private void executeTransactionally(Record rec) {
ARunnableTask aRunnableTask = (ARunnableTask) context.getBean("aRunnableTask");
aRunnableTask.setParameter(rec.param);
//some db operations...
tempTableExecutorPool.execute(aRunnableTask);
}
}
Here a scheduled code fetchs records from db and with each record instantiates a runnable task and passes it to the thread pool executor. And my runnable task is here :
#Component
#Scope("prototype")
public class ARunnableTask implements Runnable {
private String param;
private ThreadPoolExecutor executor;
private DAOOrService inject
#Autowired
public TempTableExecutorTask(DAOOrService inject) {
executor = new ThreadPoolExecutor(5, 5, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(1000));
this.inject = inject;
}
#Override
public void run() {
//...
executeTransactional();
//...
executor.shutdown();
}
#Transactional
private void executeTransactional() {
//some transactional processes
}
public void setParameter(String param) {
this.param = param;
}
}
and here is my question : Is it a good practice creating runnable tasks as a spring component and using #Transactional in a runnable?
If it is not a bad practice, is there a better way for creating runnable spring components than :
ARunnableTask aRunnableTask = (ARunnableTask) context.getBean("aRunnableTask");
aRunnableTask.setParameter(rec.param);

How to start (and eventually stop) a daemon thread in Spring-Boot?

I'm writing a Spring-Boot application to monitor a directory and process files that are being added to it. I start a thread by creating a ApplicationRunner in my Application class that calls a method annotated with #Async:
#SpringBootApplication
#EnableAsync
public class Application {
#Autowired
private DirectoryMonitorService directoryMonitorService;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public ApplicationRunner startDirectoryMonitorService() {
return args -> directoryMonitorService.monitorSourceDirectoty();
}
}
Here is the code for DirectoryMonitorService that has a method annotated with #Async:
#Service
public class DirectoryMonitorService {
private static final Logger logger = LogManager.getLogger(DirectoryMonitorService.class);
#Value("${timeout}")
private long timeout;
#Autowired
private WatchService watchService;
#Async
public void monitorSourceDirectoty() {
while (true) {
WatchKey watchKey;
try {
watchKey = watchService.poll(timeout, TimeUnit.SECONDS);
} catch (ClosedWatchServiceException | InterruptedException e) {
logger.error("Exception occured while polling from source file", e);
return;
}
// process the WatchEvents
if (!watchKey.reset()) {
break;
}
}
}
}
Finally here is where I create the ThreadPoolTaskExecutor:
public class AsyncConfig extends AsyncConfigurerSupport {
private static final Logger logger = LogManager.getLogger(AsyncConfig.class);
private static final String THREAD_NAME_PREFIX = "Parser-";
#Value("${corePoolSize}")
public int corePoolSize;
#Value("${maxPoolSize}")
public int maxPoolSize;
#Value("${queueCapacity}")
public int queueCapacity;
#Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
executor.setThreadNamePrefix(THREAD_NAME_PREFIX);
executor.initialize();
return executor;
}
#Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return (Throwable ex, Method method, Object... params) -> {
logger.error("Exception message - " + ex.getMessage());
logger.error("Method name - " + method.getName());
for (Object param : params) {
logger.error("Parameter value - " + param);
}
};
}
}
Somehow I feel this is not most elegant way of starting a main thread. Does anybody have a better solution?
Also I would rather have replace while (true) with a Boolean variable that I can set to false when Spring-Boot shuts down. Does anybody know which interface I need to implement for this?
This is correct if you want a very simple implementation and nothing more reliable.
Use #Async to a shorter tasks and it has very limited capability in terms of restarts etc.
And also, #Async will keep creating the separate threads at every watch sequence activation, and it will overwhelm the thread pool and start trowing exceptions, This is quite noticeable, if you have long running task as,
// process the WatchEvents
Other than that your implementation is correct (In my opinion).
Some suggestions (If you want to make things interesting/ complex):
So you can keep track of the files obviously using some sort of persistence mechanism and trigger decoupled batch (can use Spring Batch) to handle the execution and, get those batches into a separate UI or something and there you can have each of these batch process stopped, start, resume on the UI.

RestEasy Async Controller Proper Usage

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);
});
}

Categories

Resources