reqless 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +8 -0
- data/README.md +648 -0
- data/Rakefile +117 -0
- data/bin/docker-build-and-test +22 -0
- data/exe/reqless-web +11 -0
- data/lib/reqless/config.rb +31 -0
- data/lib/reqless/failure_formatter.rb +43 -0
- data/lib/reqless/job.rb +496 -0
- data/lib/reqless/job_reservers/ordered.rb +29 -0
- data/lib/reqless/job_reservers/round_robin.rb +46 -0
- data/lib/reqless/job_reservers/shuffled_round_robin.rb +21 -0
- data/lib/reqless/lua/reqless-lib.lua +2965 -0
- data/lib/reqless/lua/reqless.lua +2545 -0
- data/lib/reqless/lua_script.rb +90 -0
- data/lib/reqless/middleware/requeue_exceptions.rb +94 -0
- data/lib/reqless/middleware/retry_exceptions.rb +72 -0
- data/lib/reqless/middleware/sentry.rb +66 -0
- data/lib/reqless/middleware/timeout.rb +63 -0
- data/lib/reqless/queue.rb +189 -0
- data/lib/reqless/queue_priority_pattern.rb +16 -0
- data/lib/reqless/server/static/css/bootstrap-responsive.css +686 -0
- data/lib/reqless/server/static/css/bootstrap-responsive.min.css +12 -0
- data/lib/reqless/server/static/css/bootstrap.css +3991 -0
- data/lib/reqless/server/static/css/bootstrap.min.css +689 -0
- data/lib/reqless/server/static/css/codemirror.css +112 -0
- data/lib/reqless/server/static/css/docs.css +839 -0
- data/lib/reqless/server/static/css/jquery.noty.css +105 -0
- data/lib/reqless/server/static/css/noty_theme_twitter.css +137 -0
- data/lib/reqless/server/static/css/style.css +200 -0
- data/lib/reqless/server/static/favicon.ico +0 -0
- data/lib/reqless/server/static/img/glyphicons-halflings-white.png +0 -0
- data/lib/reqless/server/static/img/glyphicons-halflings.png +0 -0
- data/lib/reqless/server/static/js/bootstrap-alert.js +94 -0
- data/lib/reqless/server/static/js/bootstrap-scrollspy.js +125 -0
- data/lib/reqless/server/static/js/bootstrap-tab.js +130 -0
- data/lib/reqless/server/static/js/bootstrap-tooltip.js +270 -0
- data/lib/reqless/server/static/js/bootstrap-typeahead.js +285 -0
- data/lib/reqless/server/static/js/bootstrap.js +1726 -0
- data/lib/reqless/server/static/js/bootstrap.min.js +6 -0
- data/lib/reqless/server/static/js/codemirror.js +2972 -0
- data/lib/reqless/server/static/js/jquery.noty.js +220 -0
- data/lib/reqless/server/static/js/mode/javascript.js +360 -0
- data/lib/reqless/server/static/js/theme/cobalt.css +18 -0
- data/lib/reqless/server/static/js/theme/eclipse.css +25 -0
- data/lib/reqless/server/static/js/theme/elegant.css +10 -0
- data/lib/reqless/server/static/js/theme/lesser-dark.css +45 -0
- data/lib/reqless/server/static/js/theme/monokai.css +28 -0
- data/lib/reqless/server/static/js/theme/neat.css +9 -0
- data/lib/reqless/server/static/js/theme/night.css +21 -0
- data/lib/reqless/server/static/js/theme/rubyblue.css +21 -0
- data/lib/reqless/server/static/js/theme/xq-dark.css +46 -0
- data/lib/reqless/server/views/_job.erb +259 -0
- data/lib/reqless/server/views/_job_list.erb +8 -0
- data/lib/reqless/server/views/_pagination.erb +7 -0
- data/lib/reqless/server/views/about.erb +130 -0
- data/lib/reqless/server/views/completed.erb +11 -0
- data/lib/reqless/server/views/config.erb +14 -0
- data/lib/reqless/server/views/failed.erb +48 -0
- data/lib/reqless/server/views/failed_type.erb +18 -0
- data/lib/reqless/server/views/job.erb +17 -0
- data/lib/reqless/server/views/layout.erb +451 -0
- data/lib/reqless/server/views/overview.erb +137 -0
- data/lib/reqless/server/views/queue.erb +125 -0
- data/lib/reqless/server/views/queues.erb +45 -0
- data/lib/reqless/server/views/tag.erb +6 -0
- data/lib/reqless/server/views/throttles.erb +38 -0
- data/lib/reqless/server/views/track.erb +75 -0
- data/lib/reqless/server/views/worker.erb +34 -0
- data/lib/reqless/server/views/workers.erb +14 -0
- data/lib/reqless/server.rb +549 -0
- data/lib/reqless/subscriber.rb +74 -0
- data/lib/reqless/test_helpers/worker_helpers.rb +55 -0
- data/lib/reqless/throttle.rb +57 -0
- data/lib/reqless/version.rb +5 -0
- data/lib/reqless/worker/base.rb +237 -0
- data/lib/reqless/worker/forking.rb +215 -0
- data/lib/reqless/worker/serial.rb +41 -0
- data/lib/reqless/worker.rb +5 -0
- data/lib/reqless.rb +309 -0
- metadata +399 -0
@@ -0,0 +1,17 @@
|
|
1
|
+
<script>
|
2
|
+
var fade = function(jid, type) {
|
3
|
+
if (type == 'cancel') {
|
4
|
+
$('#job-' + jid).slideUp();
|
5
|
+
}
|
6
|
+
}
|
7
|
+
</script>
|
8
|
+
|
9
|
+
<% if job.nil? %>
|
10
|
+
<div class="row">
|
11
|
+
<div class="span12">
|
12
|
+
<h2><%= jid %> doesn't exist, was canceled, or expired</h2>
|
13
|
+
</div>
|
14
|
+
</div>
|
15
|
+
<% else %>
|
16
|
+
<%= erb :_job, :layout => false, :locals => { :job => job, :queues => queues } %>
|
17
|
+
<% end %>
|
@@ -0,0 +1,451 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<title><%= application_name %><%= (title.length == 0) ? '' : (' | ' + title) %></title>
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
7
|
+
<meta name="description" content="">
|
8
|
+
<meta name="author" content="Dan Lecocq">
|
9
|
+
|
10
|
+
<link href="<%= u '/css/bootstrap.css' %>" rel="stylesheet">
|
11
|
+
<link href="<%= u '/css/bootstrap-responsive.css' %>" rel="stylesheet">
|
12
|
+
<link href="<%= u '/css/docs.css' %>" rel="stylesheet">
|
13
|
+
<link href="<%= u '/css/jquery.noty.css' %>" rel="stylesheet">
|
14
|
+
<link href="<%= u '/css/noty_theme_twitter.css' %>" rel="stylesheet">
|
15
|
+
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
|
16
|
+
|
17
|
+
<style type="text/css">
|
18
|
+
body {
|
19
|
+
padding-top: 60px;
|
20
|
+
}
|
21
|
+
|
22
|
+
.btn-group span {
|
23
|
+
/* This is ugly. Anyone want to change it? */
|
24
|
+
border-color: #e6e6e6 #e6e6e6 #bfbfbf;
|
25
|
+
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
|
26
|
+
border: 1px solid #cccccc;
|
27
|
+
border-bottom-color: #b3b3b3;
|
28
|
+
background-color: #f5f5f5;
|
29
|
+
font-size: 13px;
|
30
|
+
line-height: 18px;
|
31
|
+
padding: 4px 10px 4px;
|
32
|
+
}
|
33
|
+
|
34
|
+
.btn-group input, .btn-group span {
|
35
|
+
position: relative;
|
36
|
+
float: left;
|
37
|
+
margin-left: -1px;
|
38
|
+
-webkit-border-radius: 0;
|
39
|
+
-moz-border-radius: 0;
|
40
|
+
border-radius: 0;
|
41
|
+
margin-bottom: 0px;
|
42
|
+
}
|
43
|
+
|
44
|
+
.btn-group input:first-child, .btn-group span:first-child {
|
45
|
+
margin-left: 0;
|
46
|
+
-webkit-border-top-left-radius: 4px;
|
47
|
+
-moz-border-radius-topleft: 4px;
|
48
|
+
border-top-left-radius: 4px;
|
49
|
+
-webkit-border-bottom-left-radius: 4px;
|
50
|
+
-moz-border-radius-bottomleft: 4px;
|
51
|
+
border-bottom-left-radius: 4px;
|
52
|
+
}
|
53
|
+
|
54
|
+
.large-text {
|
55
|
+
font-size:18px;
|
56
|
+
}
|
57
|
+
|
58
|
+
.queue-column {
|
59
|
+
min-width:300px;
|
60
|
+
}
|
61
|
+
|
62
|
+
</style>
|
63
|
+
|
64
|
+
<script type="text/javascript">
|
65
|
+
/* This is a helper method to display an alert at the top of the page,
|
66
|
+
* in a vein similar to that of Ruby's flash */
|
67
|
+
var flash = function(message, t, duration) {
|
68
|
+
var noty_id = noty({
|
69
|
+
text : '<strong>' + message + '</strong>',
|
70
|
+
layout : 'top',
|
71
|
+
type : t || 'error',
|
72
|
+
theme : 'noty_theme_twitter',
|
73
|
+
timeout: duration || 1500});
|
74
|
+
}
|
75
|
+
|
76
|
+
/* This just sets a few options that we use */
|
77
|
+
var _ajax = function(obj) {
|
78
|
+
$.ajax({
|
79
|
+
url: obj.url,
|
80
|
+
type: 'POST',
|
81
|
+
dataType: 'json',
|
82
|
+
data: JSON.stringify(obj.data),
|
83
|
+
processData: false,
|
84
|
+
success: obj.success || function() {},
|
85
|
+
error: obj.error || function() {}
|
86
|
+
});
|
87
|
+
}
|
88
|
+
|
89
|
+
/* This is a helper method to move a job into a queue, and then it will
|
90
|
+
* flash a message to that effect on the page */
|
91
|
+
var move = function(jid, queue, cb) {
|
92
|
+
_ajax({
|
93
|
+
url: '<%= u "/move" %>',
|
94
|
+
data: {id:jid, queue:queue},
|
95
|
+
success: function() { flash('Moved ' + jid + ' to ' + queue, 'success', 1500); cb(jid, queue); },
|
96
|
+
error: function() { flash('Failed to move ' + jid + ' to ' + queue); }
|
97
|
+
});
|
98
|
+
}
|
99
|
+
|
100
|
+
/* Helper function for retrying a job */
|
101
|
+
var retry = function(jid, cb) {
|
102
|
+
_ajax({
|
103
|
+
url: '<%= u "/retry" %>',
|
104
|
+
data: {id:jid},
|
105
|
+
success: function() { flash('Retrying ' + jid, 'success', 1500); if (cb) { cb(jid, 'retry'); } },
|
106
|
+
error: function() { flash('Failed to retry ' + jid); }
|
107
|
+
});
|
108
|
+
}
|
109
|
+
|
110
|
+
/* This is a helper method to cancel a job */
|
111
|
+
var cancel = function(jid, cb) {
|
112
|
+
_ajax({
|
113
|
+
url: '<%= u "/cancel" %>',
|
114
|
+
data: [jid],
|
115
|
+
success: function() { flash('Canceled ' + jid, null, 1500); if (cb) { cb(jid, 'cancel'); } },
|
116
|
+
error: function() { flash('Failed to cancel ' + jid); }
|
117
|
+
});
|
118
|
+
}
|
119
|
+
|
120
|
+
/* This is a helper method to untrack a job */
|
121
|
+
var untrack = function(jid, cb) {
|
122
|
+
_ajax({
|
123
|
+
url: '<%= u "/untrack" %>',
|
124
|
+
data: [jid],
|
125
|
+
success: function() { flash('Stopped tracking ' + jid, 'success', 1500); if (cb) { cb(jid, 'untrack'); } },
|
126
|
+
error: function() { flash('Failed to track ' + jid); }
|
127
|
+
});
|
128
|
+
}
|
129
|
+
|
130
|
+
/* This is a helper to start tracking a job, with tags */
|
131
|
+
var track = function(jid, tags, cb) {
|
132
|
+
_ajax({
|
133
|
+
url: '<%= u "/track" %>',
|
134
|
+
data: {id:jid, tags:(tags || [])},
|
135
|
+
success: function() { flash('Now tracking ' + jid, 'success', 1500); if (cb) { cb(jid, 'track'); } },
|
136
|
+
error: function() { flash('Failed to track ' + jid); }
|
137
|
+
});
|
138
|
+
}
|
139
|
+
|
140
|
+
/* This is a helper to retry all jobs of a certain failure type */
|
141
|
+
var retryall = function(type, cb) {
|
142
|
+
_ajax({
|
143
|
+
url: '<%= u "/retryall" %>',
|
144
|
+
data: {type: type},
|
145
|
+
success: function(response) {
|
146
|
+
flash('Retrying failures of type ' + type, 'success', 1500);
|
147
|
+
if (cb) {
|
148
|
+
for (var i in response) {
|
149
|
+
cb(response[i].id);
|
150
|
+
}
|
151
|
+
}
|
152
|
+
},
|
153
|
+
error: function() { flash('Failed to retry failures of type ' + type); }
|
154
|
+
});
|
155
|
+
}
|
156
|
+
|
157
|
+
/* This is a helper to cancel all jobs of a certain failure type */
|
158
|
+
var cancelall = function(type, cb) {
|
159
|
+
_ajax({
|
160
|
+
url: '<%= u "/cancelall" %>',
|
161
|
+
data: {type: type},
|
162
|
+
success: function(response) {
|
163
|
+
flash('Canceling failures of type ' + type, 'success', 1500);
|
164
|
+
if (cb) {
|
165
|
+
for (var i in response) {
|
166
|
+
cb(response[i].id);
|
167
|
+
}
|
168
|
+
}
|
169
|
+
},
|
170
|
+
error: function() { flash('Failed to cancel failures of type ' + type); }
|
171
|
+
});
|
172
|
+
}
|
173
|
+
|
174
|
+
/* This is a helper to remove job dependencies */
|
175
|
+
var undepend = function(jid, dependency, cb) {
|
176
|
+
_ajax({
|
177
|
+
url: '<%= u "/undepend" %>',
|
178
|
+
data: {id:jid, dependency:dependency},
|
179
|
+
success: function() { flash(jid + ' no longer depends on ' + dependency, 'success', 1500); if (cb) { cb(jid, 'undepend'); } },
|
180
|
+
error: function() { flash('Failed to remove ' + jid + '\'s dependency on ' + dependency); }
|
181
|
+
});
|
182
|
+
}
|
183
|
+
|
184
|
+
/* Helper function to fade out a particular element id */
|
185
|
+
var fade = function(jid, type) {
|
186
|
+
if (type != 'untrack' && type != 'track') {
|
187
|
+
$('#job-' + jid).slideUp();
|
188
|
+
}
|
189
|
+
}
|
190
|
+
|
191
|
+
/* Helper function to make a button ask for confirmation
|
192
|
+
* after being pressed once. Accepts the confirmation text,
|
193
|
+
* and the function to execute after it has been run */
|
194
|
+
var confirmation = function(button, html, action, delay) {
|
195
|
+
var obj = $(button);
|
196
|
+
var original = obj.html();
|
197
|
+
var timeout = setTimeout(function() {
|
198
|
+
obj.html(original).unbind('click').click(function() {
|
199
|
+
confirmation(button, html, action, delay);
|
200
|
+
});
|
201
|
+
}, delay || 3000);
|
202
|
+
obj.removeAttr('onclick').html(html).unbind('click').click(function() {
|
203
|
+
clearTimeout(timeout);
|
204
|
+
obj.html(original).unbind('click').click(function() {
|
205
|
+
confirmation(button, html, action, delay);
|
206
|
+
});
|
207
|
+
action();
|
208
|
+
});
|
209
|
+
}
|
210
|
+
|
211
|
+
/* Helper function for adding a tag to a job */
|
212
|
+
var tag = function(jid, tag) {
|
213
|
+
var data = {};
|
214
|
+
data[jid] = [tag];
|
215
|
+
// The button group of the 'add tag' bit
|
216
|
+
var group =
|
217
|
+
_ajax({
|
218
|
+
url: '<%= u "/tag" %>',
|
219
|
+
data: data,
|
220
|
+
success : function() {
|
221
|
+
var div = $('<div>').attr('class', 'btn-group').attr('style', 'float:left');
|
222
|
+
var span = $('<span>').attr('class', 'tag').text(tag);
|
223
|
+
var btn = $('<button>').attr('class', 'btn').click(function() {
|
224
|
+
untag(jid, tag);
|
225
|
+
});
|
226
|
+
btn.append($('<i>').attr('class', 'icon-remove'));
|
227
|
+
div.append(span).append(btn);
|
228
|
+
$('#job-' + jid).find('.add-tag').val(null).parent().before(div);
|
229
|
+
}, error: function() {
|
230
|
+
flash('Failed to tag ' + jid + ' with ' + tag);
|
231
|
+
}
|
232
|
+
});
|
233
|
+
}
|
234
|
+
|
235
|
+
/* Helper function for untagging a job */
|
236
|
+
var untag = function(jid, tag) {
|
237
|
+
var data = {};
|
238
|
+
data[jid] = [tag];
|
239
|
+
// The button group of the 'add tag' bit
|
240
|
+
var group =
|
241
|
+
_ajax({
|
242
|
+
url: '<%= u "/untag" %>',
|
243
|
+
data: data,
|
244
|
+
success : function() {
|
245
|
+
$("#job-" + jid).find('.tag').filter(function() {
|
246
|
+
return $(this).text() === tag;
|
247
|
+
}).parent().remove();
|
248
|
+
}, error: function() {
|
249
|
+
flash('Failed to untag ' + jid + ' with ' + tag);
|
250
|
+
}
|
251
|
+
});
|
252
|
+
}
|
253
|
+
|
254
|
+
/* Helper function for changing a job's priority */
|
255
|
+
var priority = function(jid, priority) {
|
256
|
+
var p = parseInt(priority);
|
257
|
+
var input = $('#job-' + jid).find('.priority');
|
258
|
+
if (p != null) {
|
259
|
+
input.attr('disabled', true);
|
260
|
+
var data = {};
|
261
|
+
data[jid] = priority;
|
262
|
+
_ajax({
|
263
|
+
url: '<%= u "/priority" %>',
|
264
|
+
data: data,
|
265
|
+
success : function(data) {
|
266
|
+
if (data[jid] != 'failed' && data[jid] != null) {
|
267
|
+
input.attr('disabled', false).attr('placeholder', 'Pri ' + priority).val(null).blur();
|
268
|
+
} else {
|
269
|
+
flash('Couldn\'t reprioritize ' + jid);
|
270
|
+
input.val(null).blur();
|
271
|
+
}
|
272
|
+
}, error: function() {
|
273
|
+
flash('Couldn\'t reprioritize ' + jid);
|
274
|
+
input.val(null).blur();
|
275
|
+
}
|
276
|
+
});
|
277
|
+
} else {
|
278
|
+
// Reset it to its original value, and print an error
|
279
|
+
flash('Cannot derive integer from "' + priority + '"');
|
280
|
+
input.val(null).blur();
|
281
|
+
}
|
282
|
+
}
|
283
|
+
|
284
|
+
var pause = function(queue) {
|
285
|
+
_ajax({
|
286
|
+
url: '<%= u "/pause" %>',
|
287
|
+
data: {
|
288
|
+
'queue': queue
|
289
|
+
}, success: function(data) {
|
290
|
+
var button = $('#' + queue + '-pause');
|
291
|
+
button.attr('title', 'Unpause').attr(
|
292
|
+
'data-original-title', 'Unpause');
|
293
|
+
button.addClass('btn-success').removeClass('btn-warning');
|
294
|
+
button.children().addClass('icon-play').removeClass('icon-pause');
|
295
|
+
button.attr('onclick', 'unpause("' + queue + '")');
|
296
|
+
}, error: function() {
|
297
|
+
flash('Couldn\'t pause queue ' + queue);
|
298
|
+
}
|
299
|
+
})
|
300
|
+
}
|
301
|
+
|
302
|
+
var unpause = function(queue) {
|
303
|
+
_ajax({
|
304
|
+
url: '<%= u "/unpause" %>',
|
305
|
+
data: {
|
306
|
+
'queue': queue
|
307
|
+
}, success: function(data) {
|
308
|
+
var button = $('#' + queue + '-pause');
|
309
|
+
button.attr('title', 'Pause').attr(
|
310
|
+
'data-original-title', 'Pause');
|
311
|
+
button.addClass('btn-warning').removeClass('btn-success');
|
312
|
+
button.children().addClass('icon-pause').removeClass('icon-play');
|
313
|
+
button.attr('onclick', 'pause("' + queue + '")');
|
314
|
+
}, error: function() {
|
315
|
+
flash('Couldn\'t unpause queue ' + queue);
|
316
|
+
}
|
317
|
+
})
|
318
|
+
}
|
319
|
+
|
320
|
+
var timeout = function(jid) {
|
321
|
+
_ajax({
|
322
|
+
url: '<%= u "/timeout" %>',
|
323
|
+
data: {
|
324
|
+
'jid': jid
|
325
|
+
}, success: function(data) {
|
326
|
+
flash('Job timed out', 'success');
|
327
|
+
}, error: function(data) {
|
328
|
+
flash('Failed to time out job: ' + data);
|
329
|
+
console.log(data);
|
330
|
+
}
|
331
|
+
})
|
332
|
+
}
|
333
|
+
|
334
|
+
var expire_throttle = function(throttle_id, expiration) {
|
335
|
+
var data = { 'id': throttle_id, 'expiration': expiration };
|
336
|
+
|
337
|
+
$.ajax({
|
338
|
+
url: '<%= u "/throttle" %>',
|
339
|
+
type: 'PUT',
|
340
|
+
dataType: 'json',
|
341
|
+
processData: false,
|
342
|
+
data: JSON.stringify(data),
|
343
|
+
success: function(data) {
|
344
|
+
flash('Set expiration for throttle ' + throttle_id, 'success');
|
345
|
+
},
|
346
|
+
error: function(data) {
|
347
|
+
flash('Couldn\'t update expiration for throttle ' + throttle_id);
|
348
|
+
}
|
349
|
+
})
|
350
|
+
}
|
351
|
+
|
352
|
+
var delete_throttle = function(throttle_id) {
|
353
|
+
var data = { 'id': throttle_id };
|
354
|
+
|
355
|
+
$.ajax({
|
356
|
+
url: '<%= u "/throttle" %>',
|
357
|
+
type: 'DELETE',
|
358
|
+
dataType: 'json',
|
359
|
+
processData: false,
|
360
|
+
data: JSON.stringify(data),
|
361
|
+
success: function(data) {
|
362
|
+
flash('Deleted throttle for ' + throttle_id, 'success');
|
363
|
+
$('.' + throttle_id.replace(/:/g, '-') + '-maximum').val(data['maximum']);
|
364
|
+
},
|
365
|
+
error: function(data) {
|
366
|
+
flash('Couldn\'t delete thottle ' + throttle_id);
|
367
|
+
}
|
368
|
+
})
|
369
|
+
}
|
370
|
+
|
371
|
+
var update_throttle = function(throttle_id, maximum) {
|
372
|
+
_ajax({
|
373
|
+
url: '<%= u "/throttle" %>',
|
374
|
+
data: {
|
375
|
+
'id': throttle_id,
|
376
|
+
'maximum': maximum
|
377
|
+
}, success: function(data) {
|
378
|
+
flash('Updated throttle for ' + throttle_id, 'success');
|
379
|
+
}, error: function(data) {
|
380
|
+
flash('Couldn\'t update throttle ' + throttle_id);
|
381
|
+
}
|
382
|
+
})
|
383
|
+
}
|
384
|
+
|
385
|
+
$(document).ready(function() {
|
386
|
+
$('button').tooltip({delay:200});
|
387
|
+
});
|
388
|
+
</script>
|
389
|
+
<!-- Le HTML5 shim, for IE6-8 support of HTML5 elements -->
|
390
|
+
<!--[if lt IE 9]>
|
391
|
+
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
|
392
|
+
<![endif]-->
|
393
|
+
</head>
|
394
|
+
|
395
|
+
<body>
|
396
|
+
<div class="navbar navbar-fixed-top">
|
397
|
+
<div class="navbar-inner">
|
398
|
+
<div class="container">
|
399
|
+
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
|
400
|
+
<span class="icon-bar"></span>
|
401
|
+
<span class="icon-bar"></span>
|
402
|
+
<span class="icon-bar"></span>
|
403
|
+
</a>
|
404
|
+
<a class="brand" href="<%= u '/' %>"><%= application_name %></a>
|
405
|
+
<div class="nav-collapse">
|
406
|
+
<ul class="nav nav-bar">
|
407
|
+
<% tabs.each do |tab| %>
|
408
|
+
<li><a href='<%= u tab[:path] %>'><%= tab[:name] %></a></li>
|
409
|
+
<% end %>
|
410
|
+
</ul>
|
411
|
+
<ul class="nav nav-bar pull-right">
|
412
|
+
<li>
|
413
|
+
<form class="navbar-search" action="<%= u '/tag' %>">
|
414
|
+
<input id="tag-search" type="text" class="search-query" placeholder="Search by Tag" data-provide="typeahead" name="tag"/>
|
415
|
+
</form>
|
416
|
+
</li>
|
417
|
+
</ul>
|
418
|
+
</div>
|
419
|
+
</div>
|
420
|
+
</div>
|
421
|
+
</div>
|
422
|
+
|
423
|
+
<div class="container">
|
424
|
+
<%= yield %>
|
425
|
+
<!-- <footer class="footer">
|
426
|
+
<p>Powered by <a href="http://github.com/tdg5/reqless-rb">reqless</a> v<%=Reqless::VERSION%></p>
|
427
|
+
</footer> -->
|
428
|
+
</div> <!-- /container -->
|
429
|
+
|
430
|
+
<!-- Le javascript
|
431
|
+
================================================== -->
|
432
|
+
<script src="<%= u '/js/bootstrap.min.js' %>"></script>
|
433
|
+
<script src="<%= u '/js/bootstrap-tab.js' %>"></script>
|
434
|
+
<script src="<%= u '/js/bootstrap-alert.js' %>"></script>
|
435
|
+
<script src="<%= u '/js/bootstrap-tooltip.js' %>"></script>
|
436
|
+
<script src="<%= u '/js/bootstrap-scrollspy.js' %>"></script>
|
437
|
+
<script src="<%= u '/js/bootstrap-typeahead.js' %>"></script>
|
438
|
+
|
439
|
+
<!-- Noty! This is such a wonderful-looking library, and /exactly/ what I wanted. Thank you so much! -->
|
440
|
+
<script src="<%= u '/js/jquery.noty.js' %>"></script>
|
441
|
+
<!--
|
442
|
+
<script src="../assets/js/bootstrap-transition.js"></script>
|
443
|
+
<script src="../assets/js/bootstrap-modal.js"></script>
|
444
|
+
<script src="../assets/js/bootstrap-dropdown.js"></script>
|
445
|
+
<script src="../assets/js/bootstrap-popover.js"></script>
|
446
|
+
<script src="../assets/js/bootstrap-button.js"></script>
|
447
|
+
<script src="../assets/js/bootstrap-collapse.js"></script>
|
448
|
+
<script src="../assets/js/bootstrap-carousel.js"></script>
|
449
|
+
-->
|
450
|
+
</body>
|
451
|
+
</html>
|
@@ -0,0 +1,137 @@
|
|
1
|
+
<% if queues.empty? %>
|
2
|
+
<div class="page-header">
|
3
|
+
<h1>No Queues <small>I wish I had some queues :-/</small></h1>
|
4
|
+
</div>
|
5
|
+
<% else %>
|
6
|
+
<div class="page-header">
|
7
|
+
<h1>Queues <small>And their job counts</small></h1>
|
8
|
+
</div>
|
9
|
+
|
10
|
+
<table class="table">
|
11
|
+
<thead>
|
12
|
+
<tr>
|
13
|
+
<th></th>
|
14
|
+
<th>running</th>
|
15
|
+
<th>waiting</th>
|
16
|
+
<th>throttled</th>
|
17
|
+
<th>scheduled</th>
|
18
|
+
<th>stalled</th>
|
19
|
+
<th>depends</th>
|
20
|
+
<th>recurring</th>
|
21
|
+
</tr>
|
22
|
+
</thead>
|
23
|
+
<tbody>
|
24
|
+
<% queues.each do |queue| %>
|
25
|
+
<tr class="queue-row">
|
26
|
+
<td class="queue-column large-text">
|
27
|
+
<% if queue['paused'] %>
|
28
|
+
<button
|
29
|
+
id="<%= queue['name'] %>-pause"
|
30
|
+
title="Unpause"
|
31
|
+
class="btn btn-success"
|
32
|
+
onclick="unpause('<%= queue['name'] %>')"><i class="icon-play"></i>
|
33
|
+
</button>
|
34
|
+
<% else %>
|
35
|
+
<button
|
36
|
+
id="<%= queue['name'] %>-pause"
|
37
|
+
title="Pause"
|
38
|
+
class="btn btn-warning"
|
39
|
+
onclick="pause('<%= queue['name'] %>')"><i class="icon-pause"></i>
|
40
|
+
</button>
|
41
|
+
<% end %>
|
42
|
+
<a href="<%= u "/queues/#{CGI::escape(queue['name'])}" %>"><%= queue['name'] %></a>
|
43
|
+
</td>
|
44
|
+
<td><%= queue['running'] %></td>
|
45
|
+
<td><%= queue['waiting'] %></td>
|
46
|
+
<td><%= queue['throttled'] %></td>
|
47
|
+
<td><%= queue['scheduled'] %></td>
|
48
|
+
<td><%= queue['stalled'] %></td>
|
49
|
+
<td><%= queue['depends'] %></td>
|
50
|
+
<td><%= queue['recurring'] %></td>
|
51
|
+
</tr>
|
52
|
+
<% end %>
|
53
|
+
</tbody>
|
54
|
+
</table>
|
55
|
+
<% end %>
|
56
|
+
|
57
|
+
<% if failed.empty? %>
|
58
|
+
<div class="page-header">
|
59
|
+
<h1>No Failed Jobs <small>Clean as a whistle</small></h1>
|
60
|
+
</div>
|
61
|
+
<% else %>
|
62
|
+
<div class="page-header">
|
63
|
+
<h1>Failed Jobs <small>D'oh!</small></h1>
|
64
|
+
</div>
|
65
|
+
|
66
|
+
<table class="table">
|
67
|
+
<thead>
|
68
|
+
<tr>
|
69
|
+
<th>failure</th>
|
70
|
+
<th>count</th>
|
71
|
+
</tr>
|
72
|
+
</thead>
|
73
|
+
<tbody>
|
74
|
+
<% failed.sort_by { |t, count| -count }.each do |t, count| %>
|
75
|
+
<tr class="failed-row">
|
76
|
+
<td class="large-text"><a href="<%= u "/failed/#{t}" %>"><%= t %></a></td>
|
77
|
+
<td><%= count %></td>
|
78
|
+
</tr>
|
79
|
+
<% end %>
|
80
|
+
</tbody>
|
81
|
+
</table>
|
82
|
+
<% end %>
|
83
|
+
|
84
|
+
<% if tracked['jobs'].empty? %>
|
85
|
+
<div class="page-header">
|
86
|
+
<h1>No Tracked Jobs <small>These aren't the droids you're looking for</small></h1>
|
87
|
+
</div>
|
88
|
+
<% else %>
|
89
|
+
<div class="page-header">
|
90
|
+
<h1>Tracked Jobs <small>These <i>are</i> the droids you're looking for</small></h1>
|
91
|
+
</div>
|
92
|
+
<% counts = Hash.new; tracked['jobs'].each { |job| counts[job.state] ||= 0; counts[job.state] += 1 } %>
|
93
|
+
<table class="table">
|
94
|
+
<thead>
|
95
|
+
<tr>
|
96
|
+
<th>state</th>
|
97
|
+
<th>count</th>
|
98
|
+
</tr>
|
99
|
+
</thead>
|
100
|
+
<tbody>
|
101
|
+
<% counts.sort_by { |state, count| - count }.each do |state, count| %>
|
102
|
+
<tr class="tracked-row">
|
103
|
+
<td class="large-text"><a href="<%= u "/track##{state}" %>"><%= state %></a></td>
|
104
|
+
<td><%= count %></td>
|
105
|
+
</tr>
|
106
|
+
<% end %>
|
107
|
+
</tbody>
|
108
|
+
</table>
|
109
|
+
<% end %>
|
110
|
+
|
111
|
+
<% if workers.empty? %>
|
112
|
+
<div class="page-header">
|
113
|
+
<h1>No Workers <small>Nobody's doin' nothin'!</small></h1>
|
114
|
+
</div>
|
115
|
+
<% else %>
|
116
|
+
<div class="page-header">
|
117
|
+
<h1>Current Workers <small>And their job counts</small></h1>
|
118
|
+
</div>
|
119
|
+
<table class="table">
|
120
|
+
<thead>
|
121
|
+
<tr>
|
122
|
+
<th></th>
|
123
|
+
<th>running</th>
|
124
|
+
<th>stalled</th>
|
125
|
+
</tr>
|
126
|
+
</thead>
|
127
|
+
<tbody>
|
128
|
+
<% workers.each do |worker| %>
|
129
|
+
<tr class='worker-row'>
|
130
|
+
<td class="large-text"><a href="<%= u "/workers/#{worker['name']}" %>"><%= worker['name'] %></a></td>
|
131
|
+
<td><%= worker['jobs'] %></td>
|
132
|
+
<td><%= worker['stalled'] %></td>
|
133
|
+
</tr>
|
134
|
+
<% end %>
|
135
|
+
</tbody>
|
136
|
+
</table>
|
137
|
+
<% end %>
|