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:
parent
8ce3cb2eba
commit
10b4caf973
9 changed files with 135 additions and 30 deletions
|
@ -1,3 +1,8 @@
|
|||
1.2.1
|
||||
-----------
|
||||
|
||||
- Overhaul retries Web UI with new index page and bulk operations #184
|
||||
|
||||
1.2.0
|
||||
-----------
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -21,3 +21,7 @@ code {
|
|||
border: 0;
|
||||
background-color: inherit;
|
||||
}
|
||||
|
||||
.hero-unit {
|
||||
padding: 30px;
|
||||
}
|
||||
|
|
|
@ -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]
|
||||
|
||||
|
|
|
@ -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
29
web/views/retries.slim
Normal 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
|
|
@ -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}" ← Back
|
||||
a.btn href="#{root_path}retries" ← Back
|
||||
input.btn.btn-primary type="submit" name="retry" value="Retry Now"
|
||||
input.btn.btn-danger type="submit" name="delete" value="Delete"
|
||||
|
|
Loading…
Reference in a new issue