Implementing threadpool in JAX-RS api - java

In a JAX-RS api, I want to implement a thread pool to allot new incoming requests to a new thread from the pool.
My api currently looks like this:
#Service
#Path("/")
public class SampleService {
#POST
#Path("/pass")
#Consumes(MediaType.APPLICATION_JSON)
public Response sampleApi(Incoming bean){
//do some processing on bean
File file = getUserData(bean);
//do some processing on file
return Response.status(200).entity("OK").build();
}
private File getUserData(Incoming bean){
//fetch data from external service through SOAP
//put in one file and return the file
}
}
My threadpool implementation looks like this
#Component
public class OnlineThreadPool {
private static ThreadPoolExecutor pool;
#PostConstruct
public void initialize(){
pool = new ThreadPoolExecutor(3, 20, 10, TimeUnit.SECONDS, new ArrayBlockingQueue<>(3));
}
public ThreadPoolExecutor getThreadPoolExecutor(){
return pool;
}
#PreDestroy
public void cleanUp(){
pool.shutdown();
}
}
I want to set up a asynchronous api so that on POST request for this api, new thread is obtained from threadpool and req is put in the new thread and response is returned without waiting for the thread to complete the processing of the request.
Any resources on how to implement this would be of great help.
EDIT:
Thanks to thilo`s answer, New thread is being created for each request but it terminates before the whole processing. But as soon as the parent thread calling this new thread terminates, child thread is also terminating. How to detach these parent child threads?
EDIT:
There was a null pointer exception in my process flow due to which thread execution was not completed. Since I have not given exception handler till now it was not showing any errors, just stopping without any exception message.

#POST
#Path("/pass")
#Consumes(MediaType.APPLICATION_JSON)
public Response sampleApi(final Incoming bean){
onlineThreadPool.getThreadPoolExecutor().submit(new Runnable(){
#Override public void run(){
//do some processing on bean
File file = getUserData(bean);
//do some processing on file
}});
return Response.status(200).entity("OK").build();
}

This is how it should look like. Notice that I am using constructor injection to inject your OnlineThreadPool dependency and Java 8 lambda for creating the Runnable.
#Service
#Path("/")
public class SampleService {
private OnlineThreadPool pool;
public SampleService(OnlineThreadPool pool) {
this.pool = pool;
} //constructor injection
#POST
#Path("/pass")
#Consumes(MediaType.APPLICATION_JSON)
public Response sampleApi(Incoming bean){
pool.getThreadPoolExecutor().submit(() -> {
File file = getUserData(bean);
//some other processing
});
return Response.status(200).entity("OK").build();
}
}

Related

Return response and execute some method (Tomcat)

Is there an option for tomcat to return some response to a request whilst at the same time executing a method in a backend service?
In my use case, I have a query which takes ~60s to execute. I'd like to respond a string to the request to let the user know that it will take some time whilst still executing the query itself in the backend service.
So instead of something like this:
...
response = this.service.getSomeData(request);
return response;
I'd like to do this:
...
return "Data not found"
this.service.getSomeData(request); // actually stores the result in a s3 bucket
You can execute it using another thread:
class MyServiceExecution implements Runnable{
public void run(){
System.out.println("thread is running...");
}
public static void main(String args[]){
MyServiceExecution m1=new MyServiceExecution();
Thread t1 =new Thread(m1);
t1.start();
}
}
Be careful when you implement threads... Read some about performance, garbage collection, etc.

How can I invoke a new #Async method but wait a condition?

I have a Spring Boot app that implements an AMQP MessageListener. This listener invoke to an #Async method managed by ThreadPoolTaskExecutor with pool size. The problem occurs when there are many incoming messages, so these messages are lost because there are no asynchronous workers available.
I am using Spring Core 5.0.7-RELEASE, Java 8
This is my code:
AsyncConfigurator:
#EnableAsync
#Configuration
public class AsyncConfiguration extends AsyncConfigurerSupport {
#Override
#Bean("docThreadPoolTaskExecutor")
public Executor getAsyncExecutor() {
final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(4);
executor.setMaxPoolSize(8);
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setThreadNamePrefix("DocWorkerThread-");
executor.initialize();
return executor;
}
My Back Service (MyAsyncService):
#Async("docThreadPoolTaskExecutor")
#Override
public void generaDocumento(String idUser, int year) {
//... some heavy and slow process
}
My message listener:
...
#Autowired
private MyAsyncService myAsyncService;
#Override
#EntryPoint
public void onMessage(Message message) {
try {
final String mensaje = new String(message.getBody(), StandardCharsets.UTF_8);
final MyPojo payload = JsonUtils.readFromJson(mensaje , MyPojo.class);
myAsyncService.generaDocumento(payload.getIdUser(), Integer.valueOf(payload.getYear()));
} catch ( Throwable t ) {
throw new AmqpRejectAndDontRequeueException( t );
}
}
I need someone to give me some idea to solve this.
ThreadPoolTaskExecutor has a queue by default. Messages should be added to the queue when you reach the corePoolSize. When the queue is full then more workers will be started until you reach the maxPoolSize. You can check the current queue size by executor.getThreadPoolExecutor().getQueue().size() to verify if the messages are really lost or just stuck in the queue.

Losing ApplicationContext when executing new runnables

I know I'm new to this spring stuff but I've been stuck on this all day. I don't much like asking questions but maybe I'll get an idea.
So here's my problem:
I'm trying to create a Queue for processing stuff on the back end. I did this by creating a static executorservice in a component class with helper methods to run them. it seems to work like i want, and when i wire in classes i can get into those classes, but it seems like when those are running they lose application context (or something this is just my guess).
I'm sure There are better ways to do this, but in the custom framework I am working in there are a number of features that will not work for me. I have no spring-config.xml, cannot use #Configuration
executor service component
#Component
public class FifoComponent {
public static ExecutorService executors = Executors.newSingleThreadExecutor();
private static Lock lock = new ReentrantLock(true);
public static void executeNewTestJob(int i) {
lock.lock();
OrderAllocationTestJob job = new OrderAllocationTestJob(i);
executors.execute(job);
lock.unlock();
}
}
Runnable component - note appdateutils has a method that calls a component that and works fine in my typical tomcat environment
#Component
public class OrderAllocationTestJob implements Runnable {
int i;
public OrderAllocationTestJob(int i) {
this.i = i;
}
#Override
public void run() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Asynchronous task " + i);
System.out.println(AppDateUtils.getCurrentTimeStamp());
}
}
call from a struts 2 action (test) i know I can call the appdateutils.gettime method from
for (int i = 0; i < 50; i++) {
FifoComponent.executeNewTestJob(i);
}
here's the exception i end up with for what it's worth
"Scope 'request' is not active for the current thread"
Exception in thread "pool-15-thread-50" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dateTimestampDao': Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
"I'm sure There are better ways to do this"
Based on this, you'll need to create/lookup all request and session scoped components before call another thread. Actually, request injection is thread local and can't works in your scenario.
i think if u remove
Thread.sleep(100);
in OrderAllocationTestJob to
job.sleep(100);
in FifoComponent will fix your problem
I solved this solution by extending ConcurrentLinkedQueue for my runnables and keeping them in a manager I instantiated in the initialize method of a ServletContextListener. By overriding the offer() method of the ConcurrentLinkedQueue to continually poll until the queue was empty I was able synchronously process runnables.
Unfortunately this locks down the request thread until the runnable is done and I will have to have my users keep an eye on it and let me know if the pages end up running long, but at least in my test environment the process seems sub-second even when i hit it with 20 at a time so I'm OK for now.
I would still prefer an ExecutorService executed from my Tomcat container but outside the scope of the requests but unless someone can answer the question I'm just going to have to leave it for now
Are you looking something like that?
#Component
public class AsynchronousThread extends Thread {
public static final Logger LOGGER = LoggerFactory
.getLogger(AsynchronousThread.class);
#Autowired
private Writer writer;
private BlockingQueue<IndexContextDTO> blockingQueue = new LinkedBlockingQueue<IndexContextDTO>(
500);
/**
*
*/
public AsynchronousThread() {
super("AsynchronousThread");
}
#PostConstruct
public void init() {
Integer internalQueueSize = 100;
this.blockingQueue = new LinkedBlockingQueue<>(internalQueueSize);
this.start();
}
#Override
public void run() {
while (true) {
// Do stuff
}
}
public void putInQueue(IndexContextDTO message) {
try {
this.blockingQueue.put(message);
} catch (InterruptedException interruptedException) {
// This exception will be thrown in very rare case.
LOGGER.error("An error while putting message in the queue. "
+ message, interruptedException);
}
}
}

What would happen to the threads managed by ExecutorService when tomcat shutting down?

I have an web app(with Spring/Spring boot) running on tomcat 7.There are some ExecutorService defined like:
public static final ExecutorService TEST_SERVICE = new ThreadPoolExecutor(10, 100, 60L,
TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(1000), new ThreadPoolExecutor.CallerRunsPolicy());
The tasks are important and must complete properly. I catch the exceptions and save them to db for retry, like this:
try {
ThreadPoolHolder.TEST_SERVICE.submit(new Runnable() {
#Override
public void run() {
try {
boolean isSuccess = false;
int tryCount = 0;
while (++tryCount < CAS_COUNT_LIMIT) {
isSuccess = doWork(param);
if (isSuccess) {
break;
}
Thread.sleep(1000);
}
if (!isSuccess) {
saveFail(param);
}
} catch (Exception e) {
log.error("test error! param : {}", param, e);
saveFail(param);
}
}
});
} catch (Exception e) {
log.error("test error! param:{}", param, e);
saveFail(param);
}
So, when tomcat shutting down, what will happen to the threads of the pool(running or waiting in the queue)? how to make sure that all the tasks either completed properly before shutdown or saved to db for retry?
Tomcat has built in Thread Leak detection, so you should get an error when the application is undeployed. As a developer it is your responsibility to link any object you create to the web applications lifecycle, this means You should never ever have static state which are not constants
If you are using Spring Boot, your Spring context is already linked to the applications lifecycle, so the best way is to create you executor as a Spring bean, and let Spring shut it down when the application stops. Here is an example you can put in any #Configuration class.
#Bean(destroyMethod = "shutdownNow", name = "MyExecutorService")
public ThreadPoolExecutor executor() {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 100, 60L,
TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(1000),
new ThreadPoolExecutor.CallerRunsPolicy());
return threadPoolExecutor;
}
As you can see the #Bean annotation allows you to specify a destroy method which will be executed when the Spring context is closed. In addition I have added the name property, this is because Spring typically creates a number of ExecutorServices for stuff like async web processing. When you need to use the executor, just Autowire it as any other spring bean.
#Autowired
#Qualifier(value = "MyExecutorService")
ThreadPoolExecutor executor;
Remember static is EVIL, you should only use static for constants, and potentially immutable obbjects.
EDIT
If you need to block the Tomcats shutdown procedure until the tasks have been processed, you need to wrap the Executor in a Component for more control, like this.
#Component
public class ExecutorWrapper implements DisposableBean {
private final ThreadPoolExecutor threadPoolExecutor;
public ExecutorWrapper() {
threadPoolExecutor = new ThreadPoolExecutor(10, 100, 60L,
TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(1000), new ThreadPoolExecutor.CallerRunsPolicy());
}
public <T> Future<T> submit(Callable<T> task) {
return threadPoolExecutor.submit(task);
}
public void submit(Runnable runnable) {
threadPoolExecutor.submit(runnable);
}
#Override
public void destroy() throws Exception {
threadPoolExecutor.shutdown();
boolean terminated = threadPoolExecutor.awaitTermination(1, TimeUnit.MINUTES);
if (!terminated) {
List<Runnable> runnables = threadPoolExecutor.shutdownNow();
// log the runnables that were not executed
}
}
}
With this code you call shutdown first so no new tasks can be submitted, then wait some time for the executor finish the current task and queue. If it does not finish in time you call shutdownNow to interrupt the running task, and get the list of unprocessed tasks.
Note: DisposableBean does the trick, but the best solution is actually to implement the SmartLifecycle interface. You have to implement a few more methods, but you get greater control, because no threads are started until all bean have been instantiated and the entire bean hierarchy is wired together, it even allows you to specify in which orders components should be started.
Tomcat as any Java application will not end untill all non-daeon threads will end. ThreadPoolExecutor in above example uses default thread factory and will create non-daemon threads.

Reading data from a thread ( in a Servlet)

I'm using the ServletContextListener to create a new thread.
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import java.util.concurrent.*;
public class Port implements ServletContextListener {
private ExecutorService executor;
public void contextDestroyed(ServletContextEvent event) {
executor.shutdown();
}
public void contextInitialized(ServletContextEvent event) {
// start task
executor = Executors.newSingleThreadExecutor();
executor.submit(new Task()); //task should implement Runnable!
}
}
Inside this thread I'm reading data from a serial port (SerialPortEventListener). The task.class should read out information from the serial port during the whole period in which the server is active. I've thrown this inside a thread because there can only be one instance that reads from the serial port; data should then be shared to all clients.
Now I would like to acces the data this thread is reading from the serial port.
Can this be done? And if yes then how?
You could, for example, store the read data in a servlet context attribute. Then, from the other classes, you would get the attribute from the servlet context:
public void contextInitialized(final ServletContextEvent event) {
// start task
executor = Executors.newSingleThreadExecutor();
executor.submit(new Runnable() {
#Override
public void run() {
String data = readFromPort();
event.getServletContext().setAttribute("serialPortData", data);
}
});
}
}
Yes it can be done, and you have few options:
1- Using a shared concurrent.BlockingQueue where inside the thread add new data from the SerialPort and in your servlet read from that queue
2- Have an event listener object inside your servlet and pass it in your task constructor. The listener object should have a callback function that is invoked when SerialEvent occur.
In general, this is a typical producer/consumer pattern
You'll need to share the data in the new Runnable you're going to create. You can add to it a concurrent collection.

Categories

Resources