/*******************************************************************************
* Copyright © 2012-2015 eBay Software Foundation
* This program is dual licensed under the MIT and Apache 2.0 licenses.
* Please see LICENSE for more information.
*******************************************************************************/
package com.ebay.jetstream.scattergather;
/**
* TaskMaster is created by the TaskMasterFactory. It provides an interface
* for user to submit scatter gather tasks and get them executed. Upon
* successful execution of the tasks the successfully executed tasks are
* returned back to the caller. It allows a caller to specify the timeout
* duration that it must wait for completing the task.
*
* @author shmurthy@ebay.com
*
*/
/**
* @author shmurthy (shmurthy@ebay.com)
*
*/
import java.util.Iterator;
import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicBoolean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TaskMaster {
private static final Logger LOGGER = LoggerFactory.getLogger("com.ebay.jetstream.scattergather");
private final LinkedList<Task> m_submittedTaskList = new LinkedList<Task>();
private final LinkedList<Task> m_executedTaskList = new LinkedList<Task>();
private TaskExecutor m_executor;
private final Object m_taskCompletionMonitor = new Object();
private long m_maxWaitTime = 1000;
private final AtomicBoolean m_abandonTask = new AtomicBoolean(false);
public void abandonTask() {
m_abandonTask.set(true);
}
/**
* @param timeout
* @return
*/
public LinkedList<Task> executeTasks(long timeout) {
synchronized (m_submittedTaskList) {
Iterator<Task> itr = m_submittedTaskList.iterator();
while (itr.hasNext()) {
Task t = itr.next();
t.setAbandonStatusIndicator(m_abandonTask);
TaskExecutorRequest ter = new TaskExecutorRequest(this, t);
try {
m_executor.execute(ter);
}
catch (Exception e) {
// TODO see how to handle this - if we are here it means we have no more resources left
// problem is part of the task might be already submitted. What do we do with that
// we might want to throw an exception at this point or continue with the submitted list
LOGGER.error( "Failed to execute task due to lack of resources - " + e.getLocalizedMessage());
}
}
}
long expiryTime = System.currentTimeMillis() + timeout;
long remainingTime = timeout;
boolean noTaskExecuted = true;
boolean maxTimeoutExpired = false;
while (true) {
synchronized (m_taskCompletionMonitor) {
try {
m_taskCompletionMonitor.wait(remainingTime);
}
catch (InterruptedException ie) {
}
}
if (m_executedTaskList.size() > 0) {
noTaskExecuted = false;
}
if (m_submittedTaskList.size() == m_executedTaskList.size())
break;
remainingTime = expiryTime - System.currentTimeMillis();
if (maxTimeoutExpired) {
abandonTask();
break;
}
if (remainingTime <= 0) {
if (noTaskExecuted) {
LOGGER.warn( "Timeout Extended by 1 SECOND");
remainingTime = getMaxWaitTime(); // wait a max of 1 more sec
maxTimeoutExpired = true;
}
else {
abandonTask();
break;
}
}
}
return m_submittedTaskList;
}
/**
* @return the executedTaskList
*/
public LinkedList<Task> getExecutedTaskList() {
return m_executedTaskList;
}
/**
* @return
*/
public TaskExecutor getExecutor() {
return m_executor;
}
public long getMaxWaitTime() {
return m_maxWaitTime;
}
/**
* @return the submittedTaskList
*/
public LinkedList<Task> getSubmittedTaskList() {
return m_submittedTaskList;
}
/**
* @param executor
*/
public void setExecutor(TaskExecutor executor) {
m_executor = executor;
}
public void setMaxWaitTime(long maxWaitTime) {
m_maxWaitTime = maxWaitTime;
}
/**
* @param task
*/
public void submitTask(Task task) {
synchronized (m_submittedTaskList) {
m_submittedTaskList.add(task);
}
}
/**
* @param task
*/
public void taskCompleted(Task task) {
synchronized (m_executedTaskList) {
task.executed();
m_executedTaskList.add(task);
}
synchronized (m_taskCompletionMonitor) {
m_taskCompletionMonitor.notifyAll();
}
}
}