Monday, April 25, 2016

Creating a thread to run tasks with a timeout in a Spring Webserver

Leave a Comment

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?

2 Answers

Answers 1

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() {             }         }     } 

Answers 2

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 Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment