azkaban-aplcache
Changes
src/java/azkaban/executor/ExecutorManager.java 173(+162 -11)
src/java/azkaban/utils/WebUtils.java 35(+34 -1)
src/web/css/azkaban.css 64(+64 -0)
src/web/js/azkaban.exflow.view.js 20(+19 -1)
src/web/js/azkaban.flow.view.js 20(+18 -2)
Details
src/java/azkaban/executor/ExecutorManager.java 173(+162 -11)
diff --git a/src/java/azkaban/executor/ExecutorManager.java b/src/java/azkaban/executor/ExecutorManager.java
index e3ff56c..8370103 100644
--- a/src/java/azkaban/executor/ExecutorManager.java
+++ b/src/java/azkaban/executor/ExecutorManager.java
@@ -8,6 +8,7 @@ import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -29,6 +30,7 @@ import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.log4j.Logger;
+import org.joda.time.DateTime;
import azkaban.executor.ExecutableFlow.Status;
import azkaban.flow.Flow;
@@ -45,8 +47,10 @@ public class ExecutorManager {
private static final String ACTIVE_DIR = ".active";
private static final String ARCHIVE_DIR = ".archive";
private static Logger logger = Logger.getLogger(ExecutorManager.class);
- private static final long ACCESS_ERROR_THRESHOLD = 60000;
+ // 30 seconds of retry before failure.
+ private static final long ACCESS_ERROR_THRESHOLD = 30000;
private static final int UPDATE_THREAD_MS = 1000;
+
private File basePath;
private AtomicInteger counter = new AtomicInteger();
@@ -153,6 +157,71 @@ public class ExecutorManager {
return execFlows;
}
+ public List<ExecutionReference> getFlowHistory(int numResults, int skip) {
+ ArrayList<ExecutionReference> searchFlows = new ArrayList<ExecutionReference>();
+
+ for (ExecutableFlow flow: runningFlows.values()) {
+ if (skip > 0) {
+ skip--;
+ }
+ else {
+ ExecutionReference ref = new ExecutionReference(flow);
+ searchFlows.add(ref);
+ if (searchFlows.size() == numResults) {
+ Collections.sort(searchFlows);
+ return searchFlows;
+ }
+ }
+ }
+
+ File archivePath = new File(basePath, ARCHIVE_DIR);
+ if (!archivePath.exists()) {
+ return searchFlows;
+ }
+
+ File[] archivePartitionsDir = archivePath.listFiles();
+ for (File archivePartition: archivePartitionsDir) {
+ File[] listArchivePartitions = archivePartition.listFiles();
+ if (skip > listArchivePartitions.length) {
+ skip -= listArchivePartitions.length;
+ continue;
+ }
+
+ Arrays.sort(listArchivePartitions);
+ for (int i = listArchivePartitions.length - 1; i >= 0; --i) {
+ if (skip > 0) {
+ skip--;
+ }
+ else {
+ try {
+ ExecutionReference ref = ExecutionReference.readFromDirectory(listArchivePartitions[i]);
+ searchFlows.add(ref);
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ if (searchFlows.size() == numResults) {
+ Collections.sort(searchFlows);
+ return searchFlows;
+ }
+ }
+ }
+ }
+
+ Collections.sort(searchFlows);
+ return searchFlows;
+ }
+
+ private boolean isBetween(long val, long from, long to) {
+ // Means that range isn't set, so we'll just say that it's okay.
+ if (to < -1) {
+ return true;
+ }
+
+ return val >= from && val <= to;
+ }
+
private void loadActiveExecutions() throws IOException, ExecutorManagerException {
File activeFlows = new File(basePath, ACTIVE_DIR);
File[] activeFlowDirs = activeFlows.listFiles();
@@ -226,7 +295,10 @@ public class ExecutorManager {
File referenceDir = new File(baseActiveDir, executionId);
if (!referenceDir.exists()) {
- File baseArchiveDir = new File(basePath, ARCHIVE_DIR);
+ // Find the partition it would be in and search.
+ String partition = getExecutableReferencePartition(executionId);
+
+ File baseArchiveDir = new File(basePath, ARCHIVE_DIR + File.separator + partition);
referenceDir = new File(baseArchiveDir, executionId);
if (!referenceDir.exists()) {
throw new ExecutorManagerException("Execution id '" + executionId + "' not found. Searching " + referenceDir);
@@ -508,6 +580,14 @@ public class ExecutorManager {
return response;
}
+ private String getExecutableReferencePartition(String execID) {
+ // We're partitioning the archive by the first part of the id, which should be a timestamp.
+ // Then we're taking a substring of length - 6 to lop off the bottom 5 digits effectively partitioning
+ // by 100000 millisec. We do this to have quicker searchs by pulling partitions, not full directories.
+ int index = execID.indexOf('.');
+ return execID.substring(0, index - 5);
+ }
+
private void cleanFinishedJob(ExecutableFlow exFlow) throws ExecutorManagerException {
// Write final file
@@ -522,16 +602,44 @@ public class ExecutorManager {
throw new ExecutorManagerException("Active reference " + activeDirectory + " doesn't exists.");
}
- String archiveReferencePath = ARCHIVE_DIR + File.separator + exFlow.getExecutionId();
- File archiveDirectory = new File(basePath, archiveReferencePath);
+ String exId = exFlow.getExecutionId();
+ String partitionVal = getExecutableReferencePartition(exId);
+
+ String archiveDatePartition = ARCHIVE_DIR + File.separator + partitionVal;
+ File archivePartitionDir = new File(basePath, archiveDatePartition);
+ if (!archivePartitionDir.exists()) {
+ archivePartitionDir.mkdirs();
+ }
+
+ File archiveDirectory = new File(archivePartitionDir, exFlow.getExecutionId());
if (archiveDirectory.exists()) {
- logger.error("WTF!! Archive reference already exists!");
- throw new ExecutorManagerException("Active reference " + archiveDirectory + " already exists.");
+ logger.error("Archive reference already exists. Cleaning up.");
+ try {
+ FileUtils.deleteDirectory(activeDirectory);
+ } catch (IOException e) {
+ logger.error(e);
+ }
+
+ return;
+ }
+
+ // Make new archive dir
+ if (!archiveDirectory.mkdirs()) {
+ throw new ExecutorManagerException("Cannot create " + archiveDirectory);
+ }
+
+ ExecutionReference reference = new ExecutionReference(exFlow);
+ try {
+ reference.writeToDirectory(archiveDirectory);
+ } catch (IOException e) {
+ throw new ExecutorManagerException("Couldn't write execution to directory.", e);
}
// Move file.
- if (!activeDirectory.renameTo(archiveDirectory)) {
- throw new ExecutorManagerException("Cannot move " + activeDirectory + " to " + archiveDirectory);
+ try {
+ FileUtils.deleteDirectory(activeDirectory);
+ } catch (IOException e) {
+ throw new ExecutorManagerException("Cannot cleanup active directory " + activeDirectory);
}
runningFlows.remove(exFlow.getExecutionId());
@@ -613,6 +721,7 @@ public class ExecutorManager {
logger.error("Flow " + exFlow.getExecutionId() + " has succeeded, but the Executor says its still running with msg: " + status);
if (System.currentTimeMillis() - exFlow.getLastCheckedTime() > ACCESS_ERROR_THRESHOLD) {
exFlow.setStatus(Status.FAILED);
+ exFlow.setEndTime(System.currentTimeMillis());
logger.error("It's been " + ACCESS_ERROR_THRESHOLD + " ms since last update. Auto-failing the job.");
}
}
@@ -623,6 +732,7 @@ public class ExecutorManager {
logger.error("Flow " + exFlow.getExecutionId() + " is running, but the Executor can't find it.");
if (System.currentTimeMillis() - exFlow.getLastCheckedTime() > ACCESS_ERROR_THRESHOLD) {
exFlow.setStatus(Status.FAILED);
+ exFlow.setEndTime(System.currentTimeMillis());
logger.error("It's been " + ACCESS_ERROR_THRESHOLD + " ms since last update. Auto-failing the job.");
}
}
@@ -644,13 +754,16 @@ public class ExecutorManager {
}
}
- private static class ExecutionReference {
+ public static class ExecutionReference implements Comparable<ExecutionReference> {
private String execId;
private String projectId;
private String flowId;
private String userId;
private String execPath;
-
+ private long startTime;
+ private long endTime;
+ private Status status;
+
public ExecutionReference() {
}
@@ -660,6 +773,10 @@ public class ExecutorManager {
this.flowId = flow.getFlowId();
this.userId = flow.getSubmitUser();
this.execPath = flow.getExecutionPath();
+
+ this.startTime = flow.getStartTime();
+ this.endTime = flow.getEndTime();
+ this.status = flow.getStatus();
}
private Object toObject() {
@@ -669,6 +786,9 @@ public class ExecutorManager {
obj.put("flowId", flowId);
obj.put("userId", userId);
obj.put("execPath", execPath);
+ obj.put("startTime", startTime);
+ obj.put("endTime", endTime);
+ obj.put("status", status);
return obj;
}
@@ -692,7 +812,9 @@ public class ExecutorManager {
reference.flowId = (String)obj.get("flowId");
reference.userId = (String)obj.get("userId");
reference.execPath = (String)obj.get("execPath");
-
+ reference.startTime = (Long)obj.get("startTime");
+ reference.endTime = (Long)obj.get("endTime");
+ reference.status = Status.valueOf((String)obj.get("status"));
return reference;
}
@@ -715,5 +837,34 @@ public class ExecutorManager {
public String getExecPath() {
return execPath;
}
+
+ public Long getStartTime() {
+ return startTime;
+ }
+
+ public void setStartTime(Long startTime) {
+ this.startTime = startTime;
+ }
+
+ public Long getEndTime() {
+ return endTime;
+ }
+
+ public void setEndTime(Long endTime) {
+ this.endTime = endTime;
+ }
+
+ @Override
+ public int compareTo(ExecutionReference arg0) {
+ return arg0.getExecId().compareTo(execId);
+ }
+
+ public Status getStatus() {
+ return status;
+ }
+
+ public void setStatus(Status status) {
+ this.status = status;
+ }
}
}
diff --git a/src/java/azkaban/webapp/servlet/AbstractAzkabanServlet.java b/src/java/azkaban/webapp/servlet/AbstractAzkabanServlet.java
index a2736eb..515e14b 100644
--- a/src/java/azkaban/webapp/servlet/AbstractAzkabanServlet.java
+++ b/src/java/azkaban/webapp/servlet/AbstractAzkabanServlet.java
@@ -35,7 +35,7 @@ import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
-import azkaban.utils.GUIUtils;
+import azkaban.utils.WebUtils;
import azkaban.utils.JSONUtils;
import azkaban.utils.Props;
import azkaban.webapp.AzkabanWebServer;
@@ -56,7 +56,7 @@ public abstract class AbstractAzkabanServlet extends HttpServlet {
public static final String XML_MIME_TYPE = "application/xhtml+xml";
public static final String JSON_MIME_TYPE = "application/json";
- private static final GUIUtils utils = new GUIUtils();
+ private static final WebUtils utils = new WebUtils();
private AzkabanWebServer application;
private String name;
@@ -130,6 +130,18 @@ public abstract class AbstractAzkabanServlet extends HttpServlet {
String p = getParam(request, name);
return Integer.parseInt(p);
}
+
+ public int getIntParam(HttpServletRequest request, String name, int defaultVal) {
+ if (hasParam(request, name)) {
+ try {
+ return getIntParam(request, name);
+ } catch (Exception e) {
+ return defaultVal;
+ }
+ }
+
+ return defaultVal;
+ }
public Map<String, String> getParamGroup(HttpServletRequest request, String groupName) throws ServletException {
Enumeration<Object> enumerate = (Enumeration<Object>)request.getParameterNames();
diff --git a/src/java/azkaban/webapp/servlet/HistoryServlet.java b/src/java/azkaban/webapp/servlet/HistoryServlet.java
index e2b9abf..d665e5b 100644
--- a/src/java/azkaban/webapp/servlet/HistoryServlet.java
+++ b/src/java/azkaban/webapp/servlet/HistoryServlet.java
@@ -1,23 +1,68 @@
package azkaban.webapp.servlet;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import azkaban.executor.ExecutorManager;
+import azkaban.executor.ExecutorManager.ExecutionReference;
+import azkaban.project.ProjectManager;
import azkaban.webapp.session.Session;
public class HistoryServlet extends LoginAbstractAzkabanServlet {
private static final long serialVersionUID = 1L;
+ private ProjectManager projectManager;
+ private ExecutorManager executorManager;
+
+ @Override
+ public void init(ServletConfig config) throws ServletException {
+ super.init(config);
+ projectManager = this.getApplication().getProjectManager();
+ executorManager = this.getApplication().getExecutorManager();
+ }
@Override
protected void handleGet(HttpServletRequest req, HttpServletResponse resp,
Session session) throws ServletException, IOException {
Page page = newPage(req, resp, session, "azkaban/webapp/servlet/velocity/historypage.vm");
+ int pageNum = getIntParam(req, "page", 1);
+ int pageSize = getIntParam(req, "size", 16);
+
+ if (pageNum < 0) {
+ pageNum = 1;
+ }
+ List<ExecutionReference> history = executorManager.getFlowHistory(pageSize, (pageNum - 1)*pageSize);
+ page.add("flowHistory", history);
+ page.add("size", pageSize);
+ page.add("page", pageNum);
+ if (pageNum == 1) {
+ page.add("previous", new PageSelection(1, pageSize, true, false));
+ }
+ page.add("next", new PageSelection(pageNum + 1, pageSize, false, false));
+ // Now for the 5 other values.
+ int pageStartValue = 1;
+ if (pageNum > 3) {
+ pageStartValue = pageNum - 2;
+ }
+
+ page.add("page1", new PageSelection(pageStartValue, pageSize, false, pageStartValue == pageNum));
+ pageStartValue++;
+ page.add("page2", new PageSelection(pageStartValue, pageSize, false, pageStartValue == pageNum));
+ pageStartValue++;
+ page.add("page3", new PageSelection(pageStartValue, pageSize, false, pageStartValue == pageNum));
+ pageStartValue++;
+ page.add("page4", new PageSelection(pageStartValue, pageSize, false, pageStartValue == pageNum));
+ pageStartValue++;
+ page.add("page5", new PageSelection(pageStartValue, pageSize, false, pageStartValue == pageNum));
+ pageStartValue++;
page.render();
}
@@ -29,4 +74,37 @@ public class HistoryServlet extends LoginAbstractAzkabanServlet {
}
+ public class PageSelection {
+ private int page;
+ private int size;
+ private boolean disabled;
+ private boolean selected;
+
+ public PageSelection(int page, int size, boolean disabled, boolean selected) {
+ this.page = page;
+ this.size = size;
+ this.disabled = disabled;
+ this.setSelected(selected);
+ }
+
+ public int getPage() {
+ return page;
+ }
+
+ public int getSize() {
+ return size;
+ }
+
+ public boolean getDisabled() {
+ return disabled;
+ }
+
+ public boolean isSelected() {
+ return selected;
+ }
+
+ public void setSelected(boolean selected) {
+ this.selected = selected;
+ }
+ }
}
diff --git a/src/java/azkaban/webapp/servlet/velocity/executionspage.vm b/src/java/azkaban/webapp/servlet/velocity/executionspage.vm
index 4a15e8b..3dd9c6f 100644
--- a/src/java/azkaban/webapp/servlet/velocity/executionspage.vm
+++ b/src/java/azkaban/webapp/servlet/velocity/executionspage.vm
@@ -34,8 +34,10 @@
<table id="executingJobs">
<thead>
<tr>
+ <th class="execid">Execution Id</th>
<th>Flow</th>
- <th>User</th>
+ <th>Project</th>
+ <th class="user">User</th>
<th class="date">Start Time</th>
<th class="date">End Time</th>
<th class="elapse">Elapsed</th>
@@ -48,13 +50,17 @@
#foreach($flow in $runningFlows)
<tr class="row" >
<td class="tb-name">
- <a href="${context}/execution?execid=${flow.executionId}">${flow.flowId}</a>
+ <a href="${context}/executions?execid=${flow.executionId}">$utils.extractNumericalId(${flow.executionId})</a>
+ </td>
+ <td><a href="${context}/manager?project=${flow.projectId}&flow=${flow.flowId}">${flow.flowId}</a></td>
+ <td>
+ <a href="${context}/manager?project=${flow.projectId}">${flow.projectId}</a>
</td>
<td>${flow.submitUser}</td>
<td>$utils.formatDate(${flow.startTime})</td>
<td>$utils.formatDate(${flow.endTime})</td>
<td>$utils.formatDuration(${flow.startTime}, ${flow.endTime})</td>
- <td>${flow.status}</td>
+ <td><div class="status ${flow.status}">$utils.formatStatus(${flow.status})</div></td>
<td></td>
</tr>
#end
@@ -69,8 +75,10 @@
<table id="recentlyFinished">
<thead>
<tr>
+ <th class="execid">Execution Id</th>
<th>Flow</th>
- <th>User</th>
+ <th>Project</th>
+ <th class="user">User</th>
<th class="date">Start Time</th>
<th class="date">End Time</th>
<th class="elapse">Elapsed</th>
@@ -83,13 +91,17 @@
#foreach($flow in $recentlyFinished)
<tr class="row" >
<td class="tb-name">
- <a href="${context}/executions?execid=${flow.executionId}">${flow.flowId}</a>
+ <a href="${context}/executions?execid=${flow.executionId}">$utils.extractNumericalId(${flow.executionId})</a>
+ </td>
+ <td><a href="${context}/manager?project=${flow.projectId}&flow=${flow.flowId}">${flow.flowId}</a></td>
+ <td>
+ <a href="${context}/manager?project=${flow.projectId}">${flow.projectId}</a>
</td>
<td>${flow.submitUser}</td>
<td>$utils.formatDate(${flow.startTime})</td>
<td>$utils.formatDate(${flow.endTime})</td>
<td>$utils.formatDuration(${flow.startTime}, ${flow.endTime})</td>
- <td>${flow.status}</td>
+ <td><div class="status ${flow.status}">$utils.formatStatus(${flow.status})</div></td>
<td></td>
</tr>
#end
diff --git a/src/java/azkaban/webapp/servlet/velocity/historypage.vm b/src/java/azkaban/webapp/servlet/velocity/historypage.vm
index 4296ebc..7204cee 100644
--- a/src/java/azkaban/webapp/servlet/velocity/historypage.vm
+++ b/src/java/azkaban/webapp/servlet/velocity/historypage.vm
@@ -38,7 +38,9 @@
<table id="executingJobs">
<thead>
<tr>
+ <th class="execid">Execution Id</th>
<th>Flow</th>
+ <th>Project</th>
<th>User</th>
<th class="date">Start Time</th>
<th class="date">End Time</th>
@@ -48,25 +50,46 @@
</tr>
</thead>
<tbody>
- #if($runningFlows)
-#foreach($flow in $runningFlows)
+ #if($flowHistory)
+#foreach($flow in $flowHistory)
<tr class="row" >
<td class="tb-name">
- <a href="${context}/execution?execid=${flow.executionId}">${flow.flowId}</a>
+ <a href="${context}/executions?execid=${flow.execId}">$utils.extractNumericalId(${flow.execId})</a>
</td>
- <td>${flow.submitUser}</td>
+ <td class="tb-name">
+ <a href="${context}/manager?project=${flow.projectId}&flow=${flow.flowId}">${flow.flowId}</a>
+ </td>
+ <td>
+ <a href="${context}/manager?project=${flow.projectId}">${flow.projectId}</a>
+ </td>
+ <td>${flow.userId}</td>
<td>$utils.formatDate(${flow.startTime})</td>
<td>$utils.formatDate(${flow.endTime})</td>
<td>$utils.formatDuration(${flow.startTime}, ${flow.endTime})</td>
- <td>${flow.status}</td>
+ <td><div class="status ${flow.status}">$utils.formatStatus(${flow.status})</div></td>
<td></td>
</tr>
#end
#else
- <tr><td class="last">No History Found</td></tr>
+ <tr><td class="last">No History Results Found</td></tr>
#end
</tbody>
</table>
+
+ <div id="pageSelection" class="nonjavascript">
+ <ul>
+
+ <li id="previous" class="first"><a href="${context}/history?page=${previous.page}&size=${previous.size}"><span class="arrow">←</span>Previous</a></li>
+
+ <li id="page1" #if($page1.selected) class="selected" #end><a href="${context}/history?page=${page1.page}&size=${page1.size}">${page1.page}</a></li>
+ <li id="page2" #if($page2.selected) class="selected" #end><a href="${context}/history?page=${page2.page}&size=${page2.size}">${page2.page}</a></li>
+ <li id="page3" #if($page3.selected) class="selected" #end><a href="${context}/history?page=${page3.page}&size=${page3.size}">${page3.page}</a></li>
+ <li id="page4" #if($page4.selected) class="selected" #end><a href="${context}/history?page=${page4.page}&size=${page4.size}">${page4.page}</a></li>
+ <li id="page5" #if($page5.selected) class="selected" #end><a href="${context}/history?page=${page5.page}&size=${page5.size}">${page5.page}</a></li>
+
+ <li id="next"><a href="${context}/history?page=${next.page}&size=${next.size}">Next<span class="arrow">→</span></a></li>
+ </ul>
+ </div>
</div>
</div>
</body>
src/web/css/azkaban.css 64(+64 -0)
diff --git a/src/web/css/azkaban.css b/src/web/css/azkaban.css
index 8d7096e..13163f8 100644
--- a/src/web/css/azkaban.css
+++ b/src/web/css/azkaban.css
@@ -1366,6 +1366,10 @@ span.sublabel {
margin-top: 5px;
}
+#pageSelection ul li:hover {
+ background-color: #D5F2FF;
+}
+
#pageSelection ul li.first {
border-left: 1px solid #CCC;
}
@@ -1470,6 +1474,18 @@ span.sublabel {
width: 140px;
}
+.executionInfo table th.execid {
+ width: 150px;
+}
+
+.executionInfo table th.project {
+ width: 200px;
+}
+
+.executionInfo table th.user {
+ width: 60px;
+}
+
.executionInfo table th.elapse {
width: 90px;
}
@@ -1502,6 +1518,49 @@ span.sublabel {
height: 20px;
}
+td .status {
+ -moz-border-radius: 2px;
+ border-radius: 2px;
+
+ padding: 2px 2px;
+ color: #FFF;
+ text-align: center;
+ margin-top: 2px;
+}
+
+td .status.SUCCEEDED {
+ background-color: #82B859;
+}
+
+td .status.FAILED {
+ background-color: #C82123;
+}
+
+td .status.READY {
+ background-color: #C82123;
+}
+
+td .status.RUNNING {
+ background-color: #3398CC;
+}
+
+td .status.FAILED_FINISHING {
+ background-color: #F19153;
+}
+
+td .status.DISABLED {
+ background-color: #AAA;
+}
+
+td .status.KILLED {
+ background-color: #000;
+}
+
+td .status.UNKNOWN {
+ background-color: #CCC;
+}
+
+
.flow-header {
height: 48px;
}
@@ -1510,6 +1569,11 @@ span.sublabel {
width: 280px;
margin: 4px;
background-color: #e2e4e3;
+ border: 1px solid #FFF;
+}
+
+tr:hover .outerProgress {
+ background-color: #F8F8F8;
}
.progressBox {
src/web/js/azkaban.exflow.view.js 20(+19 -1)
diff --git a/src/web/js/azkaban.exflow.view.js b/src/web/js/azkaban.exflow.view.js
index c95520d..c639026 100644
--- a/src/web/js/azkaban.exflow.view.js
+++ b/src/web/js/azkaban.exflow.view.js
@@ -1,6 +1,17 @@
$.namespace('azkaban');
var statusList = ["FAILED", "FAILED_FINISHING", "SUCCEEDED", "RUNNING", "WAITING", "KILLED", "DISABLED", "READY", "UNKNOWN"];
+var statusStringMap = {
+ "FAILED": "Failed",
+ "SUCCEEDED": "Success",
+ "FAILED_FINISHING": "Running w/Failure",
+ "RUNNING": "Running",
+ "WAITING": "Waiting",
+ "KILLED": "Killed",
+ "DISABLED": "Disabled",
+ "READY": "Ready",
+ "UNKNOWN": "Unknown"
+};
var handleJobMenuClick = function(action, el, pos) {
var jobid = el[0].jobid;
@@ -578,7 +589,9 @@ azkaban.ExecutionListView = Backbone.View.extend({
this.addNodeRow(node);
}
- $("#" + node.id + "-status").text(node.status);
+ var div = $("#" + node.id + "-status-div");
+ div.text(statusStringMap[node.status]);
+ $(div).attr("class", "status " + node.status);
var startdate = new Date(node.startTime);
$("#" + node.id + "-start").text(getDateFormat(startdate));
@@ -680,6 +693,11 @@ azkaban.ExecutionListView = Backbone.View.extend({
$(a).text(node.id);
$(tdName).append(a);
+ var status = document.createElement("div");
+ $(status).addClass("status");
+ $(status).attr("id", node.id + "-status-div");
+ tdStatus.appendChild(status);
+
executingBody.append(tr);
}
});
src/web/js/azkaban.flow.view.js 20(+18 -2)
diff --git a/src/web/js/azkaban.flow.view.js b/src/web/js/azkaban.flow.view.js
index c952eda..868d8d3 100644
--- a/src/web/js/azkaban.flow.view.js
+++ b/src/web/js/azkaban.flow.view.js
@@ -1,5 +1,17 @@
$.namespace('azkaban');
+var statusStringMap = {
+ "FAILED": "Failed",
+ "SUCCEEDED": "Success",
+ "FAILED_FINISHING": "Running w/Failure",
+ "RUNNING": "Running",
+ "WAITING": "Waiting",
+ "KILLED": "Killed",
+ "DISABLED": "Disabled",
+ "READY": "Ready",
+ "UNKNOWN": "Unknown"
+};
+
var handleJobMenuClick = function(action, el, pos) {
var jobid = el[0].jobid;
var requestURL = contextURL + "/manager?project=" + projectName + "&flow=" + flowName + "&job=" + jobid;
@@ -614,7 +626,7 @@ azkaban.ExecutionsView = Backbone.View.extend({
initialize: function(settings) {
this.model.bind('change:view', this.handleChangeView, this);
this.model.bind('render', this.render, this);
- this.model.set({page: 1, pageSize: 20});
+ this.model.set({page: 1, pageSize: 16});
this.model.bind('change:page', this.handlePageChange, this);
},
render: function(evt) {
@@ -667,7 +679,11 @@ azkaban.ExecutionsView = Backbone.View.extend({
row.appendChild(tdElapsed);
var tdStatus = document.createElement("td");
- $(tdStatus).text(executions[i].status);
+ var status = document.createElement("div");
+ $(status).addClass("status");
+ $(status).addClass(executions[i].status);
+ $(status).text(statusStringMap[executions[i].status]);
+ tdStatus.appendChild(status);
row.appendChild(tdStatus);
var tdAction = document.createElement("td");