I'm trying to create a thread which runs a set of tasks and, if it does not finish within a specific time (say 100 seconds), throws an exception. Currently I am trying to do this by encapsulating the tasks into a runnable
object and using ExecutorService
and Future
classes to do the timeout executions. However, when I start my Webservice I get this exception:
java.util.concurrent.ExecutionException: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.localhostInterpolatorHealthCheck': 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.
at java.util.concurrent.FutureTask.report(FutureTask.java:122)
at java.util.concurrent.FutureTask.get(FutureTask.java:202)
I read online that it's not as simple as defining your own threads and starting them to get a thread started on Spring, so I am wondering how to do this? What am I missing?
An Executor can be used to start the thread at any point throughout the application's execution. Loading cached data as a Spring application boots up is one example. To accomplish this, the Executor call would be made in the Spring Boot application's main method, prior to the SpringApplication. run().
The TaskExecutor was originally created to give other Spring components an abstraction for thread pooling where needed. Components such as the ApplicationEventMulticaster , JMS's AbstractMessageListenerContainer , and Quartz integration all use the TaskExecutor abstraction to pool threads.
The first step is to add the TaskExecutor configuration to our Spring application. Once we have our executor set up, the process is simple. We inject the executor to a Spring component and then we submit Runnable classes containing the tasks to be executed.
Try this :
/**
* Executes a task with a specified timeout.
*/
public final class TimeoutController {
/**
* Do not instantiate objects of this class. Methods are static.
*/
private TimeoutController() {
}
/**
* Executes <code>task</code>. Waits for <code>timeout</code>
* milliseconds for the task to end and returns. If the task does not return
* in time, the thread is interrupted and an Exception is thrown.
* The caller should override the Thread.interrupt() method to something that
* quickly makes the thread die or use Thread.isInterrupted().
* @param task The thread to execute
* @param timeout The timeout in milliseconds. 0 means to wait forever.
* @throws TimeoutException if the timeout passes and the thread does not return.
*/
public static void execute(Thread task, long timeout) throws TimeoutException {
task.start();
try {
task.join(timeout);
} catch (InterruptedException e) {
/* if somebody interrupts us he knows what he is doing */
}
if (task.isAlive()) {
task.interrupt();
throw new TimeoutException();
}
}
/**
* Executes <code>task</code> in a new deamon Thread and waits for the timeout.
* @param task The task to execute
* @param timeout The timeout in milliseconds. 0 means to wait forever.
* @throws TimeoutException if the timeout passes and the thread does not return.
*/
public static void execute(Runnable task, long timeout) throws TimeoutException {
Thread t = new Thread(task, "Timeout guard");
t.setDaemon(true);
execute(t, timeout);
}
/**
* Signals that the task timed out.
*/
public static class TimeoutException extends Exception {
/** Create an instance */
public TimeoutException() {
}
}
}
You can have several @async methods instead, and then run them from your main code flow, obtain list of futures. After timeout passes you can get result or stop execution (cancel/terminate).
This has benefits as you will call spring managed beans, thus all dependency injected properties will be available for you. But you should be careful on the amount of jobs/threads you submit.
In order to use @async annotation you need to enable async stuff by using either specific line in your xml configuration or AsyncEnabled annotation on your bean.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With