1
0
Fork 0
mirror of https://github.com/mperham/sidekiq.git synced 2022-11-09 13:52:34 -05:00

Add /retries page with bulk operations, trim long arguments #184

This commit is contained in:
Mike Perham 2012-05-11 16:48:03 -07:00
parent 8ce3cb2eba
commit 10b4caf973
9 changed files with 135 additions and 30 deletions

View file

@ -1,3 +1,8 @@
1.2.1
-----------
- Overhaul retries Web UI with new index page and bulk operations #184
1.2.0
-----------

View file

@ -61,15 +61,15 @@ module Sidekiq
Sidekiq.redis { |conn| conn.zcard('retry') }
end
def retries
def retries(count=50)
Sidekiq.redis do |conn|
results = conn.zrange('retry', 0, 25, :withscores => true)
results = conn.zrange('retry', 0, count, :withscores => true)
results.each_slice(2).map { |msg, score| [Sidekiq.load_json(msg), Float(score)] }
end
end
def queues
Sidekiq.redis do |conn|
@queues ||= Sidekiq.redis do |conn|
conn.smembers('queues').map do |q|
[q, conn.llen("queue:#{q}") || 0]
end.sort { |x,y| x[1] <=> y[1] }
@ -99,6 +99,10 @@ module Sidekiq
def relative_time(time)
%{<time datetime="#{time.getutc.iso8601}">#{time}</time>}
end
def display_args(args, count=100)
args.map { |arg| a = arg.inspect; a.size > count ? "#{a[0..count]}..." : a }.join(", ")
end
end
get "/" do
@ -125,14 +129,42 @@ module Sidekiq
halt 404 unless params[:score]
@score = params[:score].to_f
@retries = retries_with_score(@score)
redirect root_path if @retries.empty?
redirect "#{root_path}retries" if @retries.empty?
slim :retry
end
get '/retries' do
@retries = retries
slim :retries
end
post '/retries' do
halt 404 unless params[:score]
params[:score].each do |score|
s = score.to_f
if params['retry']
process_score(s, :retry)
elsif params['delete']
process_score(s, :delete)
end
end
redirect root_path
end
post "/retries/:score" do
halt 404 unless params[:score]
score = params[:score].to_f
if params['retry']
process_score(score, :retry)
elsif params['delete']
process_score(score, :delete)
end
redirect root_path
end
def process_score(score, operation)
case operation
when :retry
Sidekiq.redis do |conn|
results = conn.zrangebyscore('retry', score, score)
conn.zremrangebyscore('retry', score, score)
@ -141,13 +173,13 @@ module Sidekiq
conn.rpush("queue:#{msg['queue']}", message)
end
end
elsif params['delete']
when :delete
Sidekiq.redis do |conn|
conn.zremrangebyscore('retry', score, score)
end
end
redirect root_path
end
end
end

View file

@ -45,6 +45,7 @@ class TestWeb < MiniTest::Unit::TestCase
assert_match last_response.body, /Sidekiq is idle/
assert_match last_response.body, /default/
assert_match last_response.body, /foo/
assert_match last_response.body, /Backlog: 2/
end
it 'handles queues with no name' do
@ -78,5 +79,44 @@ class TestWeb < MiniTest::Unit::TestCase
refute conn.smembers('queues').include?('foo')
end
end
it 'can display retries' do
get '/retries'
assert_equal 200, last_response.status
assert_match last_response.body, /found/
refute_match last_response.body, /HardWorker/
add_retry
get '/retries'
assert_equal 200, last_response.status
refute_match last_response.body, /found/
assert_match last_response.body, /HardWorker/
end
it 'can display a single retry' do
get '/retries/12938712.123333'
assert_equal 302, last_response.status
_, score = add_retry
get "/retries/#{score}"
assert_equal 200, last_response.status
assert_match last_response.body, /HardWorker/
end
def add_retry
msg = { 'class' => 'HardWorker',
'args' => ['bob', 1, Time.now.to_f],
'queue' => 'default',
'error_message' => 'Some fake message',
'error_class' => 'RuntimeError',
'retry_count' => 0,
'failed_at' => Time.now.utc, }
score = Time.now.to_f
Sidekiq.redis do |conn|
conn.zadd('retry', score, Sidekiq.dump_json(msg))
end
[msg, score]
end
end
end

View file

@ -3,7 +3,18 @@
//= require bootstrap
//= require_tree .
jQuery(document).ready(function() {
jQuery.timeago.settings.allowFuture = true
jQuery("time").timeago();
$(function() {
$.timeago.settings.allowFuture = true
$("time").timeago();
});
$(function() {
$('.check_all').live('click', function() {
var checked = $(this).attr('checked');
if (checked == 'checked') {
$('input[type=checkbox]', $(this).closest('table')).attr('checked', checked);
} else {
$('input[type=checkbox]', $(this).closest('table')).removeAttr('checked');
}
});
});

View file

@ -21,3 +21,7 @@ code {
border: 0;
background-color: inherit;
}
.hero-unit {
padding: 30px;
}

View file

@ -5,6 +5,7 @@
p Failed: #{failed}
p Busy Workers: #{workers.size}
p Retries Pending: #{retry_count}
p Queue Backlog: #{queues.map{|q,size| size}.sum}
.tabbable
ul.nav.nav-tabs
@ -12,8 +13,6 @@
a href="#workers" data-toggle="tab" Busy Workers
li
a href="#queues" data-toggle="tab" Queues
li
a href="#retries" data-toggle="tab" Retries
.tab-content
#workers.tab-pane.active
table class="table table-striped table-bordered"
@ -46,21 +45,4 @@
form action="#{root_path}queues/#{queue}" method="post"
input.btn.btn-danger type="submit" name="delete" value="Delete"
#retries.tab-pane
table class="table table-striped table-bordered"
tr
th Next Retry
th Retry Count
th Queue
th Worker
th Args
- retries.each do |(msg, score)|
tr
td
a href="retries/#{score}"== relative_time(Time.at(score))
td= msg['retry_count']
td
a href="queues/#{msg['queue']}" #{msg['queue']}
td= msg['class']
td= msg['args'].inspect[0..100]

View file

@ -12,6 +12,8 @@ html
ul.nav
li
a href='#{{root_path}}' Home
li
a href='#{{root_path}}retries' Retries
ul.nav.pull-right
li
a Redis: #{location}

29
web/views/retries.slim Normal file
View file

@ -0,0 +1,29 @@
h1 Retries
- if @retries.size > 0
form action="#{root_path}retries" method="post"
table class="table table-striped table-bordered"
tr
th
input type="checkbox" class="check_all"
th Next Retry
th Retry Count
th Queue
th Worker
th Args
- @retries.each do |(msg, score)|
tr
td
input type='checkbox' name='score[]' value='#{score}'
td
a href="#{root_path}retries/#{score}"== relative_time(Time.at(score))
td= msg['retry_count']
td
a href="#{root_path}queues/#{msg['queue']}" #{msg['queue']}
td= msg['class']
td= display_args(msg['args'])
input.btn.btn-primary type="submit" name="retry" value="Retry Now"
input.btn.btn-danger type="submit" name="delete" value="Delete"
- else
p No retries found.
a href="#{root_path}" Back

View file

@ -15,7 +15,7 @@ header
tr
th Job Arguments
td
code= msg['args'].inspect[0..1000]
code= display_args(msg['args'], 1000)
- if msg['retry_count'] > 0
tr
th Retry Count
@ -47,6 +47,6 @@ header
td
code== msg['error_backtrace'].join("<br/>")
form.form-horizontal action="#{root_path}retries/#{@score}" method="post"
a.btn href="#{root_path}" &larr; Back
a.btn href="#{root_path}retries" &larr; Back
input.btn.btn-primary type="submit" name="retry" value="Retry Now"
input.btn.btn-danger type="submit" name="delete" value="Delete"