resque 1.23.0 → 1.23.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of resque might be problematic. Click here for more details.

@@ -13,7 +13,7 @@ module Resque
13
13
  klass.configure(&block)
14
14
  end
15
15
 
16
- def count
16
+ def count(queue = nil, class_name = nil)
17
17
  # We can't get the total # of errors from Hoptoad so we fake it
18
18
  # by asking Resque how many errors it has seen.
19
19
  Stat[:failed]
@@ -0,0 +1,7 @@
1
+ module Resque
2
+ class QuietFormatter
3
+ def call(serverity, datetime, progname, msg)
4
+ ""
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Resque
2
+ class VerboseFormatter
3
+ def call(serverity, datetime, progname, msg)
4
+ "*** #{msg}\n"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,8 @@
1
+ module Resque
2
+ class VeryVerboseFormatter
3
+ def call(serverity, datetime, progname, msg)
4
+ time = Time.now.strftime('%H:%M:%S %Y-%m-%d')
5
+ "** [#{time}] #$$: #{msg}\n"
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,18 @@
1
+ module Resque
2
+ # Include this module in classes you wish to have logging facilities
3
+ module Logging
4
+ module_function
5
+
6
+ # Thunk to the logger's own log method (if configured)
7
+ def self.log(severity, message)
8
+ Resque.logger.__send__(severity, message) if Resque.logger
9
+ end
10
+
11
+ # Log level aliases
12
+ def debug(message); Logging.log :debug, message; end
13
+ def info(message); Logging.log :info, message; end
14
+ def warn(message); Logging.log :warn, message; end
15
+ def error(message); Logging.log :error, message; end
16
+ def fatal(message); Logging.log :fatal, message; end
17
+ end
18
+ end
@@ -10,6 +10,8 @@ end
10
10
 
11
11
  module Resque
12
12
  class Server < Sinatra::Base
13
+ require 'resque/server/helpers'
14
+
13
15
  dir = File.dirname(File.expand_path(__FILE__))
14
16
 
15
17
  set :views, "#{dir}/server/views"
@@ -181,11 +183,24 @@ module Resque
181
183
  end
182
184
  end
183
185
 
186
+ get "/failed/:queue" do
187
+ if Resque::Failure.url
188
+ redirect Resque::Failure.url
189
+ else
190
+ show :failed
191
+ end
192
+ end
193
+
184
194
  post "/failed/clear" do
185
195
  Resque::Failure.clear
186
196
  redirect u('failed')
187
197
  end
188
198
 
199
+ post "/failed/:queue/clear" do
200
+ Resque::Failure.clear params[:queue]
201
+ redirect u('failed')
202
+ end
203
+
189
204
  post "/failed/requeue/all" do
190
205
  Resque::Failure.count.times do |num|
191
206
  Resque::Failure.requeue(num)
@@ -193,6 +208,11 @@ module Resque
193
208
  redirect u('failed')
194
209
  end
195
210
 
211
+ post "/failed/:queue/requeue/all" do
212
+ Resque::Failure.requeue_queue Resque::Failure.job_queue_name(params[:queue])
213
+ redirect url_path("/failed/#{params[:queue]}")
214
+ end
215
+
196
216
  get "/failed/requeue/:index/?" do
197
217
  Resque::Failure.requeue(params[:index])
198
218
  if request.xhr?
@@ -0,0 +1,48 @@
1
+ Resque::Server.helpers do
2
+ ####################
3
+ #failed.erb helpers#
4
+ ####################
5
+
6
+ def failed_date_format
7
+ "%Y/%m/%d %T %z"
8
+ end
9
+
10
+ def failed_multiple_queues?
11
+ return @multiple_failed_queues if defined?(@multiple_failed_queues)
12
+ @multiple_failed_queues = Resque::Failure.queues.size > 1
13
+ end
14
+
15
+ def failed_size
16
+ @failed_size ||= Resque::Failure.count(params[:queue], params[:class])
17
+ end
18
+
19
+ def failed_per_page
20
+ @failed_per_page = if params[:class]
21
+ failed_size
22
+ else
23
+ 20
24
+ end
25
+ end
26
+
27
+ def failed_start_at
28
+ params[:start].to_i
29
+ end
30
+
31
+ def failed_end_at
32
+ if failed_start_at + failed_per_page > failed_size
33
+ failed_size
34
+ else
35
+ failed_start_at + failed_per_page
36
+ end
37
+ end
38
+
39
+ def failed_class_counts(queue = params[:queue])
40
+ classes = Hash.new(0)
41
+ Resque::Failure.each(0, Resque::Failure.count(queue), queue) do |_, item|
42
+ class_name = item['payload']['class'] if item['payload']
43
+ class_name ||= "nil"
44
+ classes[class_name] += 1
45
+ end
46
+ classes
47
+ end
48
+ end
@@ -67,21 +67,21 @@
67
67
  * @param {Boolean} Include the time in the output
68
68
  */
69
69
  distanceOfTimeInWords: function(fromTime, toTime, includeTime) {
70
- var delta = parseInt((toTime.getTime() - fromTime.getTime()) / 1000);
70
+ var delta = parseInt((toTime.getTime() - fromTime.getTime()) / 1000, 10);
71
71
  if (delta < 60) {
72
72
  return 'just now';
73
73
  } else if (delta < 120) {
74
74
  return 'about a minute ago';
75
75
  } else if (delta < (45*60)) {
76
- return (parseInt(delta / 60)).toString() + ' minutes ago';
76
+ return (parseInt(delta / 60, 10)).toString() + ' minutes ago';
77
77
  } else if (delta < (120*60)) {
78
78
  return 'about an hour ago';
79
79
  } else if (delta < (24*60*60)) {
80
- return 'about ' + (parseInt(delta / 3600)).toString() + ' hours ago';
80
+ return 'about ' + (parseInt(delta / 3600, 10)).toString() + ' hours ago';
81
81
  } else if (delta < (48*60*60)) {
82
82
  return '1 day ago';
83
83
  } else {
84
- var days = (parseInt(delta / 86400)).toString();
84
+ var days = (parseInt(delta / 86400, 10)).toString();
85
85
  if (days > 5) {
86
86
  var fmt = '%B %d, %Y'
87
87
  if (includeTime) fmt += ' %I:%M %p'
@@ -41,10 +41,15 @@ $(function() {
41
41
  $("#main").addClass('polling')
42
42
 
43
43
  setInterval(function() {
44
- $.ajax({dataType: 'text', type: 'get', url: href, success: function(data) {
45
- $('#main').html(data)
46
- $('#main .time').relatizeDate()
47
- }})
44
+ $.ajax({dataType: 'text', type: 'get', url: href,
45
+ success: function(data) {
46
+ $('#main').html(data)
47
+ $('#main .time').relatizeDate()
48
+ },
49
+ error: function(data) {
50
+ if (data.status == '401') { window.location.href = '/' }
51
+ }
52
+ })
48
53
  }, poll_interval * 1000)
49
54
 
50
55
  return false
@@ -23,7 +23,7 @@ body { padding:0; margin:0; }
23
23
  #main h2 { margin:10px 0; font-size:130%;}
24
24
  #main table { width:100%; margin:10px 0;}
25
25
  #main table tr td, #main table tr th { border:1px solid #ccc; padding:6px;}
26
- #main table tr th { background:#efefef; color:#888; font-size:80%; font-weight:bold;}
26
+ #main table tr th { background:#efefef; color:#888; font-size:15px; font-weight:bold;}
27
27
  #main table tr td.no-data { text-align:center; padding:40px 0; color:#999; font-style:italic; font-size:130%;}
28
28
  #main a { color:#111;}
29
29
  #main p { margin:5px 0;}
@@ -33,9 +33,9 @@ body { padding:0; margin:0; }
33
33
 
34
34
  #main table.queues { width:40%;}
35
35
  #main table.queues td.queue { font-weight:bold; width:50%;}
36
- #main table.queues tr.failed td { border-top:2px solid; font-size:90%; }
37
- #main table.queues tr.failure td { background:#ffecec; border-top:2px solid #d37474; font-size:90%; color:#d37474;}
36
+ #main table.queues tr.failure td { background:#ffecec; font-size:90%; color:#d37474;}
38
37
  #main table.queues tr.failure td a{ color:#d37474;}
38
+ #main table.queues tr.first_failure td { border-top:2px solid #d37474; }
39
39
 
40
40
  #main table.jobs td.class { font-family:Monaco, "Courier New", monospace; font-size:90%; width:50%;}
41
41
  #main table.jobs td.args{ width:50%;}
@@ -45,6 +45,7 @@ body { padding:0; margin:0; }
45
45
  #main table.workers td.where { width:25%;}
46
46
  #main table.workers td.queues { width:35%;}
47
47
  #main .queue-tag { background:#b1d2e9; padding:2px; margin:0 3px; font-size:80%; text-decoration:none; text-transform:uppercase; font-weight:bold; color:#3274a2; -webkit-border-radius:4px; -moz-border-radius:4px;}
48
+ #main .queue-tag a { color: #3274A2; text-decoration: none; }
48
49
  #main table.workers td.queues.queue { width:10%;}
49
50
  #main table.workers td.process { width:35%;}
50
51
  #main table.workers td.process span.waiting { color:#999; font-size:90%;}
@@ -83,4 +84,8 @@ body { padding:0; margin:0; }
83
84
 
84
85
  #main form {float:right; margin-top:-10px;margin-left:10px;}
85
86
 
86
- #main .time a.toggle_format {text-decoration:none;}
87
+ #main .time a.toggle_format {text-decoration:none;}
88
+
89
+ #failed tr.total td {background-color: #FFECEC; color: #D37474; font-size: 15px; font-weight: bold;}
90
+ #failed .center {text-align: center;}
91
+ #failed .failed_class { padding-left: 20px; font-size:12px; }
@@ -1,67 +1,28 @@
1
- <%start = params[:start].to_i %>
2
- <%failed = Resque::Failure.all(start, 20)%>
3
- <% index = 0 %>
4
- <% date_format = "%Y/%m/%d %T %z" %>
1
+ <% if failed_multiple_queues? && !params[:queue] %>
2
+ <h1>All Failed Queues: <%= Resque::Failure.queues.size %> total</h1>
3
+ <% else %>
4
+ <h1>Failed Jobs <%= "on '#{params[:queue]}'" if params[:queue] %> <%= "with class '#{params[:class]}'" if params[:class] %></h1>
5
+ <% end %>
5
6
 
6
- <h1>Failed Jobs</h1>
7
- <%unless failed.empty?%>
8
- <form method="POST" action="<%=u 'failed/clear'%>">
9
- <input type='submit' name='' value='Clear Failed Jobs' />
7
+ <% unless failed_size.zero? %>
8
+ <form method="POST" action="<%= u "failed#{'/' + params[:queue] if params[:queue]}/clear" %>">
9
+ <input type="submit" name="" value="Clear <%= params[:queue] ? "'#{params[:queue]}'" : 'Failed' %> Jobs" />
10
10
  </form>
11
- <form method="POST" action="<%=u 'failed/requeue/all'%>">
12
- <input type='submit' name='' value='Retry Failed Jobs' />
11
+ <form method="POST" action="<%= u "failed#{'/' + params[:queue] if params[:queue]}/requeue/all" %>">
12
+ <input type="submit" name="" value="Retry <%= params[:queue] ? "'#{params[:queue]}'" : 'Failed' %> Jobs" />
13
13
  </form>
14
- <%end%>
14
+ <% end %>
15
15
 
16
- <p class='sub'>Showing <%=start%> to <%= start + 20 %> of <b><%= size = Resque::Failure.count %></b> jobs</p>
16
+ <% if failed_multiple_queues? && !params[:queue] %>
17
+ <%= partial :failed_queues_overview %>
18
+ <% else %>
19
+ <p class='sub'>Showing <%= failed_start_at %> to <%= failed_end_at %> of <b><%= failed_size %></b> jobs</p>
17
20
 
18
21
  <ul class='failed'>
19
- <%for job in failed%>
20
- <% index += 1 %>
21
- <li>
22
- <dl>
23
- <% if job.nil? %>
24
- <dt>Error</dt>
25
- <dd>Job <%= index%> could not be parsed; perhaps it contains invalid JSON?</dd>
26
- <% else %>
27
- <dt>Worker</dt>
28
- <dd>
29
- <a href="<%= u(:workers, job['worker']) %>"><%= job['worker'].split(':')[0...2].join(':') %></a> on <b class='queue-tag'><%= job['queue'] %></b > at <b><span class="time"><%= Time.parse(job['failed_at']).strftime(date_format) %></span></b>
30
- <% if job['retried_at'] %>
31
- <div class='retried'>
32
- Retried <b><span class="time"><%= Time.parse(job['retried_at']).strftime(date_format) %></span></b>
33
- <a href="<%= u "failed/remove/#{start + index - 1}" %>" class="remove" rel="remove">Remove</a>
34
- </div>
35
- <% else %>
36
- <div class='controls'>
37
- <a href="<%= u "failed/requeue/#{start + index - 1}" %>" rel="retry">Retry</a>
38
- or
39
- <a href="<%= u "failed/remove/#{start + index - 1}" %>" rel="remove">Remove</a>
40
- </div>
41
- <% end %>
42
- </dd>
43
- <dt>Class</dt>
44
- <dd><code><%= job['payload'] ? job['payload']['class'] : 'nil' %></code></dd>
45
- <dt>Arguments</dt>
46
- <dd><pre><%=h job['payload'] ? show_args(job['payload']['args']) : 'nil' %></pre></dd>
47
- <dt>Exception</dt>
48
- <dd><code><%= job['exception'] %></code></dd>
49
- <dt>Error</dt>
50
- <dd class='error'>
51
- <% if job['backtrace'] %>
52
- <a href="#" class="backtrace"><%= h(job['error']) %></a>
53
- <pre style='display:none'><%=h job['backtrace'].join("\n") %></pre>
54
- <% else %>
55
- <%=h job['error'] %>
56
- <% end %>
57
- </dd>
58
- <% end %>
59
- </dl>
60
- <div class='r'>
61
- </div>
62
- </li>
63
- <%end%>
22
+ <% Resque::Failure.each(failed_start_at, failed_per_page, params[:queue], params[:class]) do |id, job| %>
23
+ <%= partial :failed_job, :id => id, :job => job %>
24
+ <% end %>
64
25
  </ul>
65
26
 
66
- <%= partial :next_more, :start => start, :size => size %>
67
-
27
+ <%= partial :next_more, :start => failed_start_at, :size => failed_size unless params[:class] %>
28
+ <% end %>
@@ -0,0 +1,50 @@
1
+ <li>
2
+ <dl>
3
+ <% if job.nil? %>
4
+ <dt>Error</dt>
5
+ <dd>Job <%= id %> could not be parsed; perhaps it contains invalid JSON?</dd>
6
+ <% else %>
7
+ <dt>Worker</dt>
8
+ <dd>
9
+ <a href="<%= u(:workers, job['worker']) %>"><%= job['worker'].split(':')[0...2].join(':') %></a> on <b class='queue-tag'><%= job['queue'] %></b > at <b><span class="time"><%= Time.parse(job['failed_at']).strftime(failed_date_format) %></span></b>
10
+ <% if job['retried_at'] %>
11
+ <div class='retried'>
12
+ Retried <b><span class="time"><%= Time.parse(job['retried_at']).strftime(failed_date_format) %></span></b>
13
+ <a href="<%= u "failed/remove/#{id}" %>" class="remove" rel="remove">Remove</a>
14
+ </div>
15
+ <% else %>
16
+ <div class='controls'>
17
+ <a href="<%= u "failed/requeue/#{id}" %>" rel="retry">Retry</a>
18
+ or
19
+ <a href="<%= u "failed/remove/#{id}" %>" rel="remove">Remove</a>
20
+ </div>
21
+ <% end %>
22
+ </dd>
23
+ <dt>Class</dt>
24
+ <dd>
25
+ <% if job['payload'] && job['payload']['class'] %>
26
+ <a href="<%= u "failed/#{params[:queue]}?class=#{job['payload']['class']}" %>">
27
+ <code><%= job['payload']['class'] %></code>
28
+ </a>
29
+ <% else %>
30
+ <code>nil</code>
31
+ <% end %>
32
+ </dd>
33
+ <dt>Arguments</dt>
34
+ <dd><pre><%=h job['payload'] ? show_args(job['payload']['args']) : 'nil' %></pre></dd>
35
+ <dt>Exception</dt>
36
+ <dd><code><%= job['exception'] %></code></dd>
37
+ <dt>Error</dt>
38
+ <dd class='error'>
39
+ <% if job['backtrace'] %>
40
+ <a href="#" class="backtrace"><%= h(job['error']) %></a>
41
+ <pre style='display:none'><%=h job['backtrace'].join("\n") %></pre>
42
+ <% else %>
43
+ <%=h job['error'] %>
44
+ <% end %>
45
+ </dd>
46
+ <% end %>
47
+ </dl>
48
+ <div class='r'>
49
+ </div>
50
+ </li>
@@ -0,0 +1,24 @@
1
+ <table id="failed">
2
+ <tbody>
3
+ <tr class="total">
4
+ <td class='queue'>Total Failed</td>
5
+ <td class='center'><%= Resque::Failure.count %></td>
6
+ </tr>
7
+
8
+ <% Resque::Failure.queues.sort.each do |queue| %>
9
+ <tr>
10
+ <th><b class="queue-tag"><a href="/failed/<%= queue %>"><%= queue %></a></b></th>
11
+ <th style="width:75px;" class="center"><%= Resque::Failure.count(queue) %></th>
12
+ </tr>
13
+
14
+ <% failed_class_counts(queue).sort_by { |name,_| name }.each do |k, v| %>
15
+ <tr id="<%= k %>">
16
+ <td>
17
+ <a href="/failed/<%= "#{queue}?class=#{k}" %>"><span class="failed failed_class"><%= k %></span></a>
18
+ </td>
19
+ <td style="text-align: center;" class="failed<%= (v.to_i > 1000) ? '_many' : '' %>"><%= v %></td>
20
+ </tr>
21
+ <% end %>
22
+ <% end %>
23
+ </tbody>
24
+ </table>
@@ -34,16 +34,25 @@
34
34
  <th>Name</th>
35
35
  <th>Jobs</th>
36
36
  </tr>
37
- <% for queue in resque.queues.sort_by { |q| q.to_s } %>
37
+ <% resque.queues.sort_by { |q| q.to_s }.each do |queue| %>
38
38
  <tr>
39
39
  <td class='queue'><a class="queue" href="<%= u "queues/#{queue}" %>"><%= queue %></a></td>
40
40
  <td class='size'><%= resque.size queue %></td>
41
41
  </tr>
42
42
  <% end %>
43
- <tr class="<%= Resque::Failure.count.zero? ? "failed" : "failure" %>">
44
- <td class='queue failed'><a class="queue" href="<%= u :failed %>">failed</a></td>
45
- <td class='size'><%= Resque::Failure.count %></td>
46
- </tr>
43
+ <% if failed_multiple_queues? %>
44
+ <% Resque::Failure.queues.sort_by { |q| q.to_s }.each_with_index do |queue, i| %>
45
+ <tr class="<%= Resque::Failure.count(queue).zero? ? "failed" : "failure" %><%= " first_failure" if i.zero? %>">
46
+ <td class='queue failed'><a class="queue" href="<%= u "failed/#{queue}" %>"><%= queue %></a></td>
47
+ <td class='size'><%= Resque::Failure.count(queue) %></td>
48
+ </tr>
49
+ <% end %>
50
+ <% else %>
51
+ <tr class="<%= Resque::Failure.count.zero? ? "failed" : "failure" %>">
52
+ <td class='queue failed'><a class="queue" href="<%= u :failed %>">failed</a></td>
53
+ <td class='size'><%= Resque::Failure.count %></td>
54
+ </tr>
55
+ <% end %>
47
56
  </table>
48
57
 
49
58
  <% end %>
@@ -12,8 +12,12 @@ namespace :resque do
12
12
 
13
13
  begin
14
14
  worker = Resque::Worker.new(*queues)
15
- worker.verbose = ENV['LOGGING'] || ENV['VERBOSE']
16
- worker.very_verbose = ENV['VVERBOSE']
15
+ if ENV['LOGGING'] || ENV['VERBOSE']
16
+ worker.verbose = ENV['LOGGING'] || ENV['VERBOSE']
17
+ end
18
+ if ENV['VVERBOSE']
19
+ worker.very_verbose = ENV['VVERBOSE']
20
+ end
17
21
  worker.term_timeout = ENV['RESQUE_TERM_TIMEOUT'] || 4.0
18
22
  worker.term_child = ENV['TERM_CHILD']
19
23
  rescue Resque::NoQueueError
@@ -60,4 +64,19 @@ namespace :resque do
60
64
  Rails::Initializer.run :load_application_classes
61
65
  end
62
66
  end
67
+
68
+ namespace :failures do
69
+ desc "Sort the 'failed' queue for the redis_multi_queue failure backend"
70
+ task :sort do
71
+ require 'resque'
72
+ require 'resque/failure/redis'
73
+
74
+ warn "Sorting #{Resque::Failure.count} failures..."
75
+ Resque::Failure.each(0, Resque::Failure.count) do |_, failure|
76
+ data = Resque.encode(failure)
77
+ Resque.redis.rpush(Resque::Failure.failure_queue_name(failure['queue']), data)
78
+ end
79
+ warn "done!"
80
+ end
81
+ end
63
82
  end