package com.mozilla.grouperfish.batch.scheduling; import java.util.concurrent.BlockingQueue; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.mozilla.grouperfish.batch.handlers.TaskHandler; import com.mozilla.grouperfish.model.Fail; import com.mozilla.grouperfish.model.Task; class Worker extends Thread { private static Logger log = LoggerFactory.getLogger(Worker.class); private static final int NUM_TRIES = 3; private final BlockingQueue<Task> inQueue; private final BlockingQueue<Task> outQueue; private final BlockingQueue<Task> failQueue; private final TaskHandler handler; private final String name; public Worker(final BlockingQueue<Task> failQueue, final BlockingQueue<Task> inQueue, final BlockingQueue<Task> outQueue, final TaskHandler actor) { this.inQueue = inQueue; this.outQueue = outQueue; this.failQueue = failQueue; this.handler = actor; this.name = String.format("[Worker for %s]", actor.getClass().getSimpleName()); } public String toString() { return name; } public void run() { Task task = null; try { while (!Thread.currentThread().isInterrupted()) { task = inQueue.take(); try { // :TODO: NEXT: // If power fails, tasks can go MIA here. // We should maintain a global map of tasks, check it periodically, and restart tasks that went MIA. // Task update their status there, and clients could check the status using a GET /run/... call. task = handler.handle(task); } catch (final Fail e) { log.warn(String.format("%s %s: failed with message '%s'", name, task, e.getMessage())); if (task.failures().size() >= NUM_TRIES) { log.error(String.format("%s %s: Error details:", name, task), e); log.error(String.format("%s %s: Retries exhausted. Failing.", name, task)); failQueue.put(task); } else { log.warn(String.format("%s %s: recording failure & requeuing...", name, task)); inQueue.put(task.fail(e.getMessage())); } continue; } catch (final Exception e) { log.error(String.format("%s %s: Exception while handling.", name, task)); log.error(String.format("%s %s: Error details:", name, task), e); failQueue.put(task.fail(e.getMessage())); continue; } if (outQueue != null) outQueue.put(task); task = null; } } catch (InterruptedException ex) { Thread.currentThread().interrupt(); } } public void cancel() { interrupt(); } }