sidekiq-status 3.0.0 → 3.0.2

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
  SHA256:
3
- metadata.gz: 5188215b7cc5735ac70ba8ea4fa9d62df0a2b8d317b901540bf9665bbf5b0e9a
4
- data.tar.gz: 4db9d510d4a0908c6a6763f1b89075fa7e031779387c8c05d7940719a3da404f
3
+ metadata.gz: 7c2c40656501ca39c5bc87ec1b1a81acc8f8f24fcde74dfe13b60a3659ae67fb
4
+ data.tar.gz: 1647fe3d39f47444615bf83e6ba31d69ad750fdab07c23a7cafeb85f15991b93
5
5
  SHA512:
6
- metadata.gz: de2e9e08e65532dce024e2250e641b6a25833fdf5e977c86860018225c7769538d16076c627eb2f90af1ac4b9b0e035fc347c3651bcae06af43a4e622eef147b
7
- data.tar.gz: 3b1508b26d23b45b48692e033d78341dd65ca81f9382bd2498cee07f236b781a176c52dbb079a37409242ffd61632266d00e5c99e60d37eba434e495245117bd
6
+ metadata.gz: 29f7ba740739147cf2a3f3050d89ed89403d83c39e1c23d31246e4c5a0f73883a1cf7146c5b11d378673a057ab6629c76fd666c9436c5f14b4ef292e0765a0ff
7
+ data.tar.gz: c71ff262e667f0c1f330dbcf0ab51783cef4d7a5fe37a7406465d3f6a8df51b1989040b817fd2c3f671c63cb0ea670eeb46240e9c4b6b0ab332544b779e75060
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ **Version 3.0.2**
2
+ - Avoids setting statuses for non-status jobs when an exception is thrown (https://github.com/kenaniah/sidekiq-status/pull/32)
3
+
4
+ **Version 3.0.1**
5
+ - Adds elapsed time and ETA to the job status page (https://github.com/kenaniah/sidekiq-status/pull/13)
6
+
1
7
  **Version 3.0.0**
2
8
  - Drops support for Sidekiq 5.x
3
9
  - Adds support for Sidekiq 7.x
data/README.md CHANGED
@@ -1,7 +1,6 @@
1
1
  # Sidekiq::Status
2
2
  [![Gem Version](https://badge.fury.io/rb/sidekiq-status.svg)](https://badge.fury.io/rb/sidekiq-status)
3
3
  [![Build Status](https://github.com/kenaniah/sidekiq-status/actions/workflows/ci.yaml/badge.svg)](https://github.com/kenaniah/sidekiq-status/actions/)
4
- [![Inline docs](https://inch-ci.org/github/kenaniah/sidekiq-status.svg?branch=main)](https://inch-ci.org/github/kenaniah/sidekiq-status)
5
4
 
6
5
  Sidekiq-status is an extension to [Sidekiq](https://github.com/mperham/sidekiq) that tracks information about your Sidekiq and provides a UI to that purpose. It was inspired by [resque-status](https://github.com/quirkey/resque-status).
7
6
 
@@ -21,6 +20,10 @@ Or install it yourself as:
21
20
  gem install sidekiq-status
22
21
  ```
23
22
 
23
+ ### Migrating to Version 3.x from 2.x
24
+
25
+ Version 3.0.0 adds support for Sidekiq 7.x, but drops support for Sidekiq 5.x. **You should be able to upgrade cleanly from version 2.x to 3.x provided you are running Sidekiq 6.x or newer.**
26
+
24
27
  #### Migrating to Version 2.x from 1.x
25
28
 
26
29
  Version 2.0.0 was published in order to add support for Ruby 3.0 and Sidekiq 6.x and to remove support for versions of both that are now end-of-life. **You should be able to upgrade cleanly from version 1.x to 2.x provided you are running Sidekiq 5.x or newer.**
@@ -46,15 +49,15 @@ require 'sidekiq-status'
46
49
 
47
50
  Sidekiq.configure_client do |config|
48
51
  # accepts :expiration (optional)
49
- Sidekiq::Status.configure_client_middleware config, expiration: 30.minutes
52
+ Sidekiq::Status.configure_client_middleware config, expiration: 30.minutes.to_i
50
53
  end
51
54
 
52
55
  Sidekiq.configure_server do |config|
53
56
  # accepts :expiration (optional)
54
- Sidekiq::Status.configure_server_middleware config, expiration: 30.minutes
57
+ Sidekiq::Status.configure_server_middleware config, expiration: 30.minutes.to_i
55
58
 
56
59
  # accepts :expiration (optional)
57
- Sidekiq::Status.configure_client_middleware config, expiration: 30.minutes
60
+ Sidekiq::Status.configure_client_middleware config, expiration: 30.minutes.to_i
58
61
  end
59
62
  ```
60
63
 
@@ -175,6 +178,8 @@ Sidekiq::Status::at job_id #=> 5
175
178
  Sidekiq::Status::total job_id #=> 100
176
179
  Sidekiq::Status::message job_id #=> "Almost done"
177
180
  Sidekiq::Status::pct_complete job_id #=> 5
181
+ Sidekiq::Status::working_at job_id #=> 2718
182
+ Sidekiq::Status::update_time job_id #=> 2819
178
183
  ```
179
184
 
180
185
  ### Unscheduling
@@ -43,26 +43,28 @@ module Sidekiq::Status
43
43
  return
44
44
  end
45
45
 
46
- # Determine job expiration
47
- expiry = job_class.new.expiration || @expiration rescue @expiration
48
-
49
- store_status worker.jid, :working, expiry
50
- yield
51
- store_status worker.jid, :complete, expiry
52
- rescue Worker::Stopped
53
- store_status worker.jid, :stopped, expiry
54
- rescue SystemExit, Interrupt
55
- store_status worker.jid, :interrupted, expiry
56
- raise
57
- rescue Exception
58
- status = :failed
59
- if msg['retry']
60
- if retry_attempt_number(msg) < retry_attempts_from(msg['retry'], DEFAULT_MAX_RETRY_ATTEMPTS)
61
- status = :retrying
46
+ begin
47
+ # Determine job expiration
48
+ expiry = job_class.new.expiration || @expiration rescue @expiration
49
+
50
+ store_status worker.jid, :working, expiry
51
+ yield
52
+ store_status worker.jid, :complete, expiry
53
+ rescue Worker::Stopped
54
+ store_status worker.jid, :stopped, expiry
55
+ rescue SystemExit, Interrupt
56
+ store_status worker.jid, :interrupted, expiry
57
+ raise
58
+ rescue Exception
59
+ status = :failed
60
+ if msg['retry']
61
+ if retry_attempt_number(msg) < retry_attempts_from(msg['retry'], DEFAULT_MAX_RETRY_ATTEMPTS)
62
+ status = :retrying
63
+ end
62
64
  end
65
+ store_status(worker.jid, status, expiry) if job_class && job_class.ancestors.include?(Sidekiq::Status::Worker)
66
+ raise
63
67
  end
64
- store_status(worker.jid, status, expiry) if job_class && job_class.ancestors.include?(Sidekiq::Status::Worker)
65
- raise
66
68
  end
67
69
 
68
70
  private
@@ -1,5 +1,5 @@
1
1
  module Sidekiq
2
2
  module Status
3
- VERSION = '3.0.0'
3
+ VERSION = '3.0.2'
4
4
  end
5
5
  end
@@ -8,7 +8,7 @@ module Sidekiq::Status
8
8
 
9
9
  DEFAULT_PER_PAGE_OPTS = [25, 50, 100].freeze
10
10
  DEFAULT_PER_PAGE = 25
11
- COMMON_STATUS_HASH_KEYS = %w(update_time jid status worker args label pct_complete total at message)
11
+ COMMON_STATUS_HASH_KEYS = %w(update_time jid status worker args label pct_complete total at message working_at elapsed eta)
12
12
 
13
13
  class << self
14
14
  def per_page_opts= arr
@@ -48,6 +48,8 @@ module Sidekiq::Status
48
48
  def add_details_to_status(status)
49
49
  status['label'] = status_label(status['status'])
50
50
  status["pct_complete"] ||= pct_complete(status)
51
+ status["elapsed"] ||= elapsed(status).to_s
52
+ status["eta"] ||= eta(status).to_s
51
53
  status["custom"] = process_custom_data(status)
52
54
  return status
53
55
  end
@@ -61,6 +63,19 @@ module Sidekiq::Status
61
63
  Sidekiq::Status::pct_complete(status['jid']) || 0
62
64
  end
63
65
 
66
+ def elapsed(status)
67
+ case status['status']
68
+ when 'complete'
69
+ Sidekiq::Status.update_time(status['jid']) - Sidekiq::Status.working_at(status['jid'])
70
+ when 'working', 'retrying'
71
+ Time.now.to_i - Sidekiq::Status.working_at(status['jid'])
72
+ end
73
+ end
74
+
75
+ def eta(status)
76
+ Sidekiq::Status.eta(status['jid']) if status['status'] == 'working'
77
+ end
78
+
64
79
  def status_label(status)
65
80
  case status
66
81
  when 'complete'
@@ -122,6 +137,8 @@ module Sidekiq::Status
122
137
  {id: "status", name: "Status", class: nil, url: nil},
123
138
  {id: "update_time", name: "Last Updated", class: nil, url: nil},
124
139
  {id: "pct_complete", name: "Progress", class: nil, url: nil},
140
+ {id: "elapsed", name: "Time Elapsed", class: nil, url: nil},
141
+ {id: "eta", name: "ETA", class: nil, url: nil},
125
142
  ]
126
143
 
127
144
  @headers.each do |h|
@@ -29,7 +29,7 @@ module Sidekiq::Status::Worker
29
29
  def at(num, message = nil)
30
30
  @_status_total = 100 if @_status_total.nil?
31
31
  pct_complete = ((num / @_status_total.to_f) * 100).to_i rescue 0
32
- store(at: num, total: @_status_total, pct_complete: pct_complete, message: message)
32
+ store(at: num, total: @_status_total, pct_complete: pct_complete, message: message, working_at: working_at)
33
33
  end
34
34
 
35
35
  # Sets total number of tasks
@@ -37,7 +37,12 @@ module Sidekiq::Status::Worker
37
37
  # @return [String]
38
38
  def total(num)
39
39
  @_status_total = num
40
- store(total: num)
40
+ store(total: num, working_at: working_at)
41
41
  end
42
42
 
43
+ private
44
+
45
+ def working_at
46
+ @working_at ||= Time.now.to_i
47
+ end
43
48
  end
@@ -63,6 +63,21 @@ module Sidekiq::Status
63
63
  get(job_id, :pct_complete).to_i
64
64
  end
65
65
 
66
+ def working_at(job_id)
67
+ (get(job_id, :working_at) || Time.now).to_i
68
+ end
69
+
70
+ def update_time(job_id)
71
+ (get(job_id, :update_time) || Time.now).to_i
72
+ end
73
+
74
+ def eta(job_id)
75
+ at = at(job_id)
76
+ return nil if at.zero?
77
+
78
+ (Time.now.to_i - working_at(job_id)).to_f / at * (total(job_id) - at)
79
+ end
80
+
66
81
  def message(job_id)
67
82
  get(job_id, :message)
68
83
  end
@@ -61,6 +61,22 @@ describe Sidekiq::Status::ServerMiddleware do
61
61
  end
62
62
  expect(redis.hget("sidekiq:status:#{job_id}", :status)).to be_nil
63
63
  end
64
+
65
+ it "should not set any status on system exit signal" do
66
+ allow(SecureRandom).to receive(:hex).once.and_return(job_id)
67
+ start_server do
68
+ expect(ExitedNoStatusJob.perform_async).to eq(job_id)
69
+ end
70
+ expect(redis.hget("sidekiq:status:#{job_id}", :status)).to be_nil
71
+ end
72
+
73
+ it "should not set any status on interrupt signal" do
74
+ allow(SecureRandom).to receive(:hex).once.and_return(job_id)
75
+ start_server do
76
+ expect(InterruptedNoStatusJob.perform_async).to eq(job_id)
77
+ end
78
+ expect(redis.hget("sidekiq:status:#{job_id}", :status)).to be_nil
79
+ end
64
80
  end
65
81
 
66
82
  context "sets interrupted status" do
@@ -20,4 +20,22 @@ describe Sidekiq::Status::Worker do
20
20
  expect(subject.expiration).to eq(:val)
21
21
  end
22
22
  end
23
+
24
+ describe ".at" do
25
+ subject { StubJob.new }
26
+
27
+ it "records when the worker has started" do
28
+ expect { subject.at(0) }.to(change { subject.retrieve('working_at') })
29
+ end
30
+
31
+ context "when setting the total for the worker" do
32
+ it "records when the worker has started" do
33
+ expect { subject.total(100) }.to(change { subject.retrieve('working_at') })
34
+ end
35
+ end
36
+
37
+ it "records when the worker last worked" do
38
+ expect { subject.at(0) }.to(change { subject.retrieve('update_time') })
39
+ end
40
+ end
23
41
  end
@@ -111,12 +111,24 @@ class ExitedJob < StubJob
111
111
  end
112
112
  end
113
113
 
114
+ class ExitedNoStatusJob < StubNoStatusJob
115
+ def perform
116
+ raise SystemExit
117
+ end
118
+ end
119
+
114
120
  class InterruptedJob < StubJob
115
121
  def perform
116
122
  raise Interrupt
117
123
  end
118
124
  end
119
125
 
126
+ class InterruptedNoStatusJob < StubNoStatusJob
127
+ def perform
128
+ raise Interrupt
129
+ end
130
+ end
131
+
120
132
  class RetriedJob < StubJob
121
133
 
122
134
  sidekiq_options retry: true
data/web/views/status.erb CHANGED
@@ -67,6 +67,32 @@
67
67
  </div>
68
68
  </div>
69
69
 
70
+ <div class="row">
71
+ <div class="col-sm-2">
72
+ <strong>Elapsed Time</strong>
73
+ </div>
74
+ <div class="col-sm-10">
75
+ <p>
76
+ <% if @status["elapsed"] %>
77
+ <%= ChronicDuration.output(@status["elapsed"].to_i, :weeks => true, :units => 2) %>
78
+ <% end %>
79
+ </p>
80
+ </div>
81
+ </div>
82
+
83
+ <div class="row">
84
+ <div class="col-sm-2">
85
+ <strong>ETA</strong>
86
+ </div>
87
+ <div class="col-sm-10">
88
+ <p>
89
+ <% if @status["eta"] %>
90
+ <%= ChronicDuration.output(@status["eta"].to_i, :weeks => true, :units => 2) %>
91
+ <% end %>
92
+ </p>
93
+ </div>
94
+ </div>
95
+
70
96
  <% if @status["custom"].any? %>
71
97
  <hr>
72
98
  <% @status["custom"].each do |key, val| %>
@@ -119,6 +119,16 @@ function setPerPage(select){
119
119
  <% end %>
120
120
  </div>
121
121
  </td>
122
+ <td style='text-align: center; white-space: nowrap;'>
123
+ <% if container["elapsed"] %>
124
+ <%= ChronicDuration.output(container["elapsed"].to_i, :weeks => true, :units => 2) %>
125
+ <% end %>
126
+ </td>
127
+ <td style='text-align: center; white-space: nowrap;'>
128
+ <% if container["eta"] %>
129
+ <%= ChronicDuration.output(container["eta"].to_i, :weeks => true, :units => 2) %>
130
+ <% end %>
131
+ </td>
122
132
  <td>
123
133
  <div class="actions">
124
134
  <form action="statuses" method="post">
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sidekiq-status
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 3.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evgeniy Tsvigun
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-02-10 00:00:00.000000000 Z
12
+ date: 2023-04-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sidekiq