sidekiq-status 2.1.2 → 3.0.3

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: c02846f130e9fc47945e6e85e03d2e5cb5033e1d5a55f8b9ade921b72839f3a4
4
- data.tar.gz: e236b4fd1fd3b94387b31786fe0aff021904b1947cf3bc2b26e66fceb6e38ca2
3
+ metadata.gz: 7c4653623b20223d993b2c5f2ce82a1ee214083c1adb51530a76d82e4d2b3977
4
+ data.tar.gz: 6cee1ff677b1b964465e79facf5dd1e747c6747f9e99c7fd54e0330082a4b201
5
5
  SHA512:
6
- metadata.gz: 274efd30dff5904a2c1b39c2940e6785f8a446aada35e2a6fe38e58ddbc22ce0866e84e487e2bebfa439ca7ed06f862ff30c15fd3df5c48a3b59f03a6eabb95b
7
- data.tar.gz: 590bd3e108417ba70cfa7706885a524f014f80ead06aef364b113099620fb362cafa181c0640ef2adb9309891ed33b3bac41585944e9a091716bc4ae4cf553ef
6
+ metadata.gz: 99971994088169aa3ba0c21417557ce9d9fc072917b06c05a9cb7815f0405e331882f057d56079b41256f028c8248a780d9f74592a660a850959109a579519cc
7
+ data.tar.gz: aa7030ebbbb8161f5e9e81c3fac25357cac7bff62d810a3f785e9343c12c3a5839f94060d993aafc5381700b7803ca5e1de17dcb00762525eda6fa9a6bdb4725
@@ -0,0 +1,53 @@
1
+ name: Ruby CI
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ pull_request:
8
+ branches:
9
+ - main
10
+
11
+ jobs:
12
+ test:
13
+
14
+ runs-on: ubuntu-latest
15
+
16
+ services:
17
+ redis:
18
+ image: redis
19
+ options: >-
20
+ --health-cmd "redis-cli ping"
21
+ --health-interval 10s
22
+ --health-timeout 5s
23
+ --health-retries 5
24
+ ports:
25
+ - 6379:6379
26
+
27
+ strategy:
28
+ fail-fast: false
29
+ matrix:
30
+ ruby-version:
31
+ - '2.7'
32
+ - '3.0'
33
+ - '3.1'
34
+ - '3.2'
35
+ gemfile:
36
+ - 'gemfiles/sidekiq_6.1.gemfile'
37
+ - 'gemfiles/sidekiq_6.x.gemfile'
38
+ - 'gemfiles/sidekiq_7.x.gemfile'
39
+
40
+ env:
41
+ BUNDLE_GEMFILE: ${{ github.workspace }}/${{ matrix.gemfile }}
42
+
43
+ steps:
44
+ - uses: actions/checkout@v3
45
+ - name: Set up Ruby ${{ matrix.ruby-version }}
46
+ uses: ruby/setup-ruby@v1
47
+ with:
48
+ ruby-version: ${{ matrix.ruby-version }}
49
+ bundler-cache: true
50
+ rubygems: latest
51
+ - name: Run tests
52
+ run: |
53
+ bundle exec rake test
data/CHANGELOG.md CHANGED
@@ -1,23 +1,40 @@
1
+ **Version 3.0.3**
2
+ - Fixes a Sidekiq warning about the deprecated `hmset` redis command (https://github.com/kenaniah/sidekiq-status/pull/37)
3
+
4
+ **Version 3.0.2**
5
+ - Avoids setting statuses for non-status jobs when an exception is thrown (https://github.com/kenaniah/sidekiq-status/pull/32)
6
+
7
+ **Version 3.0.1**
8
+ - Adds elapsed time and ETA to the job status page (https://github.com/kenaniah/sidekiq-status/pull/13)
9
+
10
+ **Version 3.0.0**
11
+ - Drops support for Sidekiq 5.x
12
+ - Adds support for Sidekiq 7.x
13
+ - Migrates from Travis CI to GitHub Actions
14
+
15
+ **Version 2.1.3**
16
+ - Fixes redis deprecation warnings (https://github.com/kenaniah/sidekiq-status/issues/11)
17
+
1
18
  **Version 2.1.2**
2
- * Casts values to strings when HTML-encoding
19
+ - Casts values to strings when HTML-encoding
3
20
 
4
21
  **Version 2.1.1**
5
- * Ensures parameter outputs are properly HTML-encoded
22
+ - Ensures parameter outputs are properly HTML-encoded
6
23
 
7
24
  **Version 2.1.0**
8
- * Adds support for Sidekiq 6.2.2+ (https://github.com/mperham/sidekiq/issues/4955)
25
+ - Adds support for Sidekiq 6.2.2+ (https://github.com/mperham/sidekiq/issues/4955)
9
26
 
10
27
  **Version 2.0.2**
11
- * Fixes for dark mode theme
28
+ - Fixes for dark mode theme
12
29
 
13
30
  **Version 2.0.1**
14
- * Adds support for dark mode to the job status page
31
+ - Adds support for dark mode to the job status page
15
32
 
16
33
  **Version 2.0.0**
17
- * Adds support for Ruby 2.7, 3.0
18
- * Adds support for Sidekiq 6.x
19
- * Removes support for Ruby 2.3, 2.4, 2.5
20
- * Removes support for Sidekiq 3.x, 4.x
34
+ - Adds support for Ruby 2.7, 3.0
35
+ - Adds support for Sidekiq 6.x
36
+ - Removes support for Ruby 2.3, 2.4, 2.5
37
+ - Removes support for Sidekiq 3.x, 4.x
21
38
 
22
39
  **Versions 1.1.4 and prior**
23
40
 
data/README.md CHANGED
@@ -1,11 +1,10 @@
1
1
  # Sidekiq::Status
2
2
  [![Gem Version](https://badge.fury.io/rb/sidekiq-status.svg)](https://badge.fury.io/rb/sidekiq-status)
3
- [![Build Status](https://www.travis-ci.com/kenaniah/sidekiq-status.svg?branch=main)](https://www.travis-ci.com/github/kenaniah/sidekiq-status)
4
- [![Inline docs](https://inch-ci.org/github/kenaniah/sidekiq-status.svg?branch=main)](https://inch-ci.org/github/kenaniah/sidekiq-status)
3
+ [![Build Status](https://github.com/kenaniah/sidekiq-status/actions/workflows/ci.yaml/badge.svg)](https://github.com/kenaniah/sidekiq-status/actions/)
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
 
8
- Requires Ruby 2.6+ and Sidekiq 5.0+ or newer.
7
+ Requires Ruby 2.6+ and Sidekiq 6.0+ or newer.
9
8
 
10
9
  ## Installation
11
10
 
@@ -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
@@ -2,6 +2,6 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "sidekiq", "~> 5"
5
+ gem "sidekiq", "~> 7"
6
6
 
7
7
  gemspec path: "../"
@@ -48,7 +48,7 @@ module Sidekiq::Status
48
48
 
49
49
  def display_args(msg, queue)
50
50
  job = JOB_CLASS.new(msg, queue)
51
- return job.display_args.to_a.empty? ? nil : job.display_args.to_json
51
+ return job.display_args.to_a.empty? ? "{}" : job.display_args.to_json
52
52
  rescue Exception => e
53
53
  # For Sidekiq ~> 2.7
54
54
  return msg['args'].to_a.empty? ? nil : msg['args'].to_json
@@ -0,0 +1,18 @@
1
+ # adapter for redis-rb client
2
+ class Sidekiq::Status::RedisAdapter
3
+ def initialize(client)
4
+ @client = client
5
+ end
6
+
7
+ def scan(**options, &block)
8
+ @client.scan_each(**options, &block)
9
+ end
10
+
11
+ def schedule_batch(key, options)
12
+ @client.zrangebyscore key, options[:start], options[:end], limit: [options[:offset], options[:limit]]
13
+ end
14
+
15
+ def method_missing(method, *args)
16
+ @client.send(method, *args)
17
+ end
18
+ end
@@ -0,0 +1,14 @@
1
+ # adapter for redis-client client
2
+ class Sidekiq::Status::RedisClientAdapter
3
+ def initialize(client)
4
+ @client = client
5
+ end
6
+
7
+ def schedule_batch(key, options)
8
+ @client.zrange(key, options[:start], options[:end], :byscore, :limit, options[:offset], options[:limit])
9
+ end
10
+
11
+ def method_missing(method, *args)
12
+ @client.send(method, *args)
13
+ end
14
+ end
@@ -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
@@ -12,11 +12,12 @@ module Sidekiq::Status::Storage
12
12
  # @param [ConnectionPool] redis_pool optional redis connection pool
13
13
  # @return [String] Redis operation status code
14
14
  def store_for_id(id, status_updates, expiration = nil, redis_pool=nil)
15
+ status_updates.transform_values!(&:to_s)
15
16
  redis_connection(redis_pool) do |conn|
16
- conn.multi do
17
- conn.hmset key(id), 'update_time', Time.now.to_i, *(status_updates.to_a.flatten(1))
18
- conn.expire key(id), (expiration || Sidekiq::Status::DEFAULT_EXPIRY)
19
- conn.publish "status_updates", id
17
+ conn.multi do |pipeline|
18
+ pipeline.hset key(id), 'update_time', Time.now.to_i, *(status_updates.to_a.flatten(1))
19
+ pipeline.expire key(id), (expiration || Sidekiq::Status::DEFAULT_EXPIRY)
20
+ pipeline.publish "status_updates", id
20
21
  end[0]
21
22
  end
22
23
  end
@@ -36,7 +37,7 @@ module Sidekiq::Status::Storage
36
37
  # @param [String] id job id
37
38
  # @param [Num] job_unix_time, unix timestamp for the scheduled job
38
39
  def delete_and_unschedule(job_id, job_unix_time = nil)
39
- Sidekiq.redis do |conn|
40
+ Sidekiq::Status.redis_adapter do |conn|
40
41
  scan_options = {offset: 0, conn: conn, start: (job_unix_time || '-inf'), end: (job_unix_time || '+inf')}
41
42
 
42
43
  while not (jobs = schedule_batch(scan_options)).empty?
@@ -66,7 +67,7 @@ module Sidekiq::Status::Storage
66
67
  # @param [String] Symbol field fetched field name
67
68
  # @return [String] Redis operation status code
68
69
  def read_field_for_id(id, field)
69
- Sidekiq.redis do |conn|
70
+ Sidekiq::Status.redis_adapter do |conn|
70
71
  conn.hget(key(id), field)
71
72
  end
72
73
  end
@@ -75,8 +76,8 @@ module Sidekiq::Status::Storage
75
76
  # @param [String] id job id
76
77
  # @return [Hash] Hash stored in redis
77
78
  def read_hash_for_id(id)
78
- Sidekiq.redis do |conn|
79
- conn.hgetall key(id)
79
+ Sidekiq::Status.redis_adapter do |conn|
80
+ conn.hgetall(key(id))
80
81
  end
81
82
  end
82
83
 
@@ -90,7 +91,7 @@ module Sidekiq::Status::Storage
90
91
  # - end: end score (i.e. +inf or a unix timestamp)
91
92
  # - offset: current progress through (all) jobs (e.g.: 100 if you want jobs from 100 to BATCH_LIMIT)
92
93
  def schedule_batch(options)
93
- options[:conn].zrangebyscore "schedule", options[:start], options[:end], limit: [options[:offset], BATCH_LIMIT]
94
+ Sidekiq::Status.wrap_redis_connection(options[:conn]).schedule_batch("schedule", options.merge(limit: BATCH_LIMIT))
94
95
  end
95
96
 
96
97
  # Searches the jobs Array for the job_id
@@ -1,5 +1,5 @@
1
1
  module Sidekiq
2
2
  module Status
3
- VERSION = '2.1.2'
3
+ VERSION = '3.0.3'
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'
@@ -81,8 +96,8 @@ module Sidekiq::Status
81
96
 
82
97
  app.get '/statuses' do
83
98
 
84
- jids = Sidekiq.redis do |conn|
85
- conn.scan_each(match: 'sidekiq:status:*', count: 100).map do |key|
99
+ jids = Sidekiq::Status.redis_adapter do |conn|
100
+ conn.scan(match: 'sidekiq:status:*', count: 100).map do |key|
86
101
  key.split(':').last
87
102
  end.uniq
88
103
  end
@@ -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|
@@ -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 @provider_job_id || @job_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 @provider_job_id || @job_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
@@ -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
@@ -2,6 +2,8 @@ require 'sidekiq-status/version'
2
2
  require 'sidekiq-status/sidekiq_extensions'
3
3
  require 'sidekiq-status/storage'
4
4
  require 'sidekiq-status/worker'
5
+ require 'sidekiq-status/redis_client_adapter'
6
+ require 'sidekiq-status/redis_adapter'
5
7
  require 'sidekiq-status/client_middleware'
6
8
  require 'sidekiq-status/server_middleware'
7
9
  require 'sidekiq-status/web' if defined?(Sidekiq::Web)
@@ -61,8 +63,35 @@ module Sidekiq::Status
61
63
  get(job_id, :pct_complete).to_i
62
64
  end
63
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
+
64
81
  def message(job_id)
65
82
  get(job_id, :message)
66
83
  end
84
+
85
+ def wrap_redis_connection(conn)
86
+ if Sidekiq.major_version >= 7
87
+ conn.is_a?(RedisClientAdapter) ? conn : RedisClientAdapter.new(conn)
88
+ else
89
+ conn.is_a?(RedisAdapter) ? conn : RedisAdapter.new(conn)
90
+ end
91
+ end
92
+
93
+ def redis_adapter
94
+ Sidekiq.redis { |conn| yield wrap_redis_connection(conn) }
95
+ end
67
96
  end
68
97
  end
@@ -14,7 +14,7 @@ Gem::Specification.new do |gem|
14
14
  gem.require_paths = ['lib']
15
15
  gem.version = Sidekiq::Status::VERSION
16
16
 
17
- gem.add_dependency 'sidekiq', '>= 5.0'
17
+ gem.add_dependency 'sidekiq', '>= 6.0', '< 8'
18
18
  gem.add_dependency 'chronic_duration'
19
19
  gem.add_development_dependency 'appraisal'
20
20
  gem.add_development_dependency 'colorize'
@@ -9,8 +9,9 @@ describe Sidekiq::Status::ServerMiddleware do
9
9
  it "sets working/complete status" do
10
10
  allow(SecureRandom).to receive(:hex).once.and_return(job_id)
11
11
  start_server do
12
- thread = redis_thread 4, "status_updates", "job_messages_#{job_id}"
13
- expect(ConfirmationJob.perform_async 'arg1' => 'val1').to eq(job_id)
12
+ thread = branched_redis_thread 4, "status_updates", "job_messages_#{job_id}" do
13
+ expect(ConfirmationJob.perform_async 'arg1' => 'val1').to eq(job_id)
14
+ end
14
15
  expect(thread.value).to eq([
15
16
  job_id,
16
17
  job_id,
@@ -60,6 +61,22 @@ describe Sidekiq::Status::ServerMiddleware do
60
61
  end
61
62
  expect(redis.hget("sidekiq:status:#{job_id}", :status)).to be_nil
62
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
63
80
  end
64
81
 
65
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
data/spec/spec_helper.rb CHANGED
@@ -60,8 +60,47 @@ def redis_thread messages_limit, *channels
60
60
 
61
61
  end
62
62
 
63
+ def redis_client_thread message_limit, *channels
64
+ thread = Thread.new {
65
+ messages = []
66
+ Sidekiq.redis do |conn|
67
+ puts "Subscribing to #{channels} for #{message_limit.to_s.bold} messages".cyan if ENV['DEBUG']
68
+ pubsub = conn.pubsub
69
+ pubsub.call("SUBSCRIBE", *channels)
70
+
71
+ timeouts = 0
72
+ loop do
73
+ type, ch, msg = pubsub.next_event(2)
74
+ next if type == "subscribe"
75
+ if msg
76
+ puts "Message received: #{ch} -> #{msg}".white if ENV['DEBUG']
77
+ messages << msg
78
+ break if messages.length >= message_limit
79
+ else
80
+ # no new message was received in the allocated timeout
81
+ timeouts += 1
82
+ break if timeouts >= 30
83
+ end
84
+ end
85
+ end
86
+ puts "Returing from thread".cyan if ENV['DEBUG']
87
+ messages
88
+ }
89
+ sleep 0.1
90
+ yield if block_given?
91
+ thread.join
92
+ end
93
+
94
+ def branched_redis_thread n, *channels, &block
95
+ if Sidekiq.major_version < 7
96
+ redis_thread(n, *channels, &block)
97
+ else
98
+ redis_client_thread(n, *channels, &block)
99
+ end
100
+ end
101
+
63
102
  def capture_status_updates n, &block
64
- redis_thread(n, "status_updates", &block).value
103
+ branched_redis_thread(n, "status_updates", &block).value
65
104
  end
66
105
 
67
106
  # Configures server middleware and launches a sidekiq server
@@ -76,20 +115,19 @@ def start_server server_middleware_options = {}
76
115
 
77
116
  # Load and configure server options
78
117
  require 'sidekiq/cli'
79
- Sidekiq.options[:queues] << 'default'
80
- Sidekiq.options[:require] = File.expand_path 'environment.rb', File.dirname(__FILE__)
81
- Sidekiq.options[:timeout] = 1
82
- Sidekiq.options[:concurrency] = 5
83
118
 
84
119
  # Add the server middleware
85
120
  Sidekiq.configure_server do |config|
86
- config.redis = Sidekiq::RedisConnection.create
121
+ config.concurrency = 5
122
+ config.redis = Sidekiq::RedisConnection.create if Sidekiq.major_version < 7
87
123
  Sidekiq::Status.configure_server_middleware config, server_middleware_options
88
124
  end
89
125
 
90
126
  # Launch
91
127
  puts "Server starting".yellow if ENV['DEBUG']
92
- Sidekiq::CLI.instance.run
128
+ instance = Sidekiq::CLI.instance
129
+ instance.parse(['-r', File.expand_path('environment.rb', File.dirname(__FILE__))])
130
+ instance.run
93
131
 
94
132
  end
95
133
 
@@ -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: 2.1.2
4
+ version: 3.0.3
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: 2022-01-27 00:00:00.000000000 Z
12
+ date: 2023-05-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sidekiq
@@ -17,14 +17,20 @@ dependencies:
17
17
  requirements:
18
18
  - - ">="
19
19
  - !ruby/object:Gem::Version
20
- version: '5.0'
20
+ version: '6.0'
21
+ - - "<"
22
+ - !ruby/object:Gem::Version
23
+ version: '8'
21
24
  type: :runtime
22
25
  prerelease: false
23
26
  version_requirements: !ruby/object:Gem::Requirement
24
27
  requirements:
25
28
  - - ">="
26
29
  - !ruby/object:Gem::Version
27
- version: '5.0'
30
+ version: '6.0'
31
+ - - "<"
32
+ - !ruby/object:Gem::Version
33
+ version: '8'
28
34
  - !ruby/object:Gem::Dependency
29
35
  name: chronic_duration
30
36
  requirement: !ruby/object:Gem::Requirement
@@ -131,21 +137,23 @@ executables: []
131
137
  extensions: []
132
138
  extra_rdoc_files: []
133
139
  files:
140
+ - ".github/workflows/ci.yaml"
134
141
  - ".gitignore"
135
142
  - ".gitlab-ci.yml"
136
143
  - ".rspec"
137
- - ".travis.yml"
138
144
  - Appraisals
139
145
  - CHANGELOG.md
140
146
  - Gemfile
141
147
  - LICENSE
142
148
  - README.md
143
149
  - Rakefile
144
- - gemfiles/sidekiq_5.x.gemfile
145
150
  - gemfiles/sidekiq_6.1.gemfile
146
151
  - gemfiles/sidekiq_6.x.gemfile
152
+ - gemfiles/sidekiq_7.x.gemfile
147
153
  - lib/sidekiq-status.rb
148
154
  - lib/sidekiq-status/client_middleware.rb
155
+ - lib/sidekiq-status/redis_adapter.rb
156
+ - lib/sidekiq-status/redis_client_adapter.rb
149
157
  - lib/sidekiq-status/server_middleware.rb
150
158
  - lib/sidekiq-status/sidekiq_extensions.rb
151
159
  - lib/sidekiq-status/storage.rb
@@ -187,7 +195,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
187
195
  - !ruby/object:Gem::Version
188
196
  version: '0'
189
197
  requirements: []
190
- rubygems_version: 3.2.32
198
+ rubygems_version: 3.4.1
191
199
  signing_key:
192
200
  specification_version: 4
193
201
  summary: An extension to the sidekiq message processing to track your jobs
data/.travis.yml DELETED
@@ -1,20 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - 2.6
4
- - 2.7
5
- - 3.0
6
- - ruby-head
7
- gemfile:
8
- - gemfiles/sidekiq_5.x.gemfile
9
- - gemfiles/sidekiq_6.1.gemfile
10
- - gemfiles/sidekiq_6.x.gemfile
11
- before_install:
12
- - gem update --system
13
- - gem update bundler
14
- services: redis
15
- notifications:
16
- email: false
17
- matrix:
18
- fast_finish: true
19
- allow_failures:
20
- - rvm: ruby-head