azkaban-memoizeit
Changes
src/web/css/azkaban.css 27(+27 -0)
src/web/js/azkaban.date.utils.js 9(+9 -0)
src/web/js/azkaban.exflow.view.js 128(+89 -39)
src/web/js/azkaban.flow.view.js 3(+2 -1)
src/web/js/azkaban.joblog.view.js 2(+1 -1)
Details
diff --git a/src/java/azkaban/executor/ExecutableNode.java b/src/java/azkaban/executor/ExecutableNode.java
index d15a963..a0a52d5 100644
--- a/src/java/azkaban/executor/ExecutableNode.java
+++ b/src/java/azkaban/executor/ExecutableNode.java
@@ -74,10 +74,10 @@ public class ExecutableNode {
synchronized (this) {
if (pastAttempts == null) {
pastAttempts = new ArrayList<Attempt>();
- pastAttempts.add(pastAttempt);
}
+
+ pastAttempts.add(pastAttempt);
}
-
startTime = -1;
endTime = -1;
updateTime = System.currentTimeMillis();
diff --git a/src/java/azkaban/webapp/servlet/ExecutorServlet.java b/src/java/azkaban/webapp/servlet/ExecutorServlet.java
index 2536fbd..bbc2c38 100644
--- a/src/java/azkaban/webapp/servlet/ExecutorServlet.java
+++ b/src/java/azkaban/webapp/servlet/ExecutorServlet.java
@@ -86,8 +86,10 @@ public class ExecutorServlet extends LoginAbstractAzkabanServlet {
User user = session.getUser();
int execId = getIntParam(req, "execid");
String jobId = getParam(req, "job");
+ int attempt = getIntParam(req, "attempt", 0);
page.add("execid", execId);
page.add("jobid", jobId);
+ page.add("attempt", attempt);
ExecutableFlow flow = null;
try {
diff --git a/src/java/azkaban/webapp/servlet/velocity/joblogpage.vm b/src/java/azkaban/webapp/servlet/velocity/joblogpage.vm
index d3e577a..2f9ea81 100644
--- a/src/java/azkaban/webapp/servlet/velocity/joblogpage.vm
+++ b/src/java/azkaban/webapp/servlet/velocity/joblogpage.vm
@@ -37,6 +37,7 @@
var flowName = "${flowid}";
var execId = "${execid}";
var jobId = "${jobid}";
+ var attempt = ${attempt};
</script>
</head>
<body>
src/web/css/azkaban.css 27(+27 -0)
diff --git a/src/web/css/azkaban.css b/src/web/css/azkaban.css
index 0828ea3..59e1820 100644
--- a/src/web/css/azkaban.css
+++ b/src/web/css/azkaban.css
@@ -1995,6 +1995,11 @@ tr:hover td {
background-position: 16px 0px;
}
+.list ul li.QUEUED .icon {
+ opacity: 0.5;
+ background-position: 32px 0px;
+}
+
.list ul li.RUNNING .icon {
background-position: 32px 0px;
}
@@ -2177,6 +2182,11 @@ svg .RUNNING circle {
fill: #009FC9;
}
+svg .QUEUED circle {
+ opacity: 0.5;
+ fill: #009FC9;
+}
+
svg .FAILED circle {
fill: #CC0000;
}
@@ -2503,6 +2513,14 @@ tr:hover .outerProgress {
background-color: #CCC;
}
+.progressBox.attempt:hover {
+ opacity: 1;
+}
+
+.progressBox.attempt {
+ opacity: 0.70;
+}
+
.progressBox.SUCCEEDED {
background-color: #4e911e;
background: -moz-linear-gradient(top, #5bb41c 0, #598d1e 100%);
@@ -2527,6 +2545,15 @@ tr:hover .outerProgress {
background: linear-gradient(top, #009FC9 0, #007b9b 100%);
}
+.progressBox.QUEUED {
+ opacity: 0.5;
+ background-color: #009FC9;
+ background: -moz-linear-gradient(top, #009FC9 0, #007b9b 100%);
+ background: -o-linear-gradient(top, #009FC9 0, #007b9b 100%);
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0,#009FC9), color-stop(100%,#007b9b));
+ background: linear-gradient(top, #009FC9 0, #007b9b 100%);
+}
+
h3.subhead {
margin: 15px 20px 8px 20px;
font-size: 14pt;
src/web/js/azkaban.date.utils.js 9(+9 -0)
diff --git a/src/web/js/azkaban.date.utils.js b/src/web/js/azkaban.date.utils.js
index e436648..78dbd90 100644
--- a/src/web/js/azkaban.date.utils.js
+++ b/src/web/js/azkaban.date.utils.js
@@ -55,6 +55,15 @@ var getDateFormat = function(date) {
return datestring;
}
+var getHourMinSec = function(date) {
+ var hours = getTwoDigitStr(date.getHours());
+ var minutes = getTwoDigitStr(date.getMinutes());
+ var second = getTwoDigitStr(date.getSeconds());
+
+ var timestring = hours + ":" + minutes + " " + second + "s";
+ return timestring;
+}
+
var getTwoDigitStr = function(value) {
if (value < 10) {
return "0" + value;
src/web/js/azkaban.exflow.view.js 128(+89 -39)
diff --git a/src/web/js/azkaban.exflow.view.js b/src/web/js/azkaban.exflow.view.js
index 59dd6cb..b4d9764 100644
--- a/src/web/js/azkaban.exflow.view.js
+++ b/src/web/js/azkaban.exflow.view.js
@@ -271,6 +271,7 @@ var mainSvgGraphView;
var executionListView;
azkaban.ExecutionListView = Backbone.View.extend({
events: {
+// "click .progressBox" : "handleProgressBoxClick"
},
initialize: function(settings) {
this.model.bind('change:graph', this.renderJobs, this);
@@ -282,6 +283,24 @@ azkaban.ExecutionListView = Backbone.View.extend({
this.updateJobRow(data.nodes);
this.updateProgressBar(data);
},
+/* handleProgressBoxClick: function(evt) {
+ var target = evt.currentTarget;
+ var job = target.job;
+ var attempt = target.attempt;
+
+ var data = this.model.get("data");
+ var node = data.nodes[job];
+
+ var jobId = event.currentTarget.jobid;
+ var requestURL = contextURL + "/manager?project=" + projectName + "&execid=" + execId + "&job=" + job + "&attempt=" + attempt;
+
+ var menu = [
+ {title: "Open Job...", callback: function() {window.location.href=requestURL;}},
+ {title: "Open Job in New Window...", callback: function() {window.open(requestURL);}}
+ ];
+
+ contextMenuView.show(evt, menu);
+ },*/
updateJobs: function(evt) {
var data = this.model.get("update");
var lastTime = data.endTime == -1 ? (new Date()).getTime() : data.endTime;
@@ -320,12 +339,34 @@ azkaban.ExecutionListView = Backbone.View.extend({
}
var progressBar = $("#" + nodeId + "-progressbar");
- for (var j = 0; j < statusList.length; ++j) {
- var status = statusList[j];
- progressBar.removeClass(status);
+ if (!progressBar.hasClass(node.status)) {
+ for (var j = 0; j < statusList.length; ++j) {
+ var status = statusList[j];
+ progressBar.removeClass(status);
+ }
+ progressBar.addClass(node.status);
}
- progressBar.addClass(node.status);
-
+
+ // Create past attempts
+ if (node.pastAttempts) {
+ for (var a = 0; a < node.pastAttempts.length; ++a) {
+ var attemptBarId = nodeId + "-progressbar-" + a;
+ var attempt = node.pastAttempts[a];
+ if ($("#" + attemptBarId).length == 0) {
+ var attemptBox = document.createElement("div");
+ $(attemptBox).attr("id", attemptBarId);
+ $(attemptBox).addClass("progressBox");
+ $(attemptBox).addClass("attempt");
+ $(attemptBox).addClass(attempt.status);
+ $(attemptBox).css("float","left");
+ $(attemptBox).bind("contextmenu", attemptRightClick);
+ $(progressBar).before(attemptBox);
+ attemptBox.job = nodeId;
+ attemptBox.attempt = a;
+ }
+ }
+ }
+
if (node.endTime == -1) {
// $("#" + node.id + "-elapse").text("0 sec");
$("#" + nodeId + "-elapse").text(getDuration(node.startTime, (new Date()).getTime()));
@@ -353,60 +394,51 @@ azkaban.ExecutionListView = Backbone.View.extend({
}
var nodes = data.nodes;
-
+ var diff = flowLastTime - flowStartTime;
+ var factor = outerWidth/diff;
for (var i = 0; i < nodes.length; ++i) {
var node = nodes[i];
+ var nodeId = node.id.replace(".", "\\\\.");
// calculate the progress
- var diff = flowLastTime - flowStartTime;
-
- var factor = outerWidth/diff;
+ var elem = $("#" + node.id + "-progressbar");
var offsetLeft = 0;
var minOffset = 0;
+ elem.attempt = 0;
+
// Add all the attempts
- if (node.attempt > 0) {
- var logURL = contextURL + "/executor?execid=" + execId + "&job=" + node.id + "&attempt=" + node.attempt;
+ if (node.pastAttempts) {
+ var logURL = contextURL + "/executor?execid=" + execId + "&job=" + node.id + "&attempt=" + node.pastAttempts.length;
var aId = node.id + "-log-link";
$("#" + aId).attr("href", logURL);
+ elem.attempt = node.pastAttempts.length;
- /*
- minOffset = 1;
- var pastAttempts = node.pastAttempts;
- for (var j = 0; j < pastAttempts.length; ++j) {
- var past = pastAttempts[j];
- var id = node.id + "-past-progress-" + j;
-
- if ($("#" + id).length == 0) {
- var attemptBox = document.createElement("div");
- $(attemptBox).attr("id", id);
- $(attemptBox).addClass("progressBox");
- $("#" + node.id + "-outerprogressbar").append(attemptBox);
- $(attemptBox).css("float","left");
- }
-
- var attemptBox = $("#" + id);
+ // Calculate the node attempt bars
+ for(var p = 0; p < node.pastAttempts.length; ++p) {
+ var pastAttempt = node.pastAttempts[p];
+ var pastAttemptBox = $("#" + nodeId + "-progressbar-" + p);
- var absoluteLeft = Math.max((past.startTime-flowStartTime)*factor, 3);
- var left = absoluteLeft - offsetLeft;
- var width = Math.max((past.endTime - past.startTime)*factor, 1);
+ var left = (pastAttempt.startTime - flowStartTime)*factor;
+ var width = Math.max((pastAttempt.endTime - pastAttempt.startTime)*factor, 3);
- $(attemptBox).css("margin-left", left)
- $(attemptBox).css("width", width);
- $(attemptBox).addClass(past.status);
- offsetLeft += left + width;
+ var margin = left - offsetLeft;
+ $(pastAttemptBox).css("margin-left", left - offsetLeft);
+ $(pastAttemptBox).css("width", width);
+
+ $(pastAttemptBox).attr("title", "attempt:" + p + " start:" + getHourMinSec(new Date(pastAttempt.startTime)) + " end:" + getHourMinSec(new Date(pastAttempt.endTime)));
+ offsetLeft += width + margin;
}
- */
}
-
- var absoluteLeft = Math.max((node.startTime-flowStartTime)*factor, minOffset);
- var left = absoluteLeft - offsetLeft;
+
var nodeLastTime = node.endTime == -1 ? (new Date()).getTime() : node.endTime;
+ var left = Math.max((node.startTime-flowStartTime)*factor, minOffset);
+ var margin = left - offsetLeft;
var width = Math.max((nodeLastTime - node.startTime)*factor, 3);
width = Math.min(width, outerWidth);
- var elem = $("#" + node.id + "-progressbar");
elem.css("margin-left", left)
elem.css("width", width);
+ elem.attr("title", "attempt:" + elem.attempt + " start:" + getHourMinSec(new Date(node.startTime)) + " end:" + getHourMinSec(new Date(node.endTime)));
}
},
addNodeRow: function(node) {
@@ -439,6 +471,7 @@ azkaban.ExecutionListView = Backbone.View.extend({
$(outerProgressBar).addClass("outerProgress");
var progressBox = document.createElement("div");
+ progressBox.job = node.id;
$(progressBox).attr("id", node.id + "-progressbar");
$(progressBox).addClass("progressBox");
$(outerProgressBar).append(progressBox);
@@ -635,6 +668,23 @@ var exGraphClickCallback = function(event) {
contextMenuView.show(event, menu);
}
+var attemptRightClick = function(event) {
+ var target = event.currentTarget;
+ var job = target.job;
+ var attempt = target.attempt;
+
+ var jobId = event.currentTarget.jobid;
+ var requestURL = contextURL + "/executor?project=" + projectName + "&execid=" + execId + "&job=" + job + "&attempt=" + attempt;
+
+ var menu = [
+ {title: "Open Attempt Log...", callback: function() {window.location.href=requestURL;}},
+ {title: "Open Attempt Log in New Window...", callback: function() {window.open(requestURL);}}
+ ];
+
+ contextMenuView.show(event, menu);
+ return false;
+}
+
$(function() {
var selected;
src/web/js/azkaban.flow.view.js 3(+2 -1)
diff --git a/src/web/js/azkaban.flow.view.js b/src/web/js/azkaban.flow.view.js
index b23cd3d..9f3536b 100644
--- a/src/web/js/azkaban.flow.view.js
+++ b/src/web/js/azkaban.flow.view.js
@@ -9,7 +9,8 @@ var statusStringMap = {
"KILLED": "Killed",
"DISABLED": "Disabled",
"READY": "Ready",
- "UNKNOWN": "Unknown"
+ "UNKNOWN": "Unknown",
+ "QUEUED": "Queued"
};
var handleJobMenuClick = function(action, el, pos) {
src/web/js/azkaban.joblog.view.js 2(+1 -1)
diff --git a/src/web/js/azkaban.joblog.view.js b/src/web/js/azkaban.joblog.view.js
index 97c5bdf..76f5602 100644
--- a/src/web/js/azkaban.joblog.view.js
+++ b/src/web/js/azkaban.joblog.view.js
@@ -27,7 +27,7 @@ azkaban.JobLogView = Backbone.View.extend({
type: "get",
async: false,
dataType: "json",
- data: {"execid": execId, "jobId": jobId, "ajax":"fetchExecJobLogs", "offset": offset, "length": 50000},
+ data: {"execid": execId, "jobId": jobId, "ajax":"fetchExecJobLogs", "offset": offset, "length": 50000, "attempt": attempt},
error: function(data) {
console.log(data);
finished = true;