sidekiq-status 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8c3bd23f9fe0e80f8354ca3860fbeb5e5f7ca44d
4
- data.tar.gz: 1ad626cad36a7f56fab5f4ca89350c55879a2d86
3
+ metadata.gz: 1750cf2e429082ad9d404598e45fe7bf15bb31cc
4
+ data.tar.gz: 708de7f5f0a83d59fec644600f2a4e70e99c89d5
5
5
  SHA512:
6
- metadata.gz: 46cbab187b63bc2fb458e7530180a7f0b41858067213346297ec45dc62bdd04db997b2e2031205cf426d3e6eafe9921c4d22491cbcb7f86be0dda4875e3ac8d6
7
- data.tar.gz: e187d76f19d38d903df4258d8a55627da09e5cf4a9faf20b51ce16f682206cbe526142a4c88b8abb3fa993ab2bca7e21866dcd9e5e4591fe937fb3ce7c1810cb
6
+ metadata.gz: 7228891c5252a1df3da9ad85942552f5426a466d18ddc6b9e963ad3ec6f91512ecaadeb8e0ff00c09f36d2c9a044cfb44619271b772637b88c044868d15fdc4c
7
+ data.tar.gz: 56a416d652d875528fd64cebaa490fc3ae173ba96d8ea080c7d2d202a67ecdc11d365c66d3d4cac4691977a5d8d2b006addc0f84cbb2a7fca52ad3fa5cb07530
data/.travis.yml CHANGED
@@ -1,16 +1,11 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.0
4
- - 2.1
5
3
  - 2.2
6
- - rbx-2
4
+ - 2.3
5
+ - 2.4
7
6
  gemfile:
8
- - gemfiles/Gemfile.sidekiq-2
9
7
  - Gemfile
10
8
  before_install:
11
9
  - gem update --system
12
10
  - gem update bundler
13
11
  services: redis
14
- matrix:
15
- allow_failures:
16
- - rvm: rbx-2
data/CHANGELOG.md CHANGED
@@ -1,16 +1,26 @@
1
+ Version 0.7.0
2
+ + Sidekiq 4.2 and 5 now supported
3
+ + Added full support for ActiveJob
4
+ + Updated Web UI
5
+ + Styling updated to stay consistent with Sidekiq UI
6
+ + Added header sorting
7
+ + Fixed argument formatting
8
+ + Times now display using natural language via ChronicDuration
9
+ + Test suite fixed
10
+
1
11
  Version 0.6.0
2
- + Updated Web UI
12
+ + Updated Web UI
3
13
  + Will have all job statuses, previously it was showing only :working status
4
- + Bootstrap lables instead of badges for status
5
- + Added Arguments column to statuses page
6
- + New :interrupted status added
14
+ + Bootstrap lables instead of badges for status
15
+ + Added Arguments column to statuses page
16
+ + New :interrupted status added
7
17
  + Added way to specify :expiration for Sidekiq::Status::ClientMiddleware
8
- + Bug fixes & Code cleaup
18
+ + Bug fixes & Code cleaup
9
19
 
10
- Version 0.5.3
20
+ Version 0.5.3
11
21
  + some tweaks in web UI, separate redis namespace
12
22
 
13
- Version 0.5.2
23
+ Version 0.5.2
14
24
  + Sidekiq versions up to 3.3.* supported, jobs sorting options in web UI, more ruby versions
15
25
 
16
26
  Version 0.5.1
@@ -20,4 +30,4 @@ Version 0.5.0
20
30
  + Sidekiq v3 support, redis pools support
21
31
 
22
32
  Version 0.4.0
23
- + WebUI added, per-worker expiration setting enabled
33
+ + WebUI added, per-worker expiration setting enabled
data/Gemfile CHANGED
@@ -2,7 +2,3 @@
2
2
  source "https://rubygems.org"
3
3
 
4
4
  gemspec
5
-
6
- group :test do
7
- gem 'celluloid'
8
- end
data/README.md CHANGED
@@ -10,7 +10,18 @@ by [resque-status](http://github.com/quirkey/resque-status) and mostly copying i
10
10
 
11
11
  ## Installation
12
12
 
13
- gem install sidekiq-status
13
+ Add this line to your application's Gemfile:
14
+
15
+ ```ruby
16
+ gem 'sidekiq-status'
17
+ ```
18
+ And then execute:
19
+
20
+ $ bundle
21
+
22
+ Or install it yourself as:
23
+
24
+ gem install sidekiq-status
14
25
 
15
26
  ## Usage
16
27
 
@@ -115,7 +126,7 @@ class MyJob
115
126
  store vino: 'veritas'
116
127
 
117
128
  # a way of retrieving said data
118
- # remember that retrieved data is always is String|nil
129
+ # remember that retrieved data is always String|nil
119
130
  vino = retrieve :vino
120
131
  end
121
132
  end
@@ -145,10 +156,18 @@ Sidekiq::Status.unschedule '' #=> false
145
156
  ```
146
157
  Important: If you try any of the status method after the expiration time for scheduled jobs, will result into `nil` or `false`. But job will be in sidekiq's scheduled queue and will execute normally, once job is started on scheduled time you will get status info for job till expiration time defined on `Sidekiq::Status::ServerMiddleware`.
147
158
 
159
+ ### Deleting Status by Job ID
160
+ ```ruby
161
+ # returns number of keys/jobs that were removed
162
+ Sidekiq::Status.delete(job_id) #=> 1
163
+ Sidekiq::Status.delete(bad_job_id) #=> 0
164
+ ```
165
+
148
166
  ### Sidekiq web integration
149
167
 
150
- Sidekiq::Status also provides an extension to Sidekiq web interface with a `/statuses`.
151
- ![Sidekiq Status Web](https://raw.github.com/utgarda/sidekiq-status/master/web/sidekiq-status-web.png)
168
+ Sidekiq::Status also provides an extension to Sidekiq web interface with an index at `/statuses` and a single job at `/statuses/123`.
169
+ ![Sidekiq Status Web](web/sidekiq-status-web.png)
170
+ ![Sidekiq Status Web](web/sidekiq-status-single-web.png)
152
171
 
153
172
  Setup Sidekiq web interface according to Sidekiq documentation and add the Sidekiq::Status::Web require:
154
173
 
@@ -177,9 +196,16 @@ To use `sidekiq-status` inlining, require it too in your `{test,spec}_helper.rb`
177
196
 
178
197
  `require 'sidekiq-status/testing/inline'`
179
198
 
199
+ ## Contributing
200
+
201
+ Bug reports and pull requests are welcome. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
180
202
 
181
- ### Features coming
182
- * Stopping jobs by id
203
+ 1. Fork it
204
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
205
+ 3. Commit your changes along with test cases (`git commit -am 'Add some feature'`)
206
+ 4. If possible squash your commits to one commit if they all belong to same feature.
207
+ 5. Push to the branch (`git push origin my-new-feature`)
208
+ 6. Create new Pull Request.
183
209
 
184
210
  ## Thanks
185
211
  * Pramod Shinde
@@ -194,4 +220,4 @@ To use `sidekiq-status` inlining, require it too in your `{test,spec}_helper.rb`
194
220
 
195
221
  ## License
196
222
  MIT License , see LICENSE for more details.
197
- © 2012 - 2015 Evgeniy Tsvigun
223
+ © 2012 - 2016 Evgeniy Tsvigun
@@ -4,6 +4,7 @@ require 'sidekiq-status/worker'
4
4
  require 'sidekiq-status/client_middleware'
5
5
  require 'sidekiq-status/server_middleware'
6
6
  require 'sidekiq-status/web' if defined?(Sidekiq::Web)
7
+ require 'chronic_duration'
7
8
 
8
9
  module Sidekiq::Status
9
10
  extend Storage
@@ -21,8 +22,8 @@ module Sidekiq::Status
21
22
  # Get all status fields for a job
22
23
  # @params [String] id job id returned by async_perform
23
24
  # @return [Hash] hash of all fields stored for the job
24
- def get_all(id)
25
- read_hash_for_id(id)
25
+ def get_all(job_id)
26
+ read_hash_for_id(job_id)
26
27
  end
27
28
 
28
29
  def status(job_id)
@@ -34,6 +35,10 @@ module Sidekiq::Status
34
35
  delete_and_unschedule(job_id, job_unix_time)
35
36
  end
36
37
 
38
+ def delete(job_id)
39
+ delete_status(job_id)
40
+ end
41
+
37
42
  alias_method :unschedule, :cancel
38
43
 
39
44
  STATUS.each do |name|
@@ -1,3 +1,4 @@
1
+ require 'sidekiq/api'
1
2
  module Sidekiq::Status
2
3
  # Should be in the client middleware chain
3
4
  class ClientMiddleware
@@ -17,14 +18,22 @@ module Sidekiq::Status
17
18
  # @param [String] queue the queue's name
18
19
  # @param [ConnectionPool] redis_pool optional redis connection pool
19
20
  def call(worker_class, msg, queue, redis_pool=nil)
20
- initial_metadata = {
21
+ initial_metadata = {
21
22
  jid: msg['jid'],
22
23
  status: :queued,
23
- worker: worker_class,
24
- args: msg['args'].to_a.empty? ? nil : msg['args'].to_json
24
+ worker: Sidekiq::Job.new(msg, queue).display_class,
25
+ args: display_args(msg, queue)
25
26
  }
26
27
  store_for_id msg['jid'], initial_metadata, @expiration, redis_pool
27
28
  yield
28
29
  end
30
+
31
+ def display_args(msg, queue)
32
+ job = Sidekiq::Job.new(msg, queue)
33
+ return job.display_args.to_a.empty? ? nil : job.display_args.to_json
34
+ rescue Exception => e
35
+ # For Sidekiq ~> 2.7
36
+ return msg['args'].to_a.empty? ? nil : msg['args'].to_json
37
+ end
29
38
  end
30
- end
39
+ end
@@ -52,6 +52,15 @@ module Sidekiq::Status::Storage
52
52
  false
53
53
  end
54
54
 
55
+ # Deletes status hash info for given job id
56
+ # @param[String] job id
57
+ # @retrun [Integer] number of keys that were removed
58
+ def delete_status(id)
59
+ redis_connection do |conn|
60
+ conn.del(key(id))
61
+ end
62
+ end
63
+
55
64
  # Gets a single valued from job status hash
56
65
  # @param [String] id job id
57
66
  # @param [String] Symbol field fetched field name
@@ -6,5 +6,11 @@ module Sidekiq
6
6
  end
7
7
  end
8
8
  end
9
+
10
+ module Storage
11
+ def store_status(id, status, expiration = nil, redis_pool=nil)
12
+ 'ok'
13
+ end
14
+ end
9
15
  end
10
16
 
@@ -1,5 +1,5 @@
1
1
  module Sidekiq
2
2
  module Status
3
- VERSION = '0.6.0'
3
+ VERSION = '0.7.0'
4
4
  end
5
5
  end
@@ -22,7 +22,7 @@ module Sidekiq::Status
22
22
 
23
23
  def pct_complete(status)
24
24
  return 100 if status['status'] == 'complete'
25
- Sidekiq::Status::pct_complete(status['jid'])
25
+ Sidekiq::Status::pct_complete(status['jid']) || 0
26
26
  end
27
27
 
28
28
  def status_label(status)
@@ -64,20 +64,22 @@ module Sidekiq::Status
64
64
  sort_dir = "desc"
65
65
  @statuses = @statuses.sort { |y,x| x.send(sort_by) <=> y.send(sort_by) }
66
66
  end
67
-
67
+
68
68
  working_jobs = @statuses.select{|job| job.status == "working"}
69
- if working_jobs.size >= 25
70
- @statuses = working_jobs
69
+ size = params[:size] ? params[:size].to_i : 25
70
+ if working_jobs.size >= size
71
+ @statuses = working_jobs
71
72
  else
72
- @statuses = (@statuses.size >= 25) ? @statuses.take(25) : @statuses
73
+ @statuses = (@statuses.size >= size) ? @statuses.take(size) : @statuses
73
74
  end
74
-
75
+
76
+
75
77
  @headers = [
76
- { id: "worker", name: "Worker/jid", class: nil, url: nil},
78
+ { id: "worker", name: "Worker / JID", class: nil, url: nil},
79
+ { id: "args", name: "Arguments", class: nil, url: nil},
77
80
  { id: "status", name: "Status", class: nil, url: nil},
78
81
  { id: "update_time", name: "Last Updated", class: nil, url: nil},
79
82
  { id: "pct_complete", name: "Progress", class: nil, url: nil},
80
- { id: "message", name: "Message", class: nil, url: nil}
81
83
  ]
82
84
 
83
85
  @headers.each do |h|
@@ -89,6 +91,17 @@ module Sidekiq::Status
89
91
 
90
92
  erb(sidekiq_status_template(:statuses))
91
93
  end
94
+
95
+ app.get '/statuses/:jid' do
96
+ job = Sidekiq::Status::get_all params['jid']
97
+
98
+ if job.empty?
99
+ halt [404, {"Content-Type" => "text/html"}, [erb(sidekiq_status_template(:status_not_found))]]
100
+ else
101
+ @status = OpenStruct.new(add_details_to_status(job))
102
+ erb(sidekiq_status_template(:status))
103
+ end
104
+ end
92
105
  end
93
106
  end
94
107
  end
@@ -11,14 +11,14 @@ module Sidekiq::Status::Worker
11
11
  # @param [Hash] status_updates updated values
12
12
  # @return [String] Redis operation status code
13
13
  def store(hash)
14
- store_for_id @jid, hash, @expiration
14
+ store_for_id @provider_job_id || @job_id || @jid, hash, @expiration
15
15
  end
16
16
 
17
17
  # Read value from job status hash
18
18
  # @param String|Symbol hask key
19
19
  # @return [String]
20
20
  def retrieve(name)
21
- read_field_for_id @jid, name
21
+ read_field_for_id @provider_job_id || @job_id || @jid, name
22
22
  end
23
23
 
24
24
  # Sets current task progress
@@ -15,6 +15,7 @@ Gem::Specification.new do |gem|
15
15
  gem.version = Sidekiq::Status::VERSION
16
16
 
17
17
  gem.add_dependency 'sidekiq', '>= 2.7'
18
+ gem.add_dependency 'chronic_duration'
18
19
  gem.add_development_dependency 'rack-test'
19
20
  gem.add_development_dependency 'rake'
20
21
  gem.add_development_dependency 'rspec'
@@ -0,0 +1 @@
1
+ # This file has been intentionally left blank
@@ -5,9 +5,6 @@ describe Sidekiq::Status::ClientMiddleware do
5
5
  let!(:redis) { Sidekiq.redis { |conn| conn } }
6
6
  let!(:job_id) { SecureRandom.hex(12) }
7
7
 
8
- # Clean Redis before each test
9
- before { redis.flushall }
10
-
11
8
  describe "#call" do
12
9
  before { client_middleware }
13
10
  it "sets queued status" do
@@ -5,11 +5,6 @@ describe Sidekiq::Status::ServerMiddleware do
5
5
  let!(:redis) { Sidekiq.redis { |conn| conn } }
6
6
  let!(:job_id) { SecureRandom.hex(12) }
7
7
 
8
- # Clean Redis before each test
9
- # Seems like flushall has no effect on recently published messages,
10
- # so we should wait till they expire
11
- before { redis.flushall; sleep 0.1 }
12
-
13
8
  describe "#call" do
14
9
  it "sets working/complete status" do
15
10
  thread = confirmations_thread 4, "status_updates", "job_messages_#{job_id}"
@@ -35,8 +30,8 @@ describe Sidekiq::Status::ServerMiddleware do
35
30
  expect(Sidekiq::Status::failed?(job_id)).to be_truthy
36
31
  end
37
32
 
38
- context "sets interrupted status" do
39
- it "on system exit signal" do
33
+ context "sets interrupted status" do
34
+ it "on system exit signal" do
40
35
  allow(SecureRandom).to receive(:hex).once.and_return(job_id)
41
36
  start_server do
42
37
  expect(capture_status_updates(3) {
@@ -47,7 +42,7 @@ describe Sidekiq::Status::ServerMiddleware do
47
42
  expect(Sidekiq::Status::interrupted?(job_id)).to be_truthy
48
43
  end
49
44
 
50
- it "on interrupt signal" do
45
+ it "on interrupt signal" do
51
46
  allow(SecureRandom).to receive(:hex).once.and_return(job_id)
52
47
  start_server do
53
48
  expect(capture_status_updates(3) {
@@ -79,7 +74,7 @@ describe Sidekiq::Status::ServerMiddleware do
79
74
  start_server(:expiration => huge_expiration) do
80
75
  StubJob.perform_async(:arg1 => 'val1')
81
76
  end
82
- expect((Sidekiq::Status::DEFAULT_EXPIRY+1)..huge_expiration).to cover redis.ttl("sidekiq:status:#{job_id}")
77
+ expect((Sidekiq::Status::DEFAULT_EXPIRY-1)..huge_expiration).to cover redis.ttl("sidekiq:status:#{job_id}")
83
78
  end
84
79
 
85
80
  it "can be overwritten by worker expiration method" do
@@ -8,30 +8,44 @@ describe 'sidekiq status web' do
8
8
  let!(:redis) { Sidekiq.redis { |conn| conn } }
9
9
  let!(:job_id) { SecureRandom.hex(12) }
10
10
 
11
- # Clean Redis before each test
12
- # Seems like flushall has no effect on recently published messages,
13
- # so we should wait till they expire
14
- before { redis.flushall; sleep 0.1 }
15
-
16
11
  def app
17
12
  Sidekiq::Web
18
13
  end
19
14
 
20
- it 'shows a job in progress' do
15
+ before do
21
16
  client_middleware
22
17
  allow(SecureRandom).to receive(:hex).and_return(job_id)
18
+ end
19
+
20
+ around { |example| start_server(&example) }
21
+
22
+ it 'shows the list of jobs in progress' do
23
+ capture_status_updates(2) do
24
+ expect(LongJob.perform_async(1)).to eq(job_id)
25
+ end
23
26
 
24
- start_server do
25
- capture_status_updates(2) do
26
- expect(LongJob.perform_async(1)).to eq(job_id)
27
- end
27
+ get '/statuses'
28
+ expect(last_response).to be_ok
29
+ expect(last_response.body).to match(/#{job_id}/)
30
+ expect(last_response.body).to match(/LongJob/)
31
+ expect(last_response.body).to match(/working/)
32
+ end
28
33
 
29
- get '/statuses'
30
- expect(last_response).to be_ok
31
- expect(last_response.body).to match(/#{job_id}/)
32
- expect(last_response.body).to match(/LongJob/)
33
- expect(last_response.body).to match(/working/)
34
+ it 'shows a single job in progress' do
35
+ capture_status_updates(2) do
36
+ LongJob.perform_async(1, 'another argument')
34
37
  end
38
+
39
+ get "/statuses/#{job_id}"
40
+ expect(last_response).to be_ok
41
+ expect(last_response.body).to match(/#{job_id}/)
42
+ expect(last_response.body).to match(/1,"another argument"/)
43
+ expect(last_response.body).to match(/working/)
35
44
  end
36
45
 
46
+ it 'show an error when the requested job ID is not found' do
47
+ get '/statuses/12345'
48
+ expect(last_response).to be_not_found
49
+ expect(last_response.body).to match(/That job can't be found/)
50
+ end
37
51
  end
@@ -9,11 +9,6 @@ describe Sidekiq::Status do
9
9
  let!(:plain_sidekiq_job_id) { SecureRandom.hex(12) }
10
10
  let!(:retried_job_id) { SecureRandom.hex(12) }
11
11
 
12
- # Clean Redis before each test
13
- # Seems like flushall has no effect on recently published messages,
14
- # so we should wait till they expire
15
- before { redis.flushall; sleep 0.1 }
16
-
17
12
  describe ".status, .working?, .complete?" do
18
13
  it "gets job status by id as symbol" do
19
14
  allow(SecureRandom).to receive(:hex).once.and_return(job_id)
@@ -82,6 +77,23 @@ describe Sidekiq::Status do
82
77
  end
83
78
  end
84
79
 
80
+ describe '.delete' do
81
+ it 'deletes the status hash for given job id' do
82
+ allow(SecureRandom).to receive(:hex).once.and_return(job_id)
83
+ start_server do
84
+ expect(capture_status_updates(2) {
85
+ expect(LongJob.perform_async(1)).to eq(job_id)
86
+ }).to eq([job_id]*2)
87
+ end
88
+ expect(Sidekiq::Status.delete(job_id)).to eq(1)
89
+ end
90
+
91
+ it 'should not raise error while deleting status hash if invalid job id' do
92
+ allow(SecureRandom).to receive(:hex).once.and_return(job_id)
93
+ expect(Sidekiq::Status.delete(job_id)).to eq(0)
94
+ end
95
+ end
96
+
85
97
  describe ".cancel" do
86
98
  it "cancels a job by id" do
87
99
  allow(SecureRandom).to receive(:hex).twice.and_return(job_id, job_id_1)
data/spec/spec_helper.rb CHANGED
@@ -1,15 +1,21 @@
1
1
  require "rspec"
2
2
 
3
- require 'celluloid'
4
3
  require 'sidekiq'
5
4
  require 'sidekiq/processor'
6
5
  require 'sidekiq/manager'
7
6
  require 'sidekiq-status'
8
7
 
8
+ # Clears jobs before every test
9
+ RSpec.configure do |config|
10
+ config.before(:each) do
11
+ Sidekiq.redis { |conn| conn.flushall }
12
+ sleep 0.05
13
+ end
14
+ end
9
15
 
10
16
  Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
11
17
 
12
- def client_middleware(client_middleware_options={})
18
+ def client_middleware(client_middleware_options={})
13
19
  Sidekiq.configure_client do |config|
14
20
  config.client_middleware do |chain|
15
21
  chain.add Sidekiq::Status::ClientMiddleware, client_middleware_options
@@ -52,7 +58,9 @@ def start_server(server_middleware_options={})
52
58
  $stderr.reopen File::NULL, 'w'
53
59
  require 'sidekiq/cli'
54
60
  Sidekiq.options[:queues] << 'default'
55
- Sidekiq.options[:require] = File.expand_path('../support/test_jobs.rb', __FILE__)
61
+ Sidekiq.options[:require] = File.expand_path('environment.rb', File.dirname(__FILE__))
62
+ Sidekiq.options[:timeout] = 1
63
+ Sidekiq.options[:concurrency] = 5
56
64
  Sidekiq.configure_server do |config|
57
65
  config.redis = Sidekiq::RedisConnection.create
58
66
  config.server_middleware do |chain|
@@ -65,7 +73,7 @@ def start_server(server_middleware_options={})
65
73
  yield
66
74
  sleep 0.1
67
75
  Process.kill 'TERM', pid
68
- Timeout::timeout(10) { Process.wait pid } rescue Timeout::Error
76
+ Timeout::timeout(5) { Process.wait pid } rescue Timeout::Error
69
77
  ensure
70
78
  Process.kill 'KILL', pid rescue "OK" # it's OK if the process is gone already
71
79
  end
@@ -1,3 +1,5 @@
1
+ require 'sidekiq-status'
2
+
1
3
  class StubJob
2
4
  include Sidekiq::Worker
3
5
  include Sidekiq::Status::Worker
@@ -10,7 +12,7 @@ end
10
12
 
11
13
  class LongJob < StubJob
12
14
  def perform(*args)
13
- sleep args[0] || 1
15
+ sleep args[0] || 0.25
14
16
  end
15
17
  end
16
18
 
Binary file
@@ -0,0 +1,73 @@
1
+ <style>
2
+ .progress {
3
+ background-color: #C8E1ED;
4
+ }
5
+ .progress-percentage {
6
+ margin: 5px;
7
+ padding-left: 4px;
8
+ color: #333;
9
+ text-align: left;
10
+ text-shadow: 0 0 5px white;
11
+ font-weight: bold;
12
+ font-size: 14px;
13
+ }
14
+ </style>
15
+
16
+ <h3>
17
+ Job Status: <%= @status.jid %>
18
+ <span class='label label-<%= @status.label %>'>
19
+ <%= @status.status %>
20
+ </span>
21
+ </h3>
22
+
23
+ <div class="progress" style="height: 30px;">
24
+ <div class="progress-bar" role="progressbar" aria-valuenow="<%= @status.pct_complete.to_i %>" aria-valuemin="0" aria-valuemax="100" style="width: <%= @status.pct_complete.to_i %>%">
25
+ <div class="progress-percentage">
26
+ <%= @status.pct_complete.to_i %>%
27
+ </div>
28
+ </div>
29
+ </div>
30
+
31
+ <div class="panel panel-default">
32
+ <div class="panel-body">
33
+ <h4><%= @status.worker %></h4>
34
+
35
+ <div class="row">
36
+ <div class="col-sm-2">
37
+ <strong>Arguments</strong>
38
+ </div>
39
+ <div class="col-sm-10">
40
+ <p><%= @status.args.empty? ? "<i>none</i>" : @status.args %></p>
41
+ </div>
42
+ </div>
43
+
44
+ <div class="row">
45
+ <div class="col-sm-2">
46
+ <strong>Message</strong>
47
+ </div>
48
+ <div class="col-sm-10">
49
+ <p><%= @status.message || "<i>none</i>" %></p>
50
+ </div>
51
+ </div>
52
+
53
+ <div class="row">
54
+ <div class="col-sm-2">
55
+ <strong>Last Updated</strong>
56
+ </div>
57
+ <div class="col-sm-10">
58
+ <p>
59
+ <% secs = Time.now.to_i - @status.update_time.to_i %>
60
+ <% if secs > 0 %>
61
+ <%= secs %> sec<%= secs == 1 ? '' : 's' %> ago
62
+ <% else %>
63
+ Now
64
+ <% end %>
65
+ </p>
66
+ </div>
67
+ </div>
68
+ </div>
69
+ </div>
70
+
71
+ <a href="<%= root_path %>statuses">
72
+ <small>&larr; back to all statuses</small>
73
+ </a>
@@ -0,0 +1,5 @@
1
+ <h3>Job Status: <%= params[:jid] %></h3>
2
+
3
+ <div class="alert alert-danger" role="alert">
4
+ <strong>Uh oh!</strong> That job can't be found. It may have expired already.
5
+ </div>
@@ -4,8 +4,8 @@
4
4
  background-color: #C8E1ED;
5
5
  }
6
6
  .bar {
7
- background-color: #2897cb;
8
- color: white;
7
+ background-color: #2897cb;
8
+ color: white;
9
9
  text-shadow: 0 0 0;
10
10
  }
11
11
  .message {
@@ -16,21 +16,28 @@
16
16
  .header{
17
17
  text-align: center;
18
18
  }
19
+ .header_update_time{
20
+ width: 10%;
21
+ }
22
+ .header_pct_complete{
23
+ width: 45%;
24
+ }
25
+
19
26
  </style>
20
27
 
21
28
  <h3 class="wi">Recent job statuses</h3>
22
- <table class="table table-hover table-bordered table-striped table-white">
29
+ <table class="table table-hover table-bordered table-striped table-white">
23
30
  <tr>
24
- <th class="header">Worker/jid</th>
25
- <th class="header">Arguments</th>
26
- <th class="header">Status</th>
27
- <th class="header" style="width: 10%;">Last Updated</th>
28
- <th class="header" style="width: 45%;">Progress</th>
31
+ <% @headers.each do |h| %>
32
+ <th class="header <%= h[:class] %> header_<%= h[:id] %>">
33
+ <a href="<%= h[:url] %>"><%= h[:name] %></a>
34
+ </th>
35
+ <% end %>
29
36
  </tr>
30
37
  <% @statuses.each do |container| %>
31
38
  <tr>
32
39
  <td>
33
- <div title='<%= container.jid %>'><%= container.worker %></div>
40
+ <div title='<%= container.jid %>'><a href="<%= root_path %>statuses/<%= container.jid %>"><%= container.worker %></a></div>
34
41
  </td>
35
42
  <td>
36
43
  <div class='args' title='<%= container.jid %>'><%= container.args %></div>
@@ -39,9 +46,9 @@
39
46
  <div class='label label-<%= container.label %>'><%= container.status %></div>
40
47
  </td>
41
48
  <% secs = Time.now.to_i - container.update_time.to_i %>
42
- <td style='text-align: center;'>
49
+ <td style='text-align: center; white-space: nowrap;' title="<%= Time.at(container.update_time.to_i) %>">
43
50
  <% if secs > 0 %>
44
- <%= secs %> sec<%= secs == 1 ? '' : 's' %> ago
51
+ <%= ChronicDuration.output(secs, :weeks => true, :units => 2) %> ago
45
52
  <% else %>
46
53
  Now
47
54
  <% end %>
@@ -65,4 +72,4 @@
65
72
  <td colspan="6"></td>
66
73
  </tr>
67
74
  <% end %>
68
- </table>
75
+ </table>
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sidekiq-status
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evgeniy Tsvigun
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-12-27 00:00:00.000000000 Z
11
+ date: 2017-11-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sidekiq
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: chronic_duration
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: rack-test
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -95,7 +109,6 @@ files:
95
109
  - LICENSE
96
110
  - README.md
97
111
  - Rakefile
98
- - gemfiles/Gemfile.sidekiq-2
99
112
  - lib/sidekiq-status.rb
100
113
  - lib/sidekiq-status/client_middleware.rb
101
114
  - lib/sidekiq-status/server_middleware.rb
@@ -105,6 +118,7 @@ files:
105
118
  - lib/sidekiq-status/web.rb
106
119
  - lib/sidekiq-status/worker.rb
107
120
  - sidekiq-status.gemspec
121
+ - spec/environment.rb
108
122
  - spec/lib/sidekiq-status/client_middleware_spec.rb
109
123
  - spec/lib/sidekiq-status/server_middleware_spec.rb
110
124
  - spec/lib/sidekiq-status/testing_spec.rb
@@ -113,7 +127,10 @@ files:
113
127
  - spec/lib/sidekiq-status_spec.rb
114
128
  - spec/spec_helper.rb
115
129
  - spec/support/test_jobs.rb
130
+ - web/sidekiq-status-single-web.png
116
131
  - web/sidekiq-status-web.png
132
+ - web/views/status.erb
133
+ - web/views/status_not_found.erb
117
134
  - web/views/statuses.erb
118
135
  homepage: http://github.com/utgarda/sidekiq-status
119
136
  licenses:
@@ -135,11 +152,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
135
152
  version: '0'
136
153
  requirements: []
137
154
  rubyforge_project:
138
- rubygems_version: 2.4.5.1
155
+ rubygems_version: 2.6.13
139
156
  signing_key:
140
157
  specification_version: 4
141
158
  summary: An extension to the sidekiq message processing to track your jobs
142
159
  test_files:
160
+ - spec/environment.rb
143
161
  - spec/lib/sidekiq-status/client_middleware_spec.rb
144
162
  - spec/lib/sidekiq-status/server_middleware_spec.rb
145
163
  - spec/lib/sidekiq-status/testing_spec.rb
@@ -1,5 +0,0 @@
1
- source "https://rubygems.org"
2
-
3
- gemspec path: '..'
4
-
5
- gem 'sidekiq', '~> 2.17'