From 46c013f725da6ed752308e9cd4133cde6282d46c Mon Sep 17 00:00:00 2001 From: Tobias Svensson Date: Fri, 1 Feb 2013 12:26:17 +0000 Subject: [PATCH] Initial version of the web extension. --- Gemfile | 3 ++ README.md | 11 +++++ lib/sidetiq/views/sidetiq.slim | 23 ++++++++++ lib/sidetiq/views/sidetiq_details.slim | 40 +++++++++++++++++ lib/sidetiq/web.rb | 42 +++++++++++++++++ test/helper.rb | 8 +++- test/test_web.rb | 62 ++++++++++++++++++++++++++ 7 files changed, 188 insertions(+), 1 deletion(-) create mode 100644 lib/sidetiq/views/sidetiq.slim create mode 100644 lib/sidetiq/views/sidetiq_details.slim create mode 100644 lib/sidetiq/web.rb create mode 100644 test/test_web.rb diff --git a/Gemfile b/Gemfile index 5ad759e..c5337ce 100644 --- a/Gemfile +++ b/Gemfile @@ -3,11 +3,14 @@ source 'https://rubygems.org' group :development do gem 'rake' gem 'rake-compiler' + gem 'sinatra', require: false + gem 'slim', require: false end group :test do gem 'simplecov' gem 'mocha' + gem 'rack-test' end gemspec diff --git a/README.md b/README.md index 5c9b58d..94dedf5 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,17 @@ Sidetiq.configure do |config| end ``` +## WEB EXTENSION + +Sidetiq includes an extension for Sidekiq's web interface. It will not be +loaded by default, so it will have to be required manually: + +```ruby +require 'sidetiq/web' +``` + +![Screenshot](http://cl.ly/image/1X0q3v153F3Q) + ## CONSIDERATIONS If workers are spread across multiple machines multiple jobs might be enqueued diff --git a/lib/sidetiq/views/sidetiq.slim b/lib/sidetiq/views/sidetiq.slim new file mode 100644 index 0000000..90c9b11 --- /dev/null +++ b/lib/sidetiq/views/sidetiq.slim @@ -0,0 +1,23 @@ +header.row + .span5 + h3 Recurring Jobs + +- if @schedules.length > 0 + table class="table table-striped table-bordered table-white" style="width: 100%; margin: 0; table-layout:fixed;" + thead + th style="width: 50%" Worker + th style="width: 20%" Queue + th style="width: 20%" Next Run + th style="width: 10%" Actions + - @schedules.each do |worker, schedule| + tr + td + = worker.name + td= worker.get_sidekiq_options['queue'] + td + == relative_time(schedule.next_occurrence) + td + a href="#{root_path}sidetiq/#{worker.name}" Details +- else + .alert.alert-success No recurring jobs found. + diff --git a/lib/sidetiq/views/sidetiq_details.slim b/lib/sidetiq/views/sidetiq_details.slim new file mode 100644 index 0000000..860b4e4 --- /dev/null +++ b/lib/sidetiq/views/sidetiq_details.slim @@ -0,0 +1,40 @@ +header.row + .span5 + h3 + ' Recurring Job: + = @worker.name + +- if (recurrences = @schedule.recurrence_rules).length > 0 + table class="table table-striped table-bordered table-white" style="width: 100%; margin: 0; table-layout:fixed;" + thead + th Recurrences + - recurrences.each do |rule| + tr + td + = rule.to_s + +br + +- if (exceptions = @schedule.exception_rules).length > 0 + table class="table table-striped table-bordered table-white" style="width: 100%; margin: 0; table-layout:fixed;" + thead + th Exceptions + - exceptions.each do |rule| + tr + td + = rule.to_s + +br + +table class="table table-striped table-bordered table-white" style="width: 100%; margin: 0; table-layout:fixed;" + thead + th style="width: 25%" Next 10 runs + th style="width: 75%" + - @schedule.next_occurrences(10).each do |time| + tr + td + time= time.getutc + td + == relative_time(time) + +br diff --git a/lib/sidetiq/web.rb b/lib/sidetiq/web.rb new file mode 100644 index 0000000..814461f --- /dev/null +++ b/lib/sidetiq/web.rb @@ -0,0 +1,42 @@ +require 'sidekiq/web' + +module Sidetiq + module Web + + def self.registered(app) + app.helpers do + def find_template(view, *args, &block) + path = File.expand_path(File.join('..', 'views'), __FILE__) + super(path, *args, &block) + super + end + end + + app.get "/sidetiq" do + @schedules = Sidetiq::Clock.instance.schedules + slim :sidetiq + end + + app.get "/sidetiq/:name" do + halt 404 unless (name = params[:name]) + + schedules = Sidetiq::Clock.instance.schedules + + @worker, @schedule = schedules.select do |worker, schedule| + worker.name == name + end.flatten + + slim :sidetiq_details + end + end + end +end + +Sidekiq::Web.register(Sidetiq::Web) + +if Sidekiq::Web.tabs.is_a?(Array) + Sidekiq::Web.tabs << "sidetiq" +else + Sidekiq::Web.tabs["Sidetiq"] = "sidetiq" +end + diff --git a/test/helper.rb b/test/helper.rb index efa9939..70cdb2e 100644 --- a/test/helper.rb +++ b/test/helper.rb @@ -1,10 +1,16 @@ require 'simplecov' SimpleCov.start { add_filter "/test/" } + require 'minitest/autorun' require 'mocha/setup' -require 'sidetiq' +require 'rack/test' + +require 'sidekiq' require 'sidekiq/testing' +require 'sidetiq' +require 'sidetiq/web' + # Stub out Clock#start! so we don't actually loop module Sidetiq class Clock diff --git a/test/test_web.rb b/test/test_web.rb new file mode 100644 index 0000000..a7a32c2 --- /dev/null +++ b/test/test_web.rb @@ -0,0 +1,62 @@ +require_relative 'helper' + +class TestWeb < MiniTest::Unit::TestCase + include Rack::Test::Methods + + class Worker + include Sidekiq::Worker + include Sidetiq::Schedulable + + tiq do + daily(1) + yearly(2) + monthly(3) + + add_exception_rule yearly.month_of_year(:february) + end + end + + def app + Sidekiq::Web + end + + def clock + Sidetiq::Clock.instance + end + + def test_home_tab + get '/' + assert_equal 200, last_response.status + assert_match last_response.body, /Sidekiq/ + assert_match last_response.body, /Sidetiq/ + end + + def test_sidetiq_page + get '/sidetiq' + assert_equal 200, last_response.status + + clock.schedules.each do |worker, schedule| + assert_match last_response.body, /#{worker.name}/ + assert_match last_response.body, /#{worker.get_sidekiq_options['queue']}/ + end + end + + def test_details_page + get "/sidetiq/#{Worker.name}" + assert_equal 200, last_response.status + schedule = clock.schedules[Worker] + + schedule.recurrence_rules.each do |rule| + assert_match last_response.body, /#{rule.to_s}/ + end + + schedule.exception_rules.each do |rule| + assert_match last_response.body, /#{rule.to_s}/ + end + + schedule.next_occurrences(10).each do |time| + assert_match last_response.body, /#{time.getutc.to_s}/ + end + end +end +