From d8cd87aa1ea0ad4a06378748e85898587a00a5f4 Mon Sep 17 00:00:00 2001 From: Jonathan Hyman Date: Thu, 25 Jul 2013 18:36:23 -0400 Subject: [PATCH 1/7] No longer truncates arguments in sidekiq-web, instead uses overflow: scroll to let you see them. --- Changes.md | 1 + web/assets/stylesheets/application.css | 6 +++++- web/views/retries.slim | 3 ++- web/views/retry.slim | 3 ++- web/views/scheduled.slim | 3 ++- 5 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Changes.md b/Changes.md index 7c3782b1..da893189 100644 --- a/Changes.md +++ b/Changes.md @@ -1,6 +1,7 @@ 2.13.1 ----------- - Make summary bar and graphs responsive [manishval] [#1025] +- No longer truncates args in sidekiq-web, instead sets `overflow: scroll` [jonhyman] 2.13.0 ----------- diff --git a/web/assets/stylesheets/application.css b/web/assets/stylesheets/application.css index 62d2b058..6b68b0cd 100755 --- a/web/assets/stylesheets/application.css +++ b/web/assets/stylesheets/application.css @@ -844,4 +844,8 @@ img.smallogo { .rickshaw_legend li:active { background: rgba(255, 255, 255, 0.2); border-radius: 3px; -} \ No newline at end of file +} +.args { + overflow: scroll; + max-height: 100px; +} diff --git a/web/views/retries.slim b/web/views/retries.slim index 44649985..f43d8203 100644 --- a/web/views/retries.slim +++ b/web/views/retries.slim @@ -27,7 +27,8 @@ header.row td a href="#{root_path}queues/#{msg['queue']}" #{msg['queue']} td= msg['class'] - td= display_args(msg['args']) + td + div.args=display_args(msg['args']) input.btn.btn-primary.btn-small.pull-left type="submit" name="retry" value="#{t('RetryNow')}" input.btn.btn-danger.btn-small.pull-left type="submit" name="delete" value="#{t('Delete')}" diff --git a/web/views/retry.slim b/web/views/retry.slim index f64687b5..dd289467 100644 --- a/web/views/retry.slim +++ b/web/views/retry.slim @@ -14,7 +14,8 @@ table class="retry table table-bordered table-striped" tr th = t('Arguments') td - code= display_args(@retry['args'], 1000) + code + div.args=display_args(@retry['args']) tr th JID td diff --git a/web/views/scheduled.slim b/web/views/scheduled.slim index 1108497f..3218d5ae 100644 --- a/web/views/scheduled.slim +++ b/web/views/scheduled.slim @@ -24,7 +24,8 @@ header.row td a href="#{root_path}queues/#{msg['queue']}" #{msg['queue']} td= msg['class'] - td= display_args(msg['args']) + td + div.args=display_args(msg['args']) input.btn.btn-danger.pull-right type="submit" name="delete" value="#{t('Delete')}" input.btn.btn-danger.pull-right type="submit" name="add_to_queue" value="#{t('AddToQueue')}" - else From 6ce788b1210ebc9703b79780ae47ea9a48e2fd28 Mon Sep 17 00:00:00 2001 From: Jonathan Hyman Date: Thu, 25 Jul 2013 18:40:54 -0400 Subject: [PATCH 2/7] Actually remove the truncation. --- lib/sidekiq/web.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/sidekiq/web.rb b/lib/sidekiq/web.rb index f5da21b8..fd82b103 100644 --- a/lib/sidekiq/web.rb +++ b/lib/sidekiq/web.rb @@ -107,10 +107,9 @@ module Sidekiq [score.to_f, jid] end - def display_args(args, count=100) + def display_args(args) args.map do |arg| - a = arg.inspect - a.size > count ? "#{a[0..count]}..." : a + arg.inspect end.join(", ") end From 5e9bfa7ab73050326db8277c1754a6840058fe6f Mon Sep 17 00:00:00 2001 From: Jonathan Hyman Date: Sat, 27 Jul 2013 12:49:21 -0400 Subject: [PATCH 3/7] Adds a job status page for scheduled jobs; partially reverts 6ce788b1210ebc9703b79780ae47ea9a48e2fd28 which removed arg truncation from overview pages. --- Changes.md | 2 +- Contributing.md | 1 + config.ru | 19 +++++++--- lib/sidekiq/web.rb | 23 +++++++++++- web/assets/stylesheets/application.css | 4 ++ web/views/_job_info.slim | 51 ++++++++++++++++++++++++++ web/views/retry.slim | 46 +---------------------- web/views/scheduled.slim | 3 +- web/views/scheduled_job_info.slim | 6 +++ 9 files changed, 101 insertions(+), 54 deletions(-) create mode 100644 web/views/_job_info.slim create mode 100644 web/views/scheduled_job_info.slim diff --git a/Changes.md b/Changes.md index da893189..04d09f22 100644 --- a/Changes.md +++ b/Changes.md @@ -1,7 +1,7 @@ 2.13.1 ----------- - Make summary bar and graphs responsive [manishval] [#1025] -- No longer truncates args in sidekiq-web, instead sets `overflow: scroll` [jonhyman] +- Adds a job status page for scheduled jobs [jonhyman] 2.13.0 ----------- diff --git a/Contributing.md b/Contributing.md index fe79dc2d..26fa98df 100644 --- a/Contributing.md +++ b/Contributing.md @@ -10,6 +10,7 @@ If you're interested in helping or contributing to Sidekiq, here's some known areas which need improvement: * The Web UI and sidekiq.org website could always use more polish. If you have an eye for design and an idea for improvement, please open an issue and let us know. + * The config.ru file in this project has code you can use to populate the Web UI. * The Sidekiq API has a serious issue: deleting elements and iterating at the same time is broken, see #866, #1060. * Make normal testing and inline testing dynamic: #1053 diff --git a/config.ru b/config.ru index e46cb222..79b61380 100644 --- a/config.ru +++ b/config.ru @@ -4,15 +4,24 @@ Sidekiq.configure_client do |config| config.redis = { :size => 1 } end +# Uncomment this to populate sidekiq-web with some fake data +# +#require 'multi_json' +#class TestDelayExtensionJob +# def self.test(*args) +# end +#end #Sidekiq.redis {|conn| conn.flushdb } #10.times do |idx| - #Sidekiq::Client.push('class' => 'HardWorker', 'args' => ['foo', 0.1, idx]) +# Sidekiq::Client.push('class' => 'HardWorker', 'args' => ['foo', 0.1, idx]) +# Sidekiq::Client.push('class' => 'HardWorker', 'args' => ['foo', 0.1, idx], 'at' => (Time.now + Random.rand(10000)).to_f) +# TestDelayExtensionJob.delay_for(1000).test("arg0") #end - +# #Sidekiq.redis { |conn| conn.zadd('retry', Time.now.utc.to_f + 3000, MultiJson.encode({ - #'class' => 'HardWorker', 'args' => ['foo', 0.1, Time.now.to_f], - #'queue' => 'default', 'error_message' => 'No such method', 'error_class' => 'NoMethodError', - #'failed_at' => Time.now.utc, 'retry_count' => 0 })) } +# 'class' => 'HardWorker', 'args' => ['foo', 0.1, Time.now.to_f], +# 'queue' => 'default', 'error_message' => 'No such method', 'error_class' => 'NoMethodError', +# 'failed_at' => Time.now.utc, 'retry_count' => 0 })) } require 'sidekiq/web' run Sidekiq::Web diff --git a/lib/sidekiq/web.rb b/lib/sidekiq/web.rb index fd82b103..6433474f 100644 --- a/lib/sidekiq/web.rb +++ b/lib/sidekiq/web.rb @@ -107,9 +107,10 @@ module Sidekiq [score.to_f, jid] end - def display_args(args) + def display_args(args, truncate_after_chars = 2000) args.map do |arg| - arg.inspect + a = arg.inspect + truncate_after_chars && a.size > truncate_after_chars ? "#{a[0..truncate_after_chars]}..." : a end.join(", ") end @@ -248,6 +249,13 @@ module Sidekiq slim :scheduled end + get "/scheduled/:key" do + halt 404 unless params['key'] + @job = Sidekiq::ScheduledSet.new.fetch(*parse_params(params['key'])).first + redirect "#{root_path}scheduled" if @job.nil? + slim :scheduled_job_info + end + post '/scheduled' do halt 404 unless params['key'] @@ -262,6 +270,17 @@ module Sidekiq redirect "#{root_path}scheduled" end + post "/scheduled/:key" do + halt 404 unless params['key'] + job = Sidekiq::ScheduledSet.new.fetch(*parse_params(params['key'])).first + if params['add_to_queue'] + job.add_to_queue + elsif params['delete'] + job.delete + end + redirect "#{root_path}scheduled" + end + get '/' do @redis_info = Sidekiq.redis { |conn| conn.info }.select{ |k, v| redis_keys.include? k } stats_history = Sidekiq::Stats::History.new((params[:days] || 30).to_i) diff --git a/web/assets/stylesheets/application.css b/web/assets/stylesheets/application.css index 6b68b0cd..7705e19c 100755 --- a/web/assets/stylesheets/application.css +++ b/web/assets/stylesheets/application.css @@ -849,3 +849,7 @@ img.smallogo { overflow: scroll; max-height: 100px; } +.args-extended { + overflow: scroll; + max-height: 500px; +} diff --git a/web/views/_job_info.slim b/web/views/_job_info.slim new file mode 100644 index 00000000..48ea3442 --- /dev/null +++ b/web/views/_job_info.slim @@ -0,0 +1,51 @@ +header + h3 = t('Job') + +table class="table table-bordered table-striped" + tbody + tr + th = t('Queue') + td + a href="#{root_path}queues/#{job['queue']}" #{job['queue']} + tr + th = t('Class') + td + code= job['class'] + tr + th = t('Arguments') + td + code + // We don't want to truncate any job arguments when viewing a single job's status page + div.args-extended=display_args(job['args'], nil) + tr + th JID + td + code= job.jid + tr + th = t('Enqueued') + td== relative_time(job.enqueued_at) + - unless retry_extra_items(job).empty? + tr + th = t('Extras') + td + code + = retry_extra_items(job).inspect + - if type == :retry + - if job['retry_count'] && job['retry_count'] > 0 + tr + th = t('RetryCount') + td= job['retry_count'] + tr + th = t('LastRetry') + td== relative_time(job['retried_at'].is_a?(Numeric) ? Time.at(job['retried_at']) : Time.parse(job['retried_at'])) + - else + tr + th = t('OriginallyFailed') + td== relative_time(job['failed_at'].is_a?(Numeric) ? Time.at(job['failed_at']) : Time.parse(job['failed_at'])) + tr + th = t('NextRetry') + td== relative_time(job.at) + - if type == :scheduled + tr + th = t('Scheduled') + td== relative_time(job.at) diff --git a/web/views/retry.slim b/web/views/retry.slim index dd289467..1954094a 100644 --- a/web/views/retry.slim +++ b/web/views/retry.slim @@ -1,48 +1,4 @@ -header - h3 = t('Job') - -table class="retry table table-bordered table-striped" - tbody - tr - th = t('Queue') - td - a href="#{root_path}queues/#{@retry['queue']}" #{@retry['queue']} - tr - th = t('Class') - td - code= @retry['class'] - tr - th = t('Arguments') - td - code - div.args=display_args(@retry['args']) - tr - th JID - td - code= @retry.jid - tr - th = t('Enqueued') - td== relative_time(@retry.enqueued_at) - - unless retry_extra_items(@retry).empty? - tr - th = t('Extras') - td - code - = retry_extra_items(@retry).inspect - - if @retry['retry_count'] > 0 - tr - th = t('RetryCount') - td= @retry['retry_count'] - tr - th = t('LastRetry') - td== relative_time(@retry['retried_at'].is_a?(Numeric) ? Time.at(@retry['retried_at']) : Time.parse(@retry['retried_at'])) - - else - tr - th = t('OriginallyFailed') - td== relative_time(@retry['failed_at'].is_a?(Numeric) ? Time.at(@retry['failed_at']) : Time.parse(@retry['failed_at'])) - tr - th = t('NextRetry') - td== relative_time(@retry.at) +== slim :_job_info, :locals => {:job => @retry, :type => :retry} h3 = t('Error') table class="error table table-bordered table-striped" diff --git a/web/views/scheduled.slim b/web/views/scheduled.slim index 3218d5ae..e8b5dcd2 100644 --- a/web/views/scheduled.slim +++ b/web/views/scheduled.slim @@ -20,7 +20,8 @@ header.row tr td input type='checkbox' name='key[]' value='#{job_params(msg, score)}' - td== relative_time(Time.at(score)) + td + a href="#{root_path}scheduled/#{job_params(msg, score)}"== relative_time(Time.at(score)) td a href="#{root_path}queues/#{msg['queue']}" #{msg['queue']} td= msg['class'] diff --git a/web/views/scheduled_job_info.slim b/web/views/scheduled_job_info.slim new file mode 100644 index 00000000..0970dc54 --- /dev/null +++ b/web/views/scheduled_job_info.slim @@ -0,0 +1,6 @@ +== slim :_job_info, :locals => {:job => @job, :type => :scheduled} + +form.form-horizontal action="#{root_path}scheduled/#{job_params(@job, @job.score)}" method="post" + a.btn href="#{root_path}scheduled" = t('GoBack') + input.btn.btn-primary type="submit" name="add_to_queue" value="#{t('AddToQueue')}" + input.btn.btn-danger type="submit" name="delete" value="#{t('Delete')}" From 626f7f81624280f6df548e09a6ce87afbe40b352 Mon Sep 17 00:00:00 2001 From: Jonathan Hyman Date: Sat, 27 Jul 2013 18:41:14 -0400 Subject: [PATCH 4/7] Reverting contribuing.md, config.ru changes. --- Contributing.md | 1 - config.ru | 19 +++++-------------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/Contributing.md b/Contributing.md index 26fa98df..fe79dc2d 100644 --- a/Contributing.md +++ b/Contributing.md @@ -10,7 +10,6 @@ If you're interested in helping or contributing to Sidekiq, here's some known areas which need improvement: * The Web UI and sidekiq.org website could always use more polish. If you have an eye for design and an idea for improvement, please open an issue and let us know. - * The config.ru file in this project has code you can use to populate the Web UI. * The Sidekiq API has a serious issue: deleting elements and iterating at the same time is broken, see #866, #1060. * Make normal testing and inline testing dynamic: #1053 diff --git a/config.ru b/config.ru index 79b61380..403395bc 100644 --- a/config.ru +++ b/config.ru @@ -4,24 +4,15 @@ Sidekiq.configure_client do |config| config.redis = { :size => 1 } end -# Uncomment this to populate sidekiq-web with some fake data -# -#require 'multi_json' -#class TestDelayExtensionJob -# def self.test(*args) -# end -#end #Sidekiq.redis {|conn| conn.flushdb } #10.times do |idx| -# Sidekiq::Client.push('class' => 'HardWorker', 'args' => ['foo', 0.1, idx]) -# Sidekiq::Client.push('class' => 'HardWorker', 'args' => ['foo', 0.1, idx], 'at' => (Time.now + Random.rand(10000)).to_f) -# TestDelayExtensionJob.delay_for(1000).test("arg0") +#Sidekiq::Client.push('class' => 'HardWorker', 'args' => ['foo', 0.1, idx]) #end -# + #Sidekiq.redis { |conn| conn.zadd('retry', Time.now.utc.to_f + 3000, MultiJson.encode({ -# 'class' => 'HardWorker', 'args' => ['foo', 0.1, Time.now.to_f], -# 'queue' => 'default', 'error_message' => 'No such method', 'error_class' => 'NoMethodError', -# 'failed_at' => Time.now.utc, 'retry_count' => 0 })) } +#'class' => 'HardWorker', 'args' => ['foo', 0.1, Time.now.to_f], +#'queue' => 'default', 'error_message' => 'No such method', 'error_class' => 'NoMethodError', +#'failed_at' => Time.now.utc, 'retry_count' => 0 })) } require 'sidekiq/web' run Sidekiq::Web From aa8ac370f5d3d90589073a5f109e6d6338359c58 Mon Sep 17 00:00:00 2001 From: Jonathan Hyman Date: Sat, 27 Jul 2013 18:49:35 -0400 Subject: [PATCH 5/7] Adds tests for new web endpoints. --- test/test_web.rb | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/test/test_web.rb b/test/test_web.rb index d974c545..96917f15 100644 --- a/test/test_web.rb +++ b/test/test_web.rb @@ -187,6 +187,37 @@ class TestWeb < Minitest::Test assert_match /HardWorker/, last_response.body end + it 'can display a single scheduled job' do + params = add_scheduled + get '/scheduled/2c4c17969825a384a92f023b' + assert_equal 302, last_response.status + get "/scheduled/#{job_params(*params)}" + assert_equal 200, last_response.status + assert_match /HardWorker/, last_response.body + end + + it 'can add to queue a single scheduled job' do + params = add_scheduled + post "/scheduled/#{job_params(*params)}", 'add_to_queue' => true + assert_equal 302, last_response.status + assert_equal 'http://example.org/scheduled', last_response.header['Location'] + + get '/queues/default' + assert_equal 200, last_response.status + assert_match /#{params.first['args'][2]}/, last_response.body + end + + it 'can delete a single scheduled job' do + params = add_scheduled + post "/scheduled/#{job_params(*params)}", 'delete' => 'Delete' + assert_equal 302, last_response.status + assert_equal 'http://example.org/scheduled', last_response.header['Location'] + + get "/scheduled" + assert_equal 200, last_response.status + refute_match /#{params.first['args'][2]}/, last_response.body + end + it 'can delete scheduled' do params = add_scheduled Sidekiq.redis do |conn| From 963e4e95e61556089afe9a1cecc19eff71458c32 Mon Sep 17 00:00:00 2001 From: Jonathan Hyman Date: Sat, 27 Jul 2013 18:52:25 -0400 Subject: [PATCH 6/7] Fixing spacing on reverted config.ru --- config.ru | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/config.ru b/config.ru index 403395bc..e46cb222 100644 --- a/config.ru +++ b/config.ru @@ -6,13 +6,13 @@ end #Sidekiq.redis {|conn| conn.flushdb } #10.times do |idx| -#Sidekiq::Client.push('class' => 'HardWorker', 'args' => ['foo', 0.1, idx]) + #Sidekiq::Client.push('class' => 'HardWorker', 'args' => ['foo', 0.1, idx]) #end #Sidekiq.redis { |conn| conn.zadd('retry', Time.now.utc.to_f + 3000, MultiJson.encode({ -#'class' => 'HardWorker', 'args' => ['foo', 0.1, Time.now.to_f], -#'queue' => 'default', 'error_message' => 'No such method', 'error_class' => 'NoMethodError', -#'failed_at' => Time.now.utc, 'retry_count' => 0 })) } + #'class' => 'HardWorker', 'args' => ['foo', 0.1, Time.now.to_f], + #'queue' => 'default', 'error_message' => 'No such method', 'error_class' => 'NoMethodError', + #'failed_at' => Time.now.utc, 'retry_count' => 0 })) } require 'sidekiq/web' run Sidekiq::Web From 820657a29d724eb35bdde2f0f9eb9bd2a09bb719 Mon Sep 17 00:00:00 2001 From: Jonathan Hyman Date: Sat, 27 Jul 2013 19:04:06 -0400 Subject: [PATCH 7/7] Updating invalid jid in tests so it's more clear. --- test/test_web.rb | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/test/test_web.rb b/test/test_web.rb index 96917f15..68434037 100644 --- a/test/test_web.rb +++ b/test/test_web.rb @@ -130,7 +130,7 @@ class TestWeb < Minitest::Test it 'can display a single retry' do params = add_retry - get '/retries/2c4c17969825a384a92f023b' + get '/retries/0-shouldntexist' assert_equal 302, last_response.status get "/retries/#{job_params(*params)}" assert_equal 200, last_response.status @@ -138,7 +138,7 @@ class TestWeb < Minitest::Test end it 'handles missing retry' do - get "/retries/2c4c17969825a384a92f023b" + get "/retries/0-shouldntexist" assert_equal 302, last_response.status end @@ -189,13 +189,18 @@ class TestWeb < Minitest::Test it 'can display a single scheduled job' do params = add_scheduled - get '/scheduled/2c4c17969825a384a92f023b' + get '/scheduled/0-shouldntexist' assert_equal 302, last_response.status get "/scheduled/#{job_params(*params)}" assert_equal 200, last_response.status assert_match /HardWorker/, last_response.body end + it 'handles missing scheduled job' do + get "/scheduled/0-shouldntexist" + assert_equal 302, last_response.status + end + it 'can add to queue a single scheduled job' do params = add_scheduled post "/scheduled/#{job_params(*params)}", 'add_to_queue' => true