sidekiq-undertaker 1.0.0.rc01
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.
- checksums.yaml +7 -0
- data/.codeclimate.yml +6 -0
- data/.gitignore +22 -0
- data/.rubocop.yml +5 -0
- data/.rubocop_todo.yml +23 -0
- data/.travis.yml +53 -0
- data/Demo_Filter.png +0 -0
- data/Demo_Job_Filter.png +0 -0
- data/Demo_Morgue_1_Job.png +0 -0
- data/Demo_Morgue_all.png +0 -0
- data/Gemfile +11 -0
- data/LICENSE.txt +21 -0
- data/README.md +95 -0
- data/Rakefile +34 -0
- data/lib/sidekiq/undertaker.rb +16 -0
- data/lib/sidekiq/undertaker/bucket.rb +29 -0
- data/lib/sidekiq/undertaker/dead_job.rb +64 -0
- data/lib/sidekiq/undertaker/job_distributor.rb +64 -0
- data/lib/sidekiq/undertaker/job_filter.rb +46 -0
- data/lib/sidekiq/undertaker/version.rb +7 -0
- data/lib/sidekiq/undertaker/web_extension.rb +37 -0
- data/lib/sidekiq/undertaker/web_extension/api_helpers.rb +120 -0
- data/sidekiq-undertaker.gemspec +55 -0
- data/spec/fixtures/approvals/sidekiq_undertaker_webextension/show_filter/when_filter_page_is_called/behaves_like_a_page/the_displayed_page_is_correct.approved.txt +240 -0
- data/spec/fixtures/approvals/sidekiq_undertaker_webextension/show_filter/when_job_classbucket_page_is_called/behaves_like_a_page/the_displayed_page_is_correct.approved.txt +241 -0
- data/spec/fixtures/approvals/sidekiq_undertaker_webextension/show_filter/when_job_classbucket_page_is_polled/behaves_like_a_page/the_displayed_page_is_correct.approved.txt +241 -0
- data/spec/fixtures/approvals/sidekiq_undertaker_webextension/show_morgue/when_job_classerrorbucket_is_called/with_all_failures_and_errors/behaves_like_a_page/the_displayed_page_is_correct.approved.txt +316 -0
- data/spec/fixtures/approvals/sidekiq_undertaker_webextension/show_morgue/when_job_classerrorbucket_is_called/with_specific_job_class_and_a_specific_error/behaves_like_a_page/the_displayed_page_is_correct.approved.txt +274 -0
- data/spec/sidekiq/undertaker/bucket_spec.rb +26 -0
- data/spec/sidekiq/undertaker/dead_jobs_spec.rb +90 -0
- data/spec/sidekiq/undertaker/job_distributor_spec.rb +104 -0
- data/spec/sidekiq/undertaker/job_filter_spec.rb +105 -0
- data/spec/sidekiq/undertaker/web_extension_spec.rb +270 -0
- data/spec/spec_helper.rb +76 -0
- data/web/locales/en.yml +5 -0
- data/web/views/filter.erb +34 -0
- data/web/views/filter_job_class.erb +35 -0
- data/web/views/morgue.erb +75 -0
- metadata +378 -0
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "sidekiq/undertaker/dead_job"
|
4
|
+
|
5
|
+
module Sidekiq
|
6
|
+
module Undertaker
|
7
|
+
class JobFilter
|
8
|
+
class << self
|
9
|
+
def filter_dead_jobs(filters = {})
|
10
|
+
# filters can have keys in (job_class, error_class, bucket_name)
|
11
|
+
dead_jobs = []
|
12
|
+
Sidekiq::Undertaker::DeadJob.for_each do |dead_job|
|
13
|
+
filter_passed = true
|
14
|
+
filters.each do |filter, value|
|
15
|
+
next if skip?(filter, value)
|
16
|
+
|
17
|
+
filter_passed = false if dead_job.respond_to?(filter) && dead_job.public_send(filter) != value
|
18
|
+
end
|
19
|
+
dead_jobs << dead_job if filter_passed
|
20
|
+
end
|
21
|
+
|
22
|
+
dead_jobs
|
23
|
+
end
|
24
|
+
|
25
|
+
def skip?(filter, value)
|
26
|
+
value.nil? ||
|
27
|
+
total_dead_bucket?(filter, value) ||
|
28
|
+
all_jobs?(filter, value) ||
|
29
|
+
all_errors?(filter, value)
|
30
|
+
end
|
31
|
+
|
32
|
+
def total_dead_bucket?(filter, value)
|
33
|
+
filter == "bucket_name" && value == "total_dead"
|
34
|
+
end
|
35
|
+
|
36
|
+
def all_jobs?(filter, value)
|
37
|
+
filter == "job_class" && value == "all"
|
38
|
+
end
|
39
|
+
|
40
|
+
def all_errors?(filter, value)
|
41
|
+
filter == "error_class" && value == "all"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "sidekiq/undertaker/web_extension/api_helpers"
|
4
|
+
|
5
|
+
module Sidekiq
|
6
|
+
module Undertaker
|
7
|
+
module WebExtension
|
8
|
+
def self.registered(app)
|
9
|
+
app.helpers APIHelpers
|
10
|
+
|
11
|
+
app.get "/undertaker/filter" do
|
12
|
+
show_filter
|
13
|
+
end
|
14
|
+
|
15
|
+
app.get "/undertaker/filter/:job_class/:bucket_name" do
|
16
|
+
show_filter_by_job_class_bucket_name
|
17
|
+
end
|
18
|
+
|
19
|
+
app.get "/undertaker/morgue/:job_class/:error_class/:bucket_name" do
|
20
|
+
show_undertaker_by_job_class_error_class_bucket_name
|
21
|
+
end
|
22
|
+
|
23
|
+
app.post "/undertaker/morgue" do
|
24
|
+
post_undertaker
|
25
|
+
end
|
26
|
+
|
27
|
+
app.post "/undertaker/morgue/:job_class/:error_class/:bucket_name/delete" do
|
28
|
+
post_undertaker_job_class_error_class_buckent_name_delete
|
29
|
+
end
|
30
|
+
|
31
|
+
app.post "/undertaker/morgue/:job_class/:error_class/:bucket_name/retry" do
|
32
|
+
post_undertaker_job_class_error_class_buckent_name_retry
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "sidekiq/undertaker/job_distributor"
|
4
|
+
require "sidekiq/undertaker/job_filter"
|
5
|
+
|
6
|
+
module Sidekiq
|
7
|
+
module Undertaker
|
8
|
+
module WebExtension
|
9
|
+
module APIHelpers
|
10
|
+
def show_filter
|
11
|
+
store_request_params
|
12
|
+
|
13
|
+
@dead_jobs = Sidekiq::Undertaker::JobFilter.filter_dead_jobs(params)
|
14
|
+
@distribution = Sidekiq::Undertaker::JobDistributor.new(@dead_jobs).group_by_job_class
|
15
|
+
@total_dead = @dead_jobs.size
|
16
|
+
|
17
|
+
render_result("filter.erb")
|
18
|
+
end
|
19
|
+
|
20
|
+
def show_filter_by_job_class_bucket_name
|
21
|
+
store_request_params
|
22
|
+
|
23
|
+
@dead_jobs = Sidekiq::Undertaker::JobFilter.filter_dead_jobs(params)
|
24
|
+
@distribution = Sidekiq::Undertaker::JobDistributor.new(@dead_jobs).group_by_error_class
|
25
|
+
@total_dead = @dead_jobs.size
|
26
|
+
|
27
|
+
render_result("filter_job_class.erb")
|
28
|
+
end
|
29
|
+
|
30
|
+
def show_undertaker_by_job_class_error_class_bucket_name
|
31
|
+
store_request_params
|
32
|
+
|
33
|
+
@dead_jobs = Sidekiq::Undertaker::JobFilter.filter_dead_jobs(params)
|
34
|
+
|
35
|
+
# Display dead jobs as list
|
36
|
+
@dead_jobs = @dead_jobs.map(&:job)
|
37
|
+
|
38
|
+
@undertaker_path = "undertaker/#{@req_job_class}/#{@req_error_class}/#{@req_bucket_name}"
|
39
|
+
|
40
|
+
# Pagination
|
41
|
+
@total_dead = @dead_jobs.size
|
42
|
+
@current_page = (params[:page] || 1).to_i
|
43
|
+
@count = 50 # per page
|
44
|
+
@dead_jobs = @dead_jobs[((@current_page - 1) * @count), @count]
|
45
|
+
|
46
|
+
# Remove unrelated arguments to allow _paginate url to be clean
|
47
|
+
# Hack to continue to reuse sidekiq's _pagination template
|
48
|
+
params.delete("job_class")
|
49
|
+
params.delete("bucket_name")
|
50
|
+
params.delete("error_class")
|
51
|
+
|
52
|
+
render_result("morgue.erb")
|
53
|
+
end
|
54
|
+
|
55
|
+
def post_undertaker
|
56
|
+
raise ::ArgumentError.new("Key missing") unless params["key"]
|
57
|
+
|
58
|
+
params["key"].each do |key|
|
59
|
+
job = Sidekiq::DeadSet.new.fetch(*parse_params(key)).first
|
60
|
+
if job
|
61
|
+
if params["retry"]
|
62
|
+
job.retry
|
63
|
+
elsif params["delete"]
|
64
|
+
job.delete
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
redirect redirect_path(request)
|
70
|
+
rescue ::ArgumentError
|
71
|
+
bad_request
|
72
|
+
end
|
73
|
+
|
74
|
+
def post_undertaker_job_class_error_class_buckent_name_delete
|
75
|
+
store_request_params
|
76
|
+
@dead_jobs = Sidekiq::Undertaker::JobFilter.filter_dead_jobs(params)
|
77
|
+
@dead_jobs.each do |dead_job|
|
78
|
+
dead_job.job.delete
|
79
|
+
end
|
80
|
+
|
81
|
+
redirect redirect_path(request)
|
82
|
+
end
|
83
|
+
|
84
|
+
def post_undertaker_job_class_error_class_buckent_name_retry
|
85
|
+
store_request_params
|
86
|
+
|
87
|
+
@dead_jobs = Sidekiq::Undertaker::JobFilter.filter_dead_jobs(params)
|
88
|
+
@dead_jobs.each do |dead_job|
|
89
|
+
dead_job.job.retry
|
90
|
+
end
|
91
|
+
|
92
|
+
redirect redirect_path(request)
|
93
|
+
end
|
94
|
+
|
95
|
+
def render_result(template)
|
96
|
+
render(:erb, File.read(File.join(view_path, template)))
|
97
|
+
end
|
98
|
+
|
99
|
+
def store_request_params
|
100
|
+
@req_job_class = params["job_class"]
|
101
|
+
@req_bucket_name = params["bucket_name"]
|
102
|
+
@req_error_class = params["error_class"]
|
103
|
+
end
|
104
|
+
|
105
|
+
def view_path
|
106
|
+
File.join(File.expand_path(__dir__), "../../../../web/views")
|
107
|
+
end
|
108
|
+
|
109
|
+
def redirect_path(request)
|
110
|
+
path = request.referer ? URI.parse(request.referer).path : request.path
|
111
|
+
path.gsub("/delete", "").gsub("/retry", "")
|
112
|
+
end
|
113
|
+
|
114
|
+
def bad_request
|
115
|
+
[400, { "Content-Type" => "text/plain" }, ["Bad Request"]]
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path("lib", __dir__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require "sidekiq/undertaker/version"
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = "sidekiq-undertaker"
|
9
|
+
spec.version = Sidekiq::Undertaker::VERSION
|
10
|
+
spec.authors = ["Thomas Koppensteiner"]
|
11
|
+
spec.email = ["thomas.koppensteiner@gmx.net "]
|
12
|
+
spec.summary = "Sidekiq::Undertaker makes exploring the Sidekiq dead job queue easier"
|
13
|
+
spec.description = <<-DES
|
14
|
+
Sidekiq::Undertaker is a plugin for Sidekiq.
|
15
|
+
It makes exploring the dead job queue easier
|
16
|
+
by breaking down the dead jobs into time windows (buckets) of hours and days.
|
17
|
+
The gems allows retrying or deleting a certain subset of failures.
|
18
|
+
DES
|
19
|
+
spec.license = "MIT"
|
20
|
+
|
21
|
+
spec.homepage = "https://github.com/ThomasKoppensteiner/sidekiq-undertaker"
|
22
|
+
spec.metadata = {
|
23
|
+
"homepage_uri" => "https://github.com/ThomasKoppensteiner/sidekiq-undertaker",
|
24
|
+
"source_code_uri" => "https://github.com/ThomasKoppensteiner/sidekiq-undertaker",
|
25
|
+
"bug_tracker_uri" => "https://github.com/ThomasKoppensteiner/sidekiq-undertaker/issues",
|
26
|
+
"build_status_uri" => "https://travis-ci.org/ThomasKoppensteiner/sidekiq-undertaker"
|
27
|
+
}
|
28
|
+
|
29
|
+
spec.files = `git ls-files -z`.split("\x0")
|
30
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
31
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
32
|
+
spec.require_paths = ["lib", "lib/sidekiq/undertaker"]
|
33
|
+
|
34
|
+
spec.add_development_dependency "bundler", ">= 1.17", "<3"
|
35
|
+
spec.add_development_dependency "rake", "~> 12.3"
|
36
|
+
|
37
|
+
spec.add_development_dependency "approvals", "~> 0.0", ">= 0.0.24"
|
38
|
+
spec.add_development_dependency "mock_redis", "~> 0.19"
|
39
|
+
spec.add_development_dependency "pry", "~> 0.12"
|
40
|
+
spec.add_development_dependency "rack-test", "~> 1.1"
|
41
|
+
spec.add_development_dependency "rb-readline", "~> 0.5"
|
42
|
+
spec.add_development_dependency "rspec", "~> 3.8"
|
43
|
+
spec.add_development_dependency "rspec-core", "~> 3.8"
|
44
|
+
spec.add_development_dependency "rspec-mocks", "~> 3.8"
|
45
|
+
spec.add_development_dependency "rspec-sidekiq", "~> 3.0"
|
46
|
+
spec.add_development_dependency "rt_rubocop_defaults", "~> 1.2"
|
47
|
+
spec.add_development_dependency "rubocop", "~> 0.77"
|
48
|
+
spec.add_development_dependency "rubocop-rspec", "~> 1.30"
|
49
|
+
spec.add_development_dependency "rubocop_runner", "~> 2.1"
|
50
|
+
spec.add_development_dependency "simplecov", "~> 0.14"
|
51
|
+
spec.add_development_dependency "sinatra", "~> 2.0"
|
52
|
+
spec.add_development_dependency "timecop", "~> 0.9"
|
53
|
+
|
54
|
+
spec.add_runtime_dependency "sidekiq", "~> 5.2"
|
55
|
+
end
|
@@ -0,0 +1,240 @@
|
|
1
|
+
<!doctype html>
|
2
|
+
<html dir="ltr">
|
3
|
+
<head>
|
4
|
+
<title>[TEST] Sidekiq</title>
|
5
|
+
<meta charset="utf-8" />
|
6
|
+
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
|
7
|
+
|
8
|
+
<link href="/sidekiq/stylesheets/bootstrap.css" media="screen" rel="stylesheet" type="text/css" />
|
9
|
+
|
10
|
+
|
11
|
+
<link href="/sidekiq/stylesheets/application.css" media="screen" rel="stylesheet" type="text/css" />
|
12
|
+
|
13
|
+
|
14
|
+
<link rel="shortcut icon" type="image/ico" href="/sidekiq/images/favicon.ico" />
|
15
|
+
<script type="text/javascript" src="/sidekiq/javascripts/application.js"></script>
|
16
|
+
<meta name="google" content="notranslate" />
|
17
|
+
|
18
|
+
</head>
|
19
|
+
<body class="admin" data-poll-path="" data-locale="en">
|
20
|
+
<div class="navbar navbar-default navbar-fixed-top">
|
21
|
+
<div class="container-fluid">
|
22
|
+
<div class="navbar-header" data-navbar="static">
|
23
|
+
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-menu">
|
24
|
+
<span class="icon-bar"></span>
|
25
|
+
<span class="icon-bar"></span>
|
26
|
+
<span class="icon-bar"></span>
|
27
|
+
</button>
|
28
|
+
<div class="navbar-toggle collapsed navbar-livereload">
|
29
|
+
|
30
|
+
|
31
|
+
<a id="live-poll" class="btn btn-primary" href="/sidekiq/undertaker/filter?poll=true">Live Poll</a>
|
32
|
+
|
33
|
+
|
34
|
+
|
35
|
+
|
36
|
+
</div>
|
37
|
+
<a class="navbar-brand" href="/sidekiq/">
|
38
|
+
Sidekiq
|
39
|
+
<span class="status">
|
40
|
+
<i class="status-sprite status-idle"></i>
|
41
|
+
idle
|
42
|
+
</span>
|
43
|
+
|
44
|
+
</a>
|
45
|
+
</div>
|
46
|
+
|
47
|
+
<div class="collapse navbar-collapse" id="navbar-menu">
|
48
|
+
<ul class="nav navbar-nav" data-navbar="static">
|
49
|
+
|
50
|
+
|
51
|
+
<li class="">
|
52
|
+
<a href="/sidekiq/">Dashboard</a>
|
53
|
+
</li>
|
54
|
+
|
55
|
+
|
56
|
+
|
57
|
+
<li class="">
|
58
|
+
<a href="/sidekiq/busy">Busy</a>
|
59
|
+
</li>
|
60
|
+
|
61
|
+
|
62
|
+
|
63
|
+
<li class="">
|
64
|
+
<a href="/sidekiq/queues">Queues</a>
|
65
|
+
</li>
|
66
|
+
|
67
|
+
|
68
|
+
|
69
|
+
<li class="">
|
70
|
+
<a href="/sidekiq/retries">Retries</a>
|
71
|
+
</li>
|
72
|
+
|
73
|
+
|
74
|
+
|
75
|
+
<li class="">
|
76
|
+
<a href="/sidekiq/scheduled">Scheduled</a>
|
77
|
+
</li>
|
78
|
+
|
79
|
+
|
80
|
+
|
81
|
+
<li class="">
|
82
|
+
<a href="/sidekiq/morgue">Dead</a>
|
83
|
+
</li>
|
84
|
+
|
85
|
+
|
86
|
+
|
87
|
+
|
88
|
+
<li class="active" data-navbar="custom-tab">
|
89
|
+
<a href="/sidekiq/undertaker/filter">Undertaker</a>
|
90
|
+
</li>
|
91
|
+
|
92
|
+
|
93
|
+
<li class="navbar-livereload">
|
94
|
+
<div class="poll-wrapper">
|
95
|
+
|
96
|
+
|
97
|
+
<a id="live-poll" class="btn btn-primary" href="/sidekiq/undertaker/filter?poll=true">Live Poll</a>
|
98
|
+
|
99
|
+
|
100
|
+
|
101
|
+
|
102
|
+
</div>
|
103
|
+
</li>
|
104
|
+
</ul>
|
105
|
+
</div>
|
106
|
+
</div>
|
107
|
+
</div>
|
108
|
+
|
109
|
+
<div id="page">
|
110
|
+
<div class="container">
|
111
|
+
<div class="row">
|
112
|
+
<div class="col-sm-12 summary_bar">
|
113
|
+
<ul class="list-unstyled summary row">
|
114
|
+
<li class="processed col-sm-1">
|
115
|
+
<span class="count">0</span>
|
116
|
+
<span class="desc">Processed</span>
|
117
|
+
</li>
|
118
|
+
<li class="failed col-sm-1">
|
119
|
+
<span class="count">0</span>
|
120
|
+
<span class="desc">Failed</span>
|
121
|
+
</li>
|
122
|
+
<li class="busy col-sm-1">
|
123
|
+
<a href="/sidekiq/busy">
|
124
|
+
<span class="count">0</span>
|
125
|
+
<span class="desc">Busy</span>
|
126
|
+
</a>
|
127
|
+
</li>
|
128
|
+
<li class="enqueued col-sm-1">
|
129
|
+
<a href="/sidekiq/queues">
|
130
|
+
<span class="count">0</span>
|
131
|
+
<span class="desc">Enqueued</span>
|
132
|
+
</a>
|
133
|
+
</li>
|
134
|
+
<li class="retries col-sm-1">
|
135
|
+
<a href="/sidekiq/retries">
|
136
|
+
<span class="count">0</span>
|
137
|
+
<span class="desc">Retries</span>
|
138
|
+
</a>
|
139
|
+
</li>
|
140
|
+
<li class="scheduled col-sm-1">
|
141
|
+
<a href="/sidekiq/scheduled">
|
142
|
+
<span class="count">0</span>
|
143
|
+
<span class="desc">Scheduled</span>
|
144
|
+
</a>
|
145
|
+
</li>
|
146
|
+
<li class="dead col-sm-1">
|
147
|
+
<a href="/sidekiq/morgue">
|
148
|
+
<span class="count">4</span>
|
149
|
+
<span class="desc">Dead</span>
|
150
|
+
</a>
|
151
|
+
</li>
|
152
|
+
</ul>
|
153
|
+
|
154
|
+
</div>
|
155
|
+
|
156
|
+
<div class="col-sm-12">
|
157
|
+
<header class="row header">
|
158
|
+
<div class="col-sm-12">
|
159
|
+
<h3>
|
160
|
+
<b>4</b> dead jobs
|
161
|
+
</h3>
|
162
|
+
</div>
|
163
|
+
</header>
|
164
|
+
|
165
|
+
<table class="table table-striped table-bordered table-white">
|
166
|
+
<thead>
|
167
|
+
<tr>
|
168
|
+
<th style="width: 20%">Jobs</th>
|
169
|
+
<th style="width: 10%">All</th>
|
170
|
+
<th style="width: 10%">1 hour</th>
|
171
|
+
<th style="width: 10%">3 hours</th>
|
172
|
+
<th style="width: 10%">1 day</th>
|
173
|
+
<th style="width: 10%">3 days</th>
|
174
|
+
<th style="width: 10%">1 week</th>
|
175
|
+
<th style="width: 10%">Older</th>
|
176
|
+
</tr>
|
177
|
+
</thead>
|
178
|
+
|
179
|
+
<tr>
|
180
|
+
<td><a href='/sidekiq/undertaker/morgue/all/all/total_dead'> all</a></td>
|
181
|
+
<td><a href='/all/total_dead'>4</a></td>
|
182
|
+
<td><a href='/all/1_hour'>4</a></td>
|
183
|
+
<td><a href='/all/3_hours'>0</a></td>
|
184
|
+
<td><a href='/all/1_day'>0</a></td>
|
185
|
+
<td><a href='/all/3_days'>0</a></td>
|
186
|
+
<td><a href='/all/1_week'>0</a></td>
|
187
|
+
<td><a href='/all/older'>0</a></td>
|
188
|
+
</tr>
|
189
|
+
|
190
|
+
<tr>
|
191
|
+
<td><a href='/sidekiq/undertaker/morgue/HardWorker/all/total_dead'> HardWorker</a></td>
|
192
|
+
<td><a href='/HardWorker/total_dead'>3</a></td>
|
193
|
+
<td><a href='/HardWorker/1_hour'>3</a></td>
|
194
|
+
<td><a href='/HardWorker/3_hours'>0</a></td>
|
195
|
+
<td><a href='/HardWorker/1_day'>0</a></td>
|
196
|
+
<td><a href='/HardWorker/3_days'>0</a></td>
|
197
|
+
<td><a href='/HardWorker/1_week'>0</a></td>
|
198
|
+
<td><a href='/HardWorker/older'>0</a></td>
|
199
|
+
</tr>
|
200
|
+
|
201
|
+
<tr>
|
202
|
+
<td><a href='/sidekiq/undertaker/morgue/HardWorker1/all/total_dead'> HardWorker1</a></td>
|
203
|
+
<td><a href='/HardWorker1/total_dead'>1</a></td>
|
204
|
+
<td><a href='/HardWorker1/1_hour'>1</a></td>
|
205
|
+
<td><a href='/HardWorker1/3_hours'>0</a></td>
|
206
|
+
<td><a href='/HardWorker1/1_day'>0</a></td>
|
207
|
+
<td><a href='/HardWorker1/3_days'>0</a></td>
|
208
|
+
<td><a href='/HardWorker1/1_week'>0</a></td>
|
209
|
+
<td><a href='/HardWorker1/older'>0</a></td>
|
210
|
+
</tr>
|
211
|
+
|
212
|
+
</table>
|
213
|
+
|
214
|
+
</div>
|
215
|
+
</div>
|
216
|
+
</div>
|
217
|
+
</div>
|
218
|
+
<div class="navbar navbar-fixed-bottom navbar-inverse ltr">
|
219
|
+
<div class="navbar-inner">
|
220
|
+
<div class="container text-center">
|
221
|
+
<ul class="nav">
|
222
|
+
<li>
|
223
|
+
<p class="navbar-text product-version">Sidekiq v*EXCLUDED*</p>
|
224
|
+
</li>
|
225
|
+
<li>
|
226
|
+
<p class="navbar-text redis-url" title="redis://127.0.0.1:6379/0">redis://127.0.0.1:6379/0</p>
|
227
|
+
</li>
|
228
|
+
<li>
|
229
|
+
<p class="navbar-text server-utc-time">20:57:00 UTC</p>
|
230
|
+
</li>
|
231
|
+
<li>
|
232
|
+
<p class="navbar-text"><a style="color: gray;" href="https://github.com/mperham/sidekiq/wiki">docs</a></p>
|
233
|
+
</li>
|
234
|
+
</ul>
|
235
|
+
</div>
|
236
|
+
</div>
|
237
|
+
</div>
|
238
|
+
|
239
|
+
</body>
|
240
|
+
</html>
|