Wednesday, February 15, 2012

Running long running JSP using a thread implementation

This works well in a proxy-ed environment with a session affinity to a JVM from the webtier.

Steps involve creating a worker thread which executes the long running process activity. Create a mechanism to look back on the process at regular intervals from the browser for completion. If the process did not complete kill the thread and report back as "timed out". If there are orphaned process kill them with the help of a maintenance thread initiated by a startup servlet.

Here is the example code samples.

class WorkingThread extends Thread implements Runnable {
String sessionId;
public WorkingThread () {

}

public WorkingThread (String sessionId) {
this.sessionId = sessionId;
}

public void run() {
System.out.println(" Working thread");


try {
synchronized (TestServletWorker.workerMap) {
HashMap threadDetails = (HashMap) TestServletWorker.workerMap.get(sessionId);
threadDetails.put("time", new Long( System.currentTimeMillis()));
}

Thread.sleep(1000 * 60 * 3); // implement the business logic

synchronized (TestServletWorker.workerMap) {
HashMap threadDetails = (HashMap) TestServletWorker.workerMap.get(sessionId);
threadDetails.put("Data", "my Data --> Done");
}


} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

public void stopThisThread () {

// Stop application functions here

this.interrupt();
try {
this.join ();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

Method to call initiate/track/check/retrieve the Application data from a JSP or any action classes.

public class TestServletWorker {

public static HashMap workerMap;

static {
System.out.println("testServletWorker");
workerMap = new HashMap ();
}

public static synchronized String testServletWorkerrunner (String sessionId) {

if (workerMap != null && workerMap.containsKey(sessionId) ) {
HashMap wtHash = (HashMap) workerMap.get(sessionId);
WorkingThread wt = (WorkingThread) wtHash.get("thread");
if ( !wt.isAlive() ) {
System.out.println("not alive ");
String ret = (String) wtHash.get("Data");
workerMap.remove(sessionId);
return ret;
} else if ( wt.isInterrupted() ) {
wtHash.put("Data", "timed out");
workerMap.remove(sessionId);
return "timed out";
}
} else if (workerMap != null && !workerMap.containsKey(sessionId)) {
WorkingThread wt = new WorkingThread (sessionId);
wt.start();
HashMap threadDetails = new HashMap ();
threadDetails.put("thread", wt);
workerMap.put(sessionId, threadDetails);
}

return null;
}


}

Thread to stop any abandoned or orphan threads

public class StopThreadServlet extends HttpServlet implements Servlet {

/**
*
*/
private static final long serialVersionUID = 1L;

public void init() throws ServletException {
System.out.println(": Registering .... ");
threadKiller tk = new threadKiller ();
tk.start();

while ( true ) {
try {
if ( !tk.isAlive() ) {
tk.start();
}
} catch (Exception w) {
w.printStackTrace();
}
}

}
}

class threadKiller extends Thread {

public void run () {
while ( true ) {
try {
Thread.sleep(1000 * 30 * 1); // Run every 1/2 minutes
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

synchronized ( TestServletWorker.workerMap) {
System.out.println( TestServletWorker.workerMap.size() + " current size");

if ( TestServletWorker.workerMap != null && TestServletWorker.workerMap.size() > 0) {
Set s = TestServletWorker.workerMap.keySet();
Iterator it = s.iterator();

while ( it.hasNext()) {
String sessionId = (String) it.next();
System.out.println(sessionId );

HashMap threadDetails = (HashMap)TestServletWorker.workerMap.get(sessionId);
long starttime = ((Long) threadDetails.get("time")).longValue();
long currtime = System.currentTimeMillis();
long diffIntime = currtime - starttime;
if ( diffIntime > 1000 * 60 * 2 ) { // Kill threads > 2 minutes
System.out.println("stop this thread > 2 mins");
WorkingThread thrd = (WorkingThread) threadDetails.get("thread"); // Replace with WorkerThread impl class
threadDetails.put("Data", "timed out");
thrd.stopThisThread(); // Call a stop function in the the Thread implementation class.
System.out.println( TestServletWorker.workerMap.size() + " New current size");
}
}
}
}
}
}
}

Start up servlet configuration in web.xml


<servlet>
<description>Stopthreads running for long duration</description>
<display-name>Stopthreads</display-name>
<servlet-name>Stopthreads</servlet-name>
<servlet-class>StopThreadServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

No comments:

Post a Comment