reqless 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +8 -0
  3. data/README.md +648 -0
  4. data/Rakefile +117 -0
  5. data/bin/docker-build-and-test +22 -0
  6. data/exe/reqless-web +11 -0
  7. data/lib/reqless/config.rb +31 -0
  8. data/lib/reqless/failure_formatter.rb +43 -0
  9. data/lib/reqless/job.rb +496 -0
  10. data/lib/reqless/job_reservers/ordered.rb +29 -0
  11. data/lib/reqless/job_reservers/round_robin.rb +46 -0
  12. data/lib/reqless/job_reservers/shuffled_round_robin.rb +21 -0
  13. data/lib/reqless/lua/reqless-lib.lua +2965 -0
  14. data/lib/reqless/lua/reqless.lua +2545 -0
  15. data/lib/reqless/lua_script.rb +90 -0
  16. data/lib/reqless/middleware/requeue_exceptions.rb +94 -0
  17. data/lib/reqless/middleware/retry_exceptions.rb +72 -0
  18. data/lib/reqless/middleware/sentry.rb +66 -0
  19. data/lib/reqless/middleware/timeout.rb +63 -0
  20. data/lib/reqless/queue.rb +189 -0
  21. data/lib/reqless/queue_priority_pattern.rb +16 -0
  22. data/lib/reqless/server/static/css/bootstrap-responsive.css +686 -0
  23. data/lib/reqless/server/static/css/bootstrap-responsive.min.css +12 -0
  24. data/lib/reqless/server/static/css/bootstrap.css +3991 -0
  25. data/lib/reqless/server/static/css/bootstrap.min.css +689 -0
  26. data/lib/reqless/server/static/css/codemirror.css +112 -0
  27. data/lib/reqless/server/static/css/docs.css +839 -0
  28. data/lib/reqless/server/static/css/jquery.noty.css +105 -0
  29. data/lib/reqless/server/static/css/noty_theme_twitter.css +137 -0
  30. data/lib/reqless/server/static/css/style.css +200 -0
  31. data/lib/reqless/server/static/favicon.ico +0 -0
  32. data/lib/reqless/server/static/img/glyphicons-halflings-white.png +0 -0
  33. data/lib/reqless/server/static/img/glyphicons-halflings.png +0 -0
  34. data/lib/reqless/server/static/js/bootstrap-alert.js +94 -0
  35. data/lib/reqless/server/static/js/bootstrap-scrollspy.js +125 -0
  36. data/lib/reqless/server/static/js/bootstrap-tab.js +130 -0
  37. data/lib/reqless/server/static/js/bootstrap-tooltip.js +270 -0
  38. data/lib/reqless/server/static/js/bootstrap-typeahead.js +285 -0
  39. data/lib/reqless/server/static/js/bootstrap.js +1726 -0
  40. data/lib/reqless/server/static/js/bootstrap.min.js +6 -0
  41. data/lib/reqless/server/static/js/codemirror.js +2972 -0
  42. data/lib/reqless/server/static/js/jquery.noty.js +220 -0
  43. data/lib/reqless/server/static/js/mode/javascript.js +360 -0
  44. data/lib/reqless/server/static/js/theme/cobalt.css +18 -0
  45. data/lib/reqless/server/static/js/theme/eclipse.css +25 -0
  46. data/lib/reqless/server/static/js/theme/elegant.css +10 -0
  47. data/lib/reqless/server/static/js/theme/lesser-dark.css +45 -0
  48. data/lib/reqless/server/static/js/theme/monokai.css +28 -0
  49. data/lib/reqless/server/static/js/theme/neat.css +9 -0
  50. data/lib/reqless/server/static/js/theme/night.css +21 -0
  51. data/lib/reqless/server/static/js/theme/rubyblue.css +21 -0
  52. data/lib/reqless/server/static/js/theme/xq-dark.css +46 -0
  53. data/lib/reqless/server/views/_job.erb +259 -0
  54. data/lib/reqless/server/views/_job_list.erb +8 -0
  55. data/lib/reqless/server/views/_pagination.erb +7 -0
  56. data/lib/reqless/server/views/about.erb +130 -0
  57. data/lib/reqless/server/views/completed.erb +11 -0
  58. data/lib/reqless/server/views/config.erb +14 -0
  59. data/lib/reqless/server/views/failed.erb +48 -0
  60. data/lib/reqless/server/views/failed_type.erb +18 -0
  61. data/lib/reqless/server/views/job.erb +17 -0
  62. data/lib/reqless/server/views/layout.erb +451 -0
  63. data/lib/reqless/server/views/overview.erb +137 -0
  64. data/lib/reqless/server/views/queue.erb +125 -0
  65. data/lib/reqless/server/views/queues.erb +45 -0
  66. data/lib/reqless/server/views/tag.erb +6 -0
  67. data/lib/reqless/server/views/throttles.erb +38 -0
  68. data/lib/reqless/server/views/track.erb +75 -0
  69. data/lib/reqless/server/views/worker.erb +34 -0
  70. data/lib/reqless/server/views/workers.erb +14 -0
  71. data/lib/reqless/server.rb +549 -0
  72. data/lib/reqless/subscriber.rb +74 -0
  73. data/lib/reqless/test_helpers/worker_helpers.rb +55 -0
  74. data/lib/reqless/throttle.rb +57 -0
  75. data/lib/reqless/version.rb +5 -0
  76. data/lib/reqless/worker/base.rb +237 -0
  77. data/lib/reqless/worker/forking.rb +215 -0
  78. data/lib/reqless/worker/serial.rb +41 -0
  79. data/lib/reqless/worker.rb +5 -0
  80. data/lib/reqless.rb +309 -0
  81. metadata +399 -0
@@ -0,0 +1,28 @@
1
+ /* Based on Sublime Text's Monokai theme */
2
+
3
+ .cm-s-monokai {background: #272822; color: #f8f8f2;}
4
+ .cm-s-monokai div.CodeMirror-selected {background: #49483E !important;}
5
+ .cm-s-monokai .CodeMirror-gutter {background: #272822; border-right: 0px;}
6
+ .cm-s-monokai .CodeMirror-gutter-text {color: #d0d0d0;}
7
+ .cm-s-monokai .CodeMirror-cursor {border-left: 1px solid #f8f8f0 !important;}
8
+
9
+ .cm-s-monokai span.cm-comment {color: #75715e;}
10
+ .cm-s-monokai span.cm-atom {color: #ae81ff;}
11
+ .cm-s-monokai span.cm-number {color: #ae81ff;}
12
+
13
+ .cm-s-monokai span.cm-property, .cm-s-monokai span.cm-attribute {color: #a6e22e;}
14
+ .cm-s-monokai span.cm-keyword {color: #f92672;}
15
+ .cm-s-monokai span.cm-string {color: #e6db74;}
16
+
17
+ .cm-s-monokai span.cm-variable {color: #a6e22e;}
18
+ .cm-s-monokai span.cm-variable-2 {color: #9effff;}
19
+ .cm-s-monokai span.cm-def {color: #fd971f;}
20
+ .cm-s-monokai span.cm-error {background: #f92672; color: #f8f8f0;}
21
+ .cm-s-monokai span.cm-bracket {color: #f8f8f2;}
22
+ .cm-s-monokai span.cm-tag {color: #f92672;}
23
+ .cm-s-monokai span.cm-link {color: #ae81ff;}
24
+
25
+ .cm-s-monokai .CodeMirror-matchingbracket {
26
+ text-decoration: underline;
27
+ color: white !important;
28
+ }
@@ -0,0 +1,9 @@
1
+ .cm-s-neat span.cm-comment { color: #a86; }
2
+ .cm-s-neat span.cm-keyword { line-height: 1em; font-weight: bold; color: blue; }
3
+ .cm-s-neat span.cm-string { color: #a22; }
4
+ .cm-s-neat span.cm-builtin { line-height: 1em; font-weight: bold; color: #077; }
5
+ .cm-s-neat span.cm-special { line-height: 1em; font-weight: bold; color: #0aa; }
6
+ .cm-s-neat span.cm-variable { color: black; }
7
+ .cm-s-neat span.cm-number, .cm-s-neat span.cm-atom { color: #3a3; }
8
+ .cm-s-neat span.cm-meta {color: #555;}
9
+ .cm-s-neat span.cm-link { color: #3a3; }
@@ -0,0 +1,21 @@
1
+ /* Loosely based on the Midnight Textmate theme */
2
+
3
+ .cm-s-night { background: #0a001f; color: #f8f8f8; }
4
+ .cm-s-night div.CodeMirror-selected { background: #a8f !important; }
5
+ .cm-s-night .CodeMirror-gutter { background: #0a001f; border-right: 1px solid #aaa; }
6
+ .cm-s-night .CodeMirror-gutter-text { color: #f8f8f8; }
7
+ .cm-s-night .CodeMirror-cursor { border-left: 1px solid white !important; }
8
+
9
+ .cm-s-night span.cm-comment { color: #6900a1; }
10
+ .cm-s-night span.cm-atom { color: #845dc4; }
11
+ .cm-s-night span.cm-number, .cm-s-night span.cm-attribute { color: #ffd500; }
12
+ .cm-s-night span.cm-keyword { color: #599eff; }
13
+ .cm-s-night span.cm-string { color: #37f14a; }
14
+ .cm-s-night span.cm-meta { color: #7678e2; }
15
+ .cm-s-night span.cm-variable-2, .cm-s-night span.cm-tag { color: #99b2ff; }
16
+ .cm-s-night span.cm-variable-3, .cm-s-night span.cm-def { color: white; }
17
+ .cm-s-night span.cm-error { color: #9d1e15; }
18
+ .cm-s-night span.cm-bracket { color: #8da6ce; }
19
+ .cm-s-night span.cm-comment { color: #6900a1; }
20
+ .cm-s-night span.cm-builtin, .cm-s-night span.cm-special { color: #ff9e59; }
21
+ .cm-s-night span.cm-link { color: #845dc4; }
@@ -0,0 +1,21 @@
1
+ .cm-s-rubyblue { font:13px/1.4em Trebuchet, Verdana, sans-serif; } /* - customized editor font - */
2
+
3
+ .cm-s-rubyblue { background: #112435; color: white; }
4
+ .cm-s-rubyblue div.CodeMirror-selected { background: #38566F !important; }
5
+ .cm-s-rubyblue .CodeMirror-gutter { background: #1F4661; border-right: 7px solid #3E7087; min-width:2.5em; }
6
+ .cm-s-rubyblue .CodeMirror-gutter-text { color: white; }
7
+ .cm-s-rubyblue .CodeMirror-cursor { border-left: 1px solid white !important; }
8
+
9
+ .cm-s-rubyblue span.cm-comment { color: #999; font-style:italic; line-height: 1em; }
10
+ .cm-s-rubyblue span.cm-atom { color: #F4C20B; }
11
+ .cm-s-rubyblue span.cm-number, .cm-s-rubyblue span.cm-attribute { color: #82C6E0; }
12
+ .cm-s-rubyblue span.cm-keyword { color: #F0F; }
13
+ .cm-s-rubyblue span.cm-string { color: #F08047; }
14
+ .cm-s-rubyblue span.cm-meta { color: #F0F; }
15
+ .cm-s-rubyblue span.cm-variable-2, .cm-s-rubyblue span.cm-tag { color: #7BD827; }
16
+ .cm-s-rubyblue span.cm-variable-3, .cm-s-rubyblue span.cm-def { color: white; }
17
+ .cm-s-rubyblue span.cm-error { color: #AF2018; }
18
+ .cm-s-rubyblue span.cm-bracket { color: #F0F; }
19
+ .cm-s-rubyblue span.cm-link { color: #F4C20B; }
20
+ .cm-s-rubyblue span.CodeMirror-matchingbracket { color:#F0F !important; }
21
+ .cm-s-rubyblue span.cm-builtin, .cm-s-rubyblue span.cm-special { color: #FF9D00; }
@@ -0,0 +1,46 @@
1
+ /*
2
+ Copyright (C) 2011 by MarkLogic Corporation
3
+ Author: Mike Brevoort <mike@brevoort.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
22
+ */
23
+ .cm-s-xq-dark { background: #0a001f; color: #f8f8f8; }
24
+ .cm-s-xq-dark span.CodeMirror-selected { background: #a8f !important; }
25
+ .cm-s-xq-dark .CodeMirror-gutter { background: #0a001f; border-right: 1px solid #aaa; }
26
+ .cm-s-xq-dark .CodeMirror-gutter-text { color: #f8f8f8; }
27
+ .cm-s-xq-dark .CodeMirror-cursor { border-left: 1px solid white !important; }
28
+
29
+ .cm-s-xq-dark span.cm-keyword {color: #FFBD40;}
30
+ .cm-s-xq-dark span.cm-atom {color: #6C8CD5;}
31
+ .cm-s-xq-dark span.cm-number {color: #164;}
32
+ .cm-s-xq-dark span.cm-def {color: #FFF; text-decoration:underline;}
33
+ .cm-s-xq-dark span.cm-variable {color: #FFF;}
34
+ .cm-s-xq-dark span.cm-variable-2 {color: #EEE;}
35
+ .cm-s-xq-dark span.cm-variable-3 {color: #DDD;}
36
+ .cm-s-xq-dark span.cm-property {}
37
+ .cm-s-xq-dark span.cm-operator {}
38
+ .cm-s-xq-dark span.cm-comment {color: gray;}
39
+ .cm-s-xq-dark span.cm-string {color: #9FEE00;}
40
+ .cm-s-xq-dark span.cm-meta {color: yellow;}
41
+ .cm-s-xq-dark span.cm-error {color: #f00;}
42
+ .cm-s-xq-dark span.cm-qualifier {color: #FFF700;}
43
+ .cm-s-xq-dark span.cm-builtin {color: #30a;}
44
+ .cm-s-xq-dark span.cm-bracket {color: #cc7;}
45
+ .cm-s-xq-dark span.cm-tag {color: #FFBD40;}
46
+ .cm-s-xq-dark span.cm-attribute {color: #FFF700;}
@@ -0,0 +1,259 @@
1
+ <% if job.instance_of?(Reqless::Job) %>
2
+ <div class="row" id="job-<%= job.jid %>">
3
+ <div class="span12">
4
+ <div class="row">
5
+ <div class="span6">
6
+ <h2 style="text-overflow: ellipsis; white-space: nowrap; overflow: hidden">
7
+ <a href="<%= u "/jobs/#{job.jid}" %>"><%= job.jid[0..8] %>...</a> | <%= job.klass_name %>
8
+ </h2>
9
+ </div>
10
+ <div class="span3">
11
+ <h2 style="text-overflow: ellipsis; white-space: nowrap; overflow: hidden">
12
+ <strong>
13
+ | <%= job.state %> / <a href="<%= u "/queues/#{CGI::escape(job.queue_name)}" %>" title="<%= job.queue_name %><%= job.worker_name.nil? ? "/ #{job.worker_name}" : "" %>"><%= job.queue_name %></a><%= job.worker_name.nil? ? "/ #{job.worker_name}" : "" %>
14
+ </strong>
15
+ </h2>
16
+ </div>
17
+ <div class="span3">
18
+ <div style="float:right; margin-top: 4px">
19
+ <div class="btn-group">
20
+ <% if (job.state != "complete") %>
21
+ <button title="delete" class="btn btn-danger" onclick="confirmation(this, 'Delete?', function() { cancel('<%= job.jid %>', fade) })"><i class="icon-remove"></i></button>
22
+ <% end %>
23
+ <% if (job.state == "running") %>
24
+ <button title="Time out job" class="btn btn-danger" onclick="confirmation(this, 'Time out job?', function() { timeout('<%= job.jid %>') })"><i class="icon-time"></i></button>
25
+ <% end %>
26
+ <button title="track" class="btn<%= job.tracked ? " active" : "" %>" data-toggle="button" onclick="$(this).hasClass('active') ? untrack('<%= job.jid %>', fade) : track('<%= job.jid %>', [], fade)"><i class="icon-flag"></i></button>
27
+ <% if (job.state == 'failed') %>
28
+ <button title="requeue" class="btn btn-success" onclick="retry('<%= job.jid %>', fade)"><i class="icon-repeat"></i></button>
29
+ <% end %>
30
+ <button title="move" class="btn dropdown-toggle btn-success" data-toggle="dropdown">
31
+ <i class="caret"></i>
32
+ </button>
33
+ <ul class="dropdown-menu">
34
+ <% queues.each do |queue| %>
35
+ <a href="#" onclick="move('<%= job.jid %>', '<%= queue['name'] %>', fade)"><%= queue['name'] %></a>
36
+ <% end %>
37
+ </ul>
38
+ </div>
39
+ </div>
40
+ <div style="float:right; margin-right: 12px; margin-top: 4px">
41
+ <div class="btn-group">
42
+ <input class="span1 priority" type="text" placeholder="Pri <%= job.priority %>" onchange="priority('<%= job.jid %>', $(this).val())"></input>
43
+ <button class="btn dropdown-toggle" data-toggle="dropdown">
44
+ <i class="caret"></i>
45
+ </button>
46
+ <ul class="dropdown-menu">
47
+ <a href="#" onclick="priority('<%= job.jid %>', 25)">high</a>
48
+ <a href="#" onclick="priority('<%= job.jid %>', 0 )">normal</a>
49
+ <a href="#" onclick="priority('<%= job.jid %>', -25)">low</a>
50
+ </ul>
51
+ </div>
52
+ </div>
53
+ </div>
54
+ </div>
55
+
56
+ <% if not job.dependencies.empty? %>
57
+ <div class="row">
58
+ <div class="span12" style="margin-bottom: 10px">
59
+ <div style="float:left; margin-right: 10px"><h3>Dependencies:</h3></div>
60
+ <% job.dependencies.each do |jid| %>
61
+ <div class="btn-group" style="float:left; margin-right: 10px" id="<%= sanitize_attr("#{job.jid}-dependson-#{jid}") %>">
62
+ <button class="btn" onclick="window.open('<%= u "/jobs/#{jid}" %>', '_blank')" title="<%= jid %>"><%= jid[0...8] %>...</button>
63
+ <button class="btn dropdown-toggle" onclick="confirmation(this, 'Undepend?', function() { undepend('<%= job.jid %>', '<%= jid %>', function() { $('#<%= sanitize_attr("#{job.jid}-dependson-#{jid}") %>').remove()} ); })">
64
+ <i class="icon-remove"></i>
65
+ </button>
66
+ </div>
67
+ <% end %>
68
+ </div>
69
+ </div>
70
+ <% end %>
71
+
72
+ <% if not job.dependents.empty? %>
73
+ <div class="row">
74
+ <div class="span12" style="margin-bottom: 10px">
75
+ <div style="float:left; margin-right: 10px"><h3>Dependents:</h3></div>
76
+ <% job.dependents.each do |jid| %>
77
+ <div class="btn-group" style="float:left; margin-right: 10px" id="<%= sanitize_attr("#{job.jid}-dependents-#{jid}") %>">
78
+ <button class="btn" onclick="window.open('<%= u "/jobs/#{jid}" %>', '_blank')" title="<%= jid %>"><%= jid[0...8] %>...</button>
79
+ <button class="btn dropdown-toggle" onclick="confirmation(this, 'Undepend?', function() { undepend('<%= jid %>', '<%= job.jid %>', function() { $('#<%= sanitize_attr("#{job.jid}-dependents-#{jid}") %>').remove()} ); })">
80
+ <i class="icon-remove"></i>
81
+ </button>
82
+ </div>
83
+ <% end %>
84
+ </div>
85
+ </div>
86
+ <% end %>
87
+
88
+ <div class="row">
89
+ <div class="span12 tags" style="margin-bottom: 3px;">
90
+ <% job.tags.each do |tag| %>
91
+ <div class="btn-group" style="float:left">
92
+ <span class="tag"><%= tag %></span>
93
+ <button class="btn" onclick="untag('<%= job.jid %>', '<%= tag %>')">
94
+ <i class="icon-remove"></i>
95
+ </button>
96
+ </div>
97
+ <% end %>
98
+
99
+ <!-- One for adding new tags -->
100
+ <div class="btn-group" style="float:left">
101
+ <input class="span1 add-tag" type="text" placeholder="Add Tag" onchange="tag('<%= job.jid %>', $(this).val())"></input>
102
+ <button class="btn" onclick="tag('<%= job.jid %>', $(this).parent().siblings().val())">
103
+ <i class="icon-plus"></i>
104
+ </button>
105
+ </div>
106
+ </div>
107
+ </div>
108
+
109
+ <% if not defined? brief %>
110
+ <div class="row">
111
+ <div class="span6">
112
+ <h3><small>Data</small></h3>
113
+ <pre style="overflow-y:scroll; height: 200px"><%= JSON.pretty_generate(job.data) %></pre>
114
+ </div>
115
+ <div class="span6">
116
+ <h3><small>History</small></h3>
117
+ <div style="overflow-y:scroll; height: 200px">
118
+ <% job.queue_history.reverse.each do |h| %>
119
+ <% if h['what'] == 'put' %>
120
+ <pre><strong><%= h['what'] %></strong> at <%= strftime(h['when']) %>
121
+ in queue <strong><%= h['q'] %></strong></pre>
122
+ <% elsif h['what'] == 'popped' %>
123
+ <pre><strong><%= h['what'] %></strong> at <%= strftime(h['when']) %>
124
+ by <strong><%= h['worker'] %></strong></pre>
125
+ <% elsif h['what'] == 'done' %>
126
+ <pre><strong>completed</strong> at <%= strftime(h['when']) %></pre>
127
+ <% elsif h['what'] == 'failed' %>
128
+ <% if h['worker'] %>
129
+ <pre><strong><%= h['what'] %></strong> at <%= strftime(h['when']) %>
130
+ by <strong><%= h['worker'] %></strong>
131
+ in group <strong><%= h['group'] %></strong></pre>
132
+ <% else %>
133
+ <pre><strong><%= h['what'] %></strong> at <%= strftime(h['when']) %>
134
+ in group <strong><%= h['group'] %></strong></pre>
135
+ <% end %>
136
+ <% else %>
137
+ <pre><strong><%= h['what'] %></strong> at <%= strftime(h['when']) %></pre>
138
+ <% end %>
139
+ <% end %>
140
+ </div>
141
+ </div>
142
+ </div>
143
+ <% end %>
144
+
145
+ <% if job.failure.length > 0 %>
146
+ <div class="row">
147
+ <div class="span12">
148
+ <div class="alert alert-error">
149
+ <p>In <strong><%= job.queue_name %></strong> on <strong><%= job.failure['worker'] %></strong>
150
+ about <%= strftime(Time.at(job.failure['when'])) %></p>
151
+ <pre><%= job.failure['message'].gsub('>', '&gt;').gsub('<', '&lt;') %></pre>
152
+ </div>
153
+ </div>
154
+ </div>
155
+ <% end %>
156
+
157
+ <% job.throttle_objects.each do |throttle| %>
158
+ <div class="row">
159
+ <div class="span4">
160
+ <h3><%= throttle.id %></h3>
161
+ </div>
162
+ <div class="span1">
163
+ <input class="span1 <%= throttle.id.gsub(':', '-') %>-maximum" type="text" placeholder="<%= throttle.maximum %>" onchange="update_throttle('<%= throttle.id %>', $(this).val())"></input>
164
+ </div>
165
+ <div class="span1" style="margin-left:10px">
166
+ <input class="span1 <%= throttle.id.gsub(':', '-') %>-expiration" type="text" placeholder="<%= throttle.ttl %>" onchange="expire_throttle('<%= throttle.id %>', $(this).val())"></input>
167
+ </div>
168
+ <div class="span1" style="margin-left:10px">
169
+ <button title="delete" class="btn btn-danger remove-throttle" onclick="confirmation(this, 'Delete?',function() { delete_throttle('<%= throttle.id %>', fade) })">
170
+ <i class="icon-remove"></i>
171
+ </button>
172
+ </div>
173
+ <div class="span3">
174
+ <h3><small>( maximum / TTL / reset )</small></h3>
175
+ </div>
176
+ </div>
177
+ <% end %>
178
+ <hr/>
179
+ </div>
180
+ </div>
181
+ <% else # Recurring job %>
182
+ <div class="row" id="job-<%= job.jid %>">
183
+ <div class="span12">
184
+ <div class="row">
185
+ <div class="span6">
186
+ <h2 style="text-overflow: ellipsis; white-space: nowrap; overflow: hidden">
187
+ <a href="<%= u "/jobs/#{job.jid}" %>" title="<%= job.jid %>"><%= job.jid[0..8] %>...</a> | <span title="<%= job.klass_name %>"><%= job.klass_name %></span>
188
+ </h2>
189
+ </div>
190
+ <div class="span3">
191
+ <h2 style="text-overflow: ellipsis; white-space: nowrap; overflow: hidden">
192
+ <strong>
193
+ | recurring / <a href="<%= u "/queues/#{CGI::escape(job.queue_name)}" %>" title="<%= job.queue_name %>"><%= job.queue_name %></a>
194
+ </strong>
195
+ </h2>
196
+ </div>
197
+ <div class="span3">
198
+ <div style="float:right; margin-top: 4px">
199
+ <div class="btn-group">
200
+ <button title="delete" class="btn btn-danger" onclick="confirmation(this, 'Delete?', function() { cancel('<%= job.jid %>', fade) })"><i class="icon-remove"></i></button>
201
+ <button title="move" class="btn dropdown-toggle btn-success" data-toggle="dropdown">
202
+ <i class="caret"></i>
203
+ </button>
204
+ <ul class="dropdown-menu">
205
+ <% queues.each do |queue| %>
206
+ <a href="#" onclick="move('<%= job.jid %>', '<%= queue['name'] %>', fade)"><%= queue['name'] %></a>
207
+ <% end %>
208
+ </ul>
209
+ </div>
210
+ </div>
211
+ <div style="float:right; margin-right: 12px; margin-top: 4px">
212
+ <div class="btn-group">
213
+ <input class="span1 priority" type="text" placeholder="Pri <%= job.priority %>" onchange="priority('<%= job.jid %>', $(this).val())"></input>
214
+ <button class="btn dropdown-toggle" data-toggle="dropdown">
215
+ <i class="caret"></i>
216
+ </button>
217
+ <ul class="dropdown-menu">
218
+ <a href="#" onclick="priority('<%= job.jid %>', 25)">high</a>
219
+ <a href="#" onclick="priority('<%= job.jid %>', 0 )">normal</a>
220
+ <a href="#" onclick="priority('<%= job.jid %>', -25)">low</a>
221
+ </ul>
222
+ </div>
223
+ </div>
224
+ </div>
225
+ </div>
226
+
227
+ <div class="row">
228
+ <div class="span12 tags" style="margin-bottom: 3px;">
229
+ <% job.tags.each do |tag| %>
230
+ <div class="btn-group" style="float:left">
231
+ <span class="tag"><%= tag %></span>
232
+ <button class="btn" onclick="untag('<%= job.jid %>', '<%= tag %>')">
233
+ <i class="icon-remove"></i>
234
+ </button>
235
+ </div>
236
+ <% end %>
237
+
238
+ <!-- One for adding new tags -->
239
+ <div class="btn-group" style="float:left">
240
+ <input class="span1 add-tag" type="text" placeholder="Add Tag" onchange="tag('<%= job.jid %>', $(this).val())"></input>
241
+ <button class="btn" onclick="tag('<%= job.jid %>', $(this).parent().siblings().val())">
242
+ <i class="icon-plus"></i>
243
+ </button>
244
+ </div>
245
+ </div>
246
+ </div>
247
+
248
+ <% if not defined? brief %>
249
+ <div class="row">
250
+ <div class="span12">
251
+ <h3><small>Data</small></h3>
252
+ <pre style="overflow-y:scroll; height: 200px"><%= JSON.pretty_generate(job.data) %></pre>
253
+ </div>
254
+ </div>
255
+ <% end %>
256
+ <hr/>
257
+ </div>
258
+ </div>
259
+ <% end %>
@@ -0,0 +1,8 @@
1
+ <%= erb :_pagination, :layout => false, :locals => {:extra_classes => ['top-pagination']} %>
2
+
3
+ <% jobs.each do |job| %>
4
+ <%= erb :_job, :layout => false, :locals => { :job => job, :queues => queues } %>
5
+ <% end %>
6
+
7
+ <%= erb :_pagination, :layout => false, :locals => {:extra_classes => ['bottom-pagination']} %>
8
+
@@ -0,0 +1,7 @@
1
+ <div class="pagination<%= extra_classes ? " #{extra_classes.join(' ')}" : '' %>">
2
+ <ul>
3
+ <li><a href="<%= prev_page_url %>">Prev</a></li>
4
+ <li><a href="<%= next_page_url %>">Next</a></li>
5
+ </ul>
6
+ </div>
7
+
@@ -0,0 +1,130 @@
1
+ <div class="subnav subnav-fixed">
2
+ <ul class="nav nav-pills">
3
+ <li><a href="#philosophy">Philosophy</a></li>
4
+ <li><a href="#features">Features</a></li>
5
+ <li><a href="#benchmarks">Benchmarks</a></li>
6
+ </ul>
7
+ </div>
8
+
9
+ <header class="jumbotron subhead" style="margin-top: 40px">
10
+ <h1>Reqless <small>In 50 words or less</small></h1>
11
+ <p class="lead">Reqless is a <a href="http://redis.io/">Redis</a>-backed, robust, language-agnostic job queueing system.
12
+ It is a collection of <a href="http://github.com/tdg5/reqless-core">Lua scripts</a> that run on a Redis server,
13
+ as well as this web app). <a href="http://github.com/tdg5/reqless-rb">Reqless</a> is open-sourced under the MIT license
14
+ and currently has bindings for <a href="http://github.com/tdg5/reqless-rb">Ruby</a>, <a href="http://github.com/tdg5/reqless-py">Python</a>
15
+ with C++ and Node.js support coming soon.</p>
16
+ </header>
17
+
18
+ <section id="philosophy">
19
+ <div class="page-header">
20
+ <h1>Philosophy <small>and nomenclature</h1>
21
+ </div>
22
+ <div class="row">
23
+ <div class="span12">
24
+ <p class="lead">A job is a unit of work. A queue can contain several jobs that are scheduled to be run at a certain time, several jobs that are waiting to run, and jobs that are currently running. A worker is a process on a host, identified uniquely, that asks for jobs from the queue, performs some process associated with that job, and then marks it as complete. When it's completed, it can be put into another queue.</p>
25
+ <p class="lead">Jobs can only be in one queue at a time. That queue is whatever queue they were last put in. So if a worker is working on a job, and you move it, the worker's request to complete the job will be ignored.</p>
26
+ <p class="lead">A job can be canceled, which means it disappears into the ether, and we'll never pay it any mind ever again. A job can be dropped, which is when a worker fails to heartbeat or complete the job in a timely fashion, or a job can be failed, which is when a host recognizes some systematically problematic state about the job. A worker should only fail a job if the error is likely not a transient one; otherwise, that worker should just drop it and let the system reclaim it.</p>
27
+ </div>
28
+ </div>
29
+ </section>
30
+
31
+ <section id="features">
32
+ <div class="page-header">
33
+ <h1>Features <small>In no particular order</small></h1>
34
+ </div>
35
+ <div class="row">
36
+ <div class="span12">
37
+ <div class="row">
38
+ <div class="span6">
39
+ <h3 style="text-align:right">Jobs don't get dropped on the floor</h3>
40
+ </div>
41
+ <div class="span6">
42
+ <h3><small>even in the face of the flakiest workers</small></h3>
43
+ </div>
44
+ </div>
45
+
46
+ <div class="row">
47
+ <div class="span6">
48
+ <h3 style="text-align:right">Jobs are stored temporarily</h3>
49
+ </div>
50
+ <div class="span6">
51
+ <h3><small>but automatically expire after a configurable amount of time</small></h3>
52
+ </div>
53
+ </div>
54
+
55
+ <div class="row">
56
+ <div class="span6">
57
+ <h3 style="text-align:right">Tagging and Tracking</h3>
58
+ </div>
59
+ <div class="span6">
60
+ <h3><small>for keeping tabs on important jobs</small></h3>
61
+ </div>
62
+ </div>
63
+
64
+ <div class="row">
65
+ <div class="span6">
66
+ <h3 style="text-align:right">High Performance</h3>
67
+ </div>
68
+ <div class="span6">
69
+ <h3><small>thanks to Redis and Lua</small></h3>
70
+ </div>
71
+ </div>
72
+
73
+ <div class="row">
74
+ <div class="span6">
75
+ <h3 style="text-align:right">Scheduled Work</h3>
76
+ </div>
77
+ <div class="span6">
78
+ <h3><small>for delayed or periodic processing</small></h3>
79
+ </div>
80
+ </div>
81
+
82
+ <div class="row">
83
+ <div class="span6">
84
+ <h3 style="text-align:right">Retry Logic</h3>
85
+ </div>
86
+ <div class="span6">
87
+ <h3><small>for jobs that have been dropped on the floor</small></h3>
88
+ </div>
89
+ </div>
90
+
91
+ <div class="row">
92
+ <div class="span6">
93
+ <h3 style="text-align:right">Web App</h3>
94
+ </div>
95
+ <div class="span6">
96
+ <h3><small>for checking up on progress and monitoring</small></h3>
97
+ </div>
98
+ </div>
99
+
100
+ <div class="row">
101
+ <div class="span6">
102
+ <h3 style="text-align:right">Priority</h3>
103
+ </div>
104
+ <div class="span6">
105
+ <h3><small>for jobs means you can put selected jobs before others</small></h3>
106
+ </div>
107
+ </div>
108
+
109
+ <div class="row">
110
+ <div class="span6">
111
+ <h3 style="text-align:right">Stats</h3>
112
+ </div>
113
+ <div class="span6">
114
+ <h3><small>about how long jobs wait, how long they take to process</small></h3>
115
+ </div>
116
+ </div>
117
+ </div>
118
+ </div>
119
+ </section>
120
+
121
+ <section id="benchmarks">
122
+ <div class="page-header">
123
+ <h1>Benchmarks <small>In Amazon's EC2</small></h1>
124
+ </div>
125
+ <div class="row">
126
+ <div class="span12">
127
+ <p class="lead">These benchmarks were performed on a <span class="badge badge-info">m1.medium</span>, which has 3.75GB of RAM and 2 ECUs. Actually, I'm going to wait until development's a little more complete before posting these.</p>
128
+ </div>
129
+ </div>
130
+ </section>
@@ -0,0 +1,11 @@
1
+ <% if jobs.empty? %>
2
+ <div class="page-header">
3
+ <h1>No Completed Jobs<small>(yet)</small></h1>
4
+ </div>
5
+ <% else %>
6
+ <div class="page-header">
7
+ <h1>Completed Jobs <small>You must be doing something right!</small></h1>
8
+ </div>
9
+ <% end %>
10
+
11
+ <%= erb :_job_list, :locals => { :jobs => jobs, :queues => queues } %>
@@ -0,0 +1,14 @@
1
+ <div class="page-header">
2
+ <h1>Configuration Settings <small>Including defaults</small></h1>
3
+ </div>
4
+
5
+ <% options.each do |key, value| %>
6
+ <div class="row">
7
+ <div class="span4">
8
+ <h2><%= key %></h2>
9
+ </div>
10
+ <div class="span8">
11
+ <h2>=> <%= value %></h2>
12
+ </div>
13
+ </div>
14
+ <% end %>
@@ -0,0 +1,48 @@
1
+ <div class="subnav subnav-fixed">
2
+ <ul class="nav nav-pills">
3
+ <% failed.sort_by { |f| -f['total'] }.each do |f| %>
4
+ <li><a href="#<%= sanitize_attr(f['type']) %>" data-toggle="tab"><%= f['type'] %> (<%= f['total'] %>)</a></li>
5
+ <% end %>
6
+ </ul>
7
+ </div>
8
+
9
+ <div id="alerts" style="margin-top: 40px"></div>
10
+
11
+ <% if failed.empty? %>
12
+ <div class="page-header">
13
+ <h1>No Failed Jobs <small>You Have Done Well!</small></h1>
14
+ </div>
15
+ <% else %>
16
+ <div class="page-header">
17
+ <h1>Failed Jobs <small>Failure is a Part of Success!</small></h1>
18
+ </div>
19
+ <% end %>
20
+
21
+ <div class="tab-content">
22
+ <% failed.sort_by { |f| -f['total'] }.each do |f| %>
23
+ <div class="tab-pane active" id="<%= sanitize_attr(f['type']) %>">
24
+ <div class="page-header">
25
+ <div class="row">
26
+ <div class="span8">
27
+ <h2>
28
+ <a href="<%= u "/failed/#{f['type']}" %>"><%= f['type'] %></a> | <%= f['total'] %> <small>Jobs</small
29
+ </h2>
30
+ </div>
31
+ <div class="span4">
32
+ <div class="btn-group" style="float:right; margin-top: 5px">
33
+ <button class="btn btn-danger" title="cancel" onclick="confirmation(this, 'Cancel?', function() { cancelall('<%= f['type'] %>', fade) })"><i class="icon-remove"></i></button>
34
+ <button class="btn btn-success" title="retry all" onclick="retryall('<%= f['type'] %>', fade)"><i class="icon-repeat"></i></button>
35
+ </div>
36
+ </div>
37
+ </div>
38
+ </div>
39
+ <div class="row">
40
+ <div class="span12">
41
+ <% f['jobs'][0..5].each do |job| %>
42
+ <%= erb :_job, :layout => false, :locals => { :job => job, :queues => queues, :brief => true } %>
43
+ <% end %>
44
+ </div>
45
+ </div>
46
+ </div>
47
+ <% end %>
48
+ </div>
@@ -0,0 +1,18 @@
1
+ <div id="alerts"></div>
2
+
3
+ <div class="page-header">
4
+ <div class="row">
5
+ <div class="span8">
6
+ <h2>Type '<%= type %>' Failed Jobs <small>These jobs are all failed :-/</small></h2>
7
+ </div>
8
+ <div class="span4">
9
+ <div class="btn-group" style="float:right; margin-top: 5px">
10
+ <button class="btn btn-danger" title="cancel" onclick="confirmation(this, 'Cancel?', function() { cancelall('<%= type %>', fade) })"><i class="icon-remove"></i></button>
11
+ <button class="btn btn-success" title="retry all" onclick="retryall('<%= type %>', fade)"><i class="icon-repeat"></i></button>
12
+ </div>
13
+ </div>
14
+ </div>
15
+ </div>
16
+
17
+ <%= erb :_job_list, :locals => { :jobs => failed.fetch('jobs'), :queues => queues } %>
18
+