/** * */ package com.trendrr.oss.taskprocessor; import java.util.ArrayList; import java.util.Comparator; import java.util.Date; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.trendrr.oss.PriorityUpdateQueue; import com.trendrr.oss.concurrent.Sleep; import com.trendrr.oss.exceptions.TrendrrTimeoutException; import com.trendrr.oss.taskprocessor.Task.ASYNCH; /** * Holds the tasks that a paused on some asynch task. * * @author Dustin Norlander * @created Sep 25, 2012 * */ public class AsynchTaskRegistery implements Runnable{ protected static Log log = LogFactory.getLog(AsynchTaskRegistery.class); protected ConcurrentHashMap<String, AsynchTaskWrapper> asynchTasks = new ConcurrentHashMap<String, AsynchTaskWrapper>(); protected PriorityUpdateQueue<AsynchTaskWrapper> asynchTaskFreeList = new PriorityUpdateQueue<AsynchTaskWrapper>(new Comparator<AsynchTaskWrapper>() { @Override public int compare(AsynchTaskWrapper o1, AsynchTaskWrapper o2) { //want the oldest items first return o2.getExpire().compareTo(o1.getExpire()); } }); protected ConcurrentHashMap<FuturePollerWrapper, Boolean> pollingFutures = new ConcurrentHashMap<FuturePollerWrapper, Boolean>(); protected LinkedBlockingQueue<FuturePollerWrapper> pollingFuturesQueue = new LinkedBlockingQueue<FuturePollerWrapper>(); protected Thread thread = null; public synchronized void start() { if (thread != null) { return; //already started } thread = new Thread(this); thread.setDaemon(true); thread.start(); } // /** // * Resumes the execution of the task // * @param id // * @return // */ // public Task resume(String id) { // Task t = this.remove(id); // if (t == null) // return null; // return resume(t); // } public Task resume(Task task) { this.remove(task.getId()); task.getProcessor().submitTask(task); return task; } /** * remove the task from the registry, does not resume its execution * @param id * @return */ public Task remove(String id) { AsynchTaskWrapper w = asynchTasks.remove(id); if (w == null) return null; asynchTaskFreeList.remove(w); return w.getTask(); } /** * add a task to the registry. * @param task * @param asynch * @param timeout */ public void add(Task task, ASYNCH asynch, long timeout) { AsynchTaskWrapper w = new AsynchTaskWrapper(task, asynch, timeout); if (this.asynchTasks.putIfAbsent(task.getId(), w) != null) { log.error("task : " + task.getId() + " is already in the task registry!"); return; } this.asynchTaskFreeList.push(w); } public void addFuture(FuturePollerWrapper wrapper) { this.pollingFutures.put(wrapper, true); this.pollingFuturesQueue.add(wrapper);//trigger a wakup. } /* (non-Javadoc) * @see java.lang.Runnable#run() */ @Override public void run() { //free thread. while(true) { Date now = new Date(); this.pollingFuturesQueue.clear(); int numFinished = 0; AsynchTaskWrapper t = asynchTaskFreeList.peek(); while(t != null && t.getExpire().before(now)) { t = asynchTaskFreeList.pop(); this.expired(t); t = asynchTaskFreeList.peek(); numFinished++; } // System.out.println("Don expiring, sleep ... size: " + this.asynchTasks.size()); //test the polling futures. for (FuturePollerWrapper f : this.pollingFutures.keySet()) { if (f.getFuture().isDone()) { this.pollingFutures.remove(f); f.getTask().getProcessor().getExecutor().execute(new FuturePollerCallbackThread(f, true)); numFinished++; } else if (f.getExpire().before(now)) { this.pollingFutures.remove(f); f.getTask().getProcessor().getExecutor().execute(new FuturePollerCallbackThread(f, false)); numFinished++; } } if (numFinished == 0) { //only sleep if we ran and nothing was finished... //randomize the sleep times if (this.pollingFutures.isEmpty()) { try { this.pollingFuturesQueue.poll((int)(250d * Math.random()), TimeUnit.MILLISECONDS); } catch (InterruptedException e) { log.error("Caught", e); } } else { //polling futures are considered way more time sensitive Sleep.millis((int)(5d * Math.random())); } } } } protected void expired(AsynchTaskWrapper t) { // System.out.println("Expiring: " + t.getTask().getId()); if (this.asynchTasks.remove(t.getTask().getId()) == null) { return; //already processed somewhere else } if (t.getAsynch() == ASYNCH.CONTINUE_ON_TIMEOUT) { t.getTask().asynch = false; t.getTask().getProcessor().submitTask(t.getTask()); } else if (t.getAsynch() == ASYNCH.FAIL_ON_TIMEOUNT) { t.getTask().getProcessor().taskError(t.getTask(), new TrendrrTimeoutException("Asynch Task with id: " + t.getTask().getId() + " timed out!")); } else if (t.getAsynch() == ASYNCH.DO_NOTHING_ON_TIMEOUT) { //do nothing.. } } }