sidekiq 4.2.4 → 6.2.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of sidekiq might be problematic. Click here for more details.

Files changed (134) hide show
  1. checksums.yaml +5 -5
  2. data/Changes.md +445 -0
  3. data/LICENSE +1 -1
  4. data/README.md +21 -34
  5. data/bin/sidekiq +26 -2
  6. data/bin/sidekiqload +28 -38
  7. data/bin/sidekiqmon +8 -0
  8. data/lib/generators/sidekiq/templates/worker_spec.rb.erb +1 -1
  9. data/lib/generators/sidekiq/templates/worker_test.rb.erb +2 -2
  10. data/lib/generators/sidekiq/worker_generator.rb +21 -13
  11. data/lib/sidekiq/api.rb +347 -213
  12. data/lib/sidekiq/cli.rb +221 -212
  13. data/lib/sidekiq/client.rb +75 -52
  14. data/lib/sidekiq/delay.rb +41 -0
  15. data/lib/sidekiq/exception_handler.rb +12 -16
  16. data/lib/sidekiq/extensions/action_mailer.rb +13 -22
  17. data/lib/sidekiq/extensions/active_record.rb +13 -10
  18. data/lib/sidekiq/extensions/class_methods.rb +14 -11
  19. data/lib/sidekiq/extensions/generic_proxy.rb +10 -4
  20. data/lib/sidekiq/fetch.rb +38 -31
  21. data/lib/sidekiq/job_logger.rb +63 -0
  22. data/lib/sidekiq/job_retry.rb +263 -0
  23. data/lib/sidekiq/launcher.rb +169 -70
  24. data/lib/sidekiq/logger.rb +166 -0
  25. data/lib/sidekiq/manager.rb +17 -20
  26. data/lib/sidekiq/middleware/chain.rb +15 -5
  27. data/lib/sidekiq/middleware/i18n.rb +5 -7
  28. data/lib/sidekiq/monitor.rb +133 -0
  29. data/lib/sidekiq/paginator.rb +18 -14
  30. data/lib/sidekiq/processor.rb +161 -70
  31. data/lib/sidekiq/rails.rb +30 -73
  32. data/lib/sidekiq/redis_connection.rb +67 -20
  33. data/lib/sidekiq/scheduled.rb +61 -35
  34. data/lib/sidekiq/sd_notify.rb +149 -0
  35. data/lib/sidekiq/systemd.rb +24 -0
  36. data/lib/sidekiq/testing/inline.rb +2 -1
  37. data/lib/sidekiq/testing.rb +54 -26
  38. data/lib/sidekiq/util.rb +48 -15
  39. data/lib/sidekiq/version.rb +2 -1
  40. data/lib/sidekiq/web/action.rb +15 -15
  41. data/lib/sidekiq/web/application.rb +112 -89
  42. data/lib/sidekiq/web/csrf_protection.rb +180 -0
  43. data/lib/sidekiq/web/helpers.rb +153 -73
  44. data/lib/sidekiq/web/router.rb +27 -19
  45. data/lib/sidekiq/web.rb +64 -109
  46. data/lib/sidekiq/worker.rb +164 -41
  47. data/lib/sidekiq.rb +86 -60
  48. data/sidekiq.gemspec +24 -22
  49. data/web/assets/images/apple-touch-icon.png +0 -0
  50. data/web/assets/javascripts/application.js +25 -27
  51. data/web/assets/javascripts/dashboard.js +34 -38
  52. data/web/assets/stylesheets/application-dark.css +160 -0
  53. data/web/assets/stylesheets/application-rtl.css +246 -0
  54. data/web/assets/stylesheets/application.css +402 -12
  55. data/web/assets/stylesheets/bootstrap-rtl.min.css +9 -0
  56. data/web/assets/stylesheets/bootstrap.css +2 -2
  57. data/web/locales/ar.yml +81 -0
  58. data/web/locales/de.yml +14 -2
  59. data/web/locales/en.yml +4 -0
  60. data/web/locales/es.yml +4 -3
  61. data/web/locales/fa.yml +80 -0
  62. data/web/locales/fr.yml +3 -3
  63. data/web/locales/he.yml +79 -0
  64. data/web/locales/ja.yml +9 -4
  65. data/web/locales/lt.yml +83 -0
  66. data/web/locales/pl.yml +4 -4
  67. data/web/locales/ru.yml +4 -0
  68. data/web/locales/ur.yml +80 -0
  69. data/web/locales/vi.yml +83 -0
  70. data/web/views/_footer.erb +5 -2
  71. data/web/views/_job_info.erb +3 -2
  72. data/web/views/_nav.erb +4 -18
  73. data/web/views/_paging.erb +1 -1
  74. data/web/views/busy.erb +57 -19
  75. data/web/views/dashboard.erb +3 -3
  76. data/web/views/dead.erb +2 -2
  77. data/web/views/layout.erb +13 -2
  78. data/web/views/morgue.erb +19 -12
  79. data/web/views/queue.erb +22 -12
  80. data/web/views/queues.erb +13 -3
  81. data/web/views/retries.erb +22 -13
  82. data/web/views/retry.erb +3 -3
  83. data/web/views/scheduled.erb +7 -4
  84. metadata +42 -194
  85. data/.github/contributing.md +0 -32
  86. data/.github/issue_template.md +0 -4
  87. data/.gitignore +0 -12
  88. data/.travis.yml +0 -12
  89. data/3.0-Upgrade.md +0 -70
  90. data/4.0-Upgrade.md +0 -53
  91. data/COMM-LICENSE +0 -95
  92. data/Ent-Changes.md +0 -146
  93. data/Gemfile +0 -29
  94. data/Pro-2.0-Upgrade.md +0 -138
  95. data/Pro-3.0-Upgrade.md +0 -44
  96. data/Pro-Changes.md +0 -585
  97. data/Rakefile +0 -9
  98. data/bin/sidekiqctl +0 -99
  99. data/code_of_conduct.md +0 -50
  100. data/lib/sidekiq/core_ext.rb +0 -106
  101. data/lib/sidekiq/logging.rb +0 -106
  102. data/lib/sidekiq/middleware/server/active_record.rb +0 -13
  103. data/lib/sidekiq/middleware/server/logging.rb +0 -40
  104. data/lib/sidekiq/middleware/server/retry_jobs.rb +0 -205
  105. data/test/config.yml +0 -9
  106. data/test/env_based_config.yml +0 -11
  107. data/test/fake_env.rb +0 -1
  108. data/test/fixtures/en.yml +0 -2
  109. data/test/helper.rb +0 -75
  110. data/test/test_actors.rb +0 -138
  111. data/test/test_api.rb +0 -528
  112. data/test/test_cli.rb +0 -418
  113. data/test/test_client.rb +0 -266
  114. data/test/test_exception_handler.rb +0 -56
  115. data/test/test_extensions.rb +0 -127
  116. data/test/test_fetch.rb +0 -50
  117. data/test/test_launcher.rb +0 -95
  118. data/test/test_logging.rb +0 -35
  119. data/test/test_manager.rb +0 -50
  120. data/test/test_middleware.rb +0 -158
  121. data/test/test_processor.rb +0 -235
  122. data/test/test_rails.rb +0 -22
  123. data/test/test_redis_connection.rb +0 -132
  124. data/test/test_retry.rb +0 -326
  125. data/test/test_retry_exhausted.rb +0 -149
  126. data/test/test_scheduled.rb +0 -115
  127. data/test/test_scheduling.rb +0 -58
  128. data/test/test_sidekiq.rb +0 -107
  129. data/test/test_testing.rb +0 -143
  130. data/test/test_testing_fake.rb +0 -357
  131. data/test/test_testing_inline.rb +0 -94
  132. data/test/test_util.rb +0 -13
  133. data/test/test_web.rb +0 -726
  134. data/test/test_web_helpers.rb +0 -54
@@ -0,0 +1,166 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "logger"
4
+ require "time"
5
+
6
+ module Sidekiq
7
+ module Context
8
+ def self.with(hash)
9
+ orig_context = current.dup
10
+ current.merge!(hash)
11
+ yield
12
+ ensure
13
+ Thread.current[:sidekiq_context] = orig_context
14
+ end
15
+
16
+ def self.current
17
+ Thread.current[:sidekiq_context] ||= {}
18
+ end
19
+ end
20
+
21
+ module LoggingUtils
22
+ LEVELS = {
23
+ "debug" => 0,
24
+ "info" => 1,
25
+ "warn" => 2,
26
+ "error" => 3,
27
+ "fatal" => 4
28
+ }
29
+ LEVELS.default_proc = proc do |_, level|
30
+ Sidekiq.logger.warn("Invalid log level: #{level.inspect}")
31
+ nil
32
+ end
33
+
34
+ def debug?
35
+ level <= 0
36
+ end
37
+
38
+ def info?
39
+ level <= 1
40
+ end
41
+
42
+ def warn?
43
+ level <= 2
44
+ end
45
+
46
+ def error?
47
+ level <= 3
48
+ end
49
+
50
+ def fatal?
51
+ level <= 4
52
+ end
53
+
54
+ def local_level
55
+ Thread.current[:sidekiq_log_level]
56
+ end
57
+
58
+ def local_level=(level)
59
+ case level
60
+ when Integer
61
+ Thread.current[:sidekiq_log_level] = level
62
+ when Symbol, String
63
+ Thread.current[:sidekiq_log_level] = LEVELS[level.to_s]
64
+ when nil
65
+ Thread.current[:sidekiq_log_level] = nil
66
+ else
67
+ raise ArgumentError, "Invalid log level: #{level.inspect}"
68
+ end
69
+ end
70
+
71
+ def level
72
+ local_level || super
73
+ end
74
+
75
+ # Change the thread-local level for the duration of the given block.
76
+ def log_at(level)
77
+ old_local_level = local_level
78
+ self.local_level = level
79
+ yield
80
+ ensure
81
+ self.local_level = old_local_level
82
+ end
83
+
84
+ # Redefined to check severity against #level, and thus the thread-local level, rather than +@level+.
85
+ # FIXME: Remove when the minimum Ruby version supports overriding Logger#level.
86
+ def add(severity, message = nil, progname = nil, &block)
87
+ severity ||= ::Logger::UNKNOWN
88
+ progname ||= @progname
89
+
90
+ return true if @logdev.nil? || severity < level
91
+
92
+ if message.nil?
93
+ if block
94
+ message = yield
95
+ else
96
+ message = progname
97
+ progname = @progname
98
+ end
99
+ end
100
+
101
+ @logdev.write format_message(format_severity(severity), Time.now, progname, message)
102
+ end
103
+ end
104
+
105
+ class Logger < ::Logger
106
+ include LoggingUtils
107
+
108
+ def initialize(*args, **kwargs)
109
+ super
110
+ self.formatter = Sidekiq.log_formatter
111
+ end
112
+
113
+ module Formatters
114
+ class Base < ::Logger::Formatter
115
+ def tid
116
+ Thread.current["sidekiq_tid"] ||= (Thread.current.object_id ^ ::Process.pid).to_s(36)
117
+ end
118
+
119
+ def ctx
120
+ Sidekiq::Context.current
121
+ end
122
+
123
+ def format_context
124
+ if ctx.any?
125
+ " " + ctx.compact.map { |k, v|
126
+ case v
127
+ when Array
128
+ "#{k}=#{v.join(",")}"
129
+ else
130
+ "#{k}=#{v}"
131
+ end
132
+ }.join(" ")
133
+ end
134
+ end
135
+ end
136
+
137
+ class Pretty < Base
138
+ def call(severity, time, program_name, message)
139
+ "#{time.utc.iso8601(3)} pid=#{::Process.pid} tid=#{tid}#{format_context} #{severity}: #{message}\n"
140
+ end
141
+ end
142
+
143
+ class WithoutTimestamp < Pretty
144
+ def call(severity, time, program_name, message)
145
+ "pid=#{::Process.pid} tid=#{tid}#{format_context} #{severity}: #{message}\n"
146
+ end
147
+ end
148
+
149
+ class JSON < Base
150
+ def call(severity, time, program_name, message)
151
+ hash = {
152
+ ts: time.utc.iso8601(3),
153
+ pid: ::Process.pid,
154
+ tid: tid,
155
+ lvl: severity,
156
+ msg: message
157
+ }
158
+ c = ctx
159
+ hash["ctx"] = c unless c.empty?
160
+
161
+ Sidekiq.dump_json(hash) << "\n"
162
+ end
163
+ end
164
+ end
165
+ end
166
+ end
@@ -1,16 +1,14 @@
1
1
  # frozen_string_literal: true
2
- # encoding: utf-8
3
- require 'sidekiq/util'
4
- require 'sidekiq/processor'
5
- require 'sidekiq/fetch'
6
- require 'thread'
7
- require 'set'
8
2
 
9
- module Sidekiq
3
+ require "sidekiq/util"
4
+ require "sidekiq/processor"
5
+ require "sidekiq/fetch"
6
+ require "set"
10
7
 
8
+ module Sidekiq
11
9
  ##
12
10
  # The Manager is the central coordination point in Sidekiq, controlling
13
- # the lifecycle of the Processors and feeding them jobs as necessary.
11
+ # the lifecycle of the Processors.
14
12
  #
15
13
  # Tasks:
16
14
  #
@@ -28,16 +26,16 @@ module Sidekiq
28
26
  attr_reader :workers
29
27
  attr_reader :options
30
28
 
31
- def initialize(options={})
29
+ def initialize(options = {})
32
30
  logger.debug { options.inspect }
33
31
  @options = options
34
- @count = options[:concurrency] || 25
32
+ @count = options[:concurrency] || 10
35
33
  raise ArgumentError, "Concurrency of #{@count} is not supported" if @count < 1
36
34
 
37
35
  @done = false
38
36
  @workers = Set.new
39
37
  @count.times do
40
- @workers << Processor.new(self)
38
+ @workers << Processor.new(self, options)
41
39
  end
42
40
  @plock = Mutex.new
43
41
  end
@@ -54,15 +52,15 @@ module Sidekiq
54
52
 
55
53
  logger.info { "Terminating quiet workers" }
56
54
  @workers.each { |x| x.terminate }
57
- fire_event(:quiet, true)
55
+ fire_event(:quiet, reverse: true)
58
56
  end
59
57
 
60
58
  # hack for quicker development / testing environment #2774
61
- PAUSE_TIME = STDOUT.tty? ? 0.1 : 0.5
59
+ PAUSE_TIME = $stdout.tty? ? 0.1 : 0.5
62
60
 
63
61
  def stop(deadline)
64
62
  quiet
65
- fire_event(:shutdown, true)
63
+ fire_event(:shutdown, reverse: true)
66
64
 
67
65
  # some of the shutdown events can be async,
68
66
  # we don't have any way to know when they're done but
@@ -71,11 +69,11 @@ module Sidekiq
71
69
  return if @workers.empty?
72
70
 
73
71
  logger.info { "Pausing to allow workers to finish..." }
74
- remaining = deadline - Time.now
72
+ remaining = deadline - ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
75
73
  while remaining > PAUSE_TIME
76
74
  return if @workers.empty?
77
75
  sleep PAUSE_TIME
78
- remaining = deadline - Time.now
76
+ remaining = deadline - ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
79
77
  end
80
78
  return if @workers.empty?
81
79
 
@@ -92,7 +90,7 @@ module Sidekiq
92
90
  @plock.synchronize do
93
91
  @workers.delete(processor)
94
92
  unless @done
95
- p = Processor.new(self)
93
+ p = Processor.new(self, options)
96
94
  @workers << p
97
95
  p.start
98
96
  end
@@ -114,7 +112,7 @@ module Sidekiq
114
112
  end
115
113
 
116
114
  if cleanup.size > 0
117
- jobs = cleanup.map {|p| p.job }.compact
115
+ jobs = cleanup.map { |p| p.job }.compact
118
116
 
119
117
  logger.warn { "Terminating #{cleanup.size} busy worker threads" }
120
118
  logger.warn { "Work still in progress #{jobs.inspect}" }
@@ -125,7 +123,7 @@ module Sidekiq
125
123
  # contract says that jobs are run AT LEAST once. Process termination
126
124
  # is delayed until we're certain the jobs are back in Redis because
127
125
  # it is worse to lose a job than to run it twice.
128
- strategy = (@options[:fetch] || Sidekiq::BasicFetch)
126
+ strategy = @options[:fetch]
129
127
  strategy.bulk_requeue(jobs, @options)
130
128
  end
131
129
 
@@ -133,6 +131,5 @@ module Sidekiq
133
131
  processor.kill
134
132
  end
135
133
  end
136
-
137
134
  end
138
135
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Sidekiq
3
4
  # Middleware is code configured to run before/after
4
5
  # a message is processed. It is patterned after Rack
@@ -66,7 +67,6 @@ module Sidekiq
66
67
  module Middleware
67
68
  class Chain
68
69
  include Enumerable
69
- attr_reader :entries
70
70
 
71
71
  def initialize_copy(copy)
72
72
  copy.instance_variable_set(:@entries, entries.dup)
@@ -77,10 +77,14 @@ module Sidekiq
77
77
  end
78
78
 
79
79
  def initialize
80
- @entries = []
80
+ @entries = nil
81
81
  yield self if block_given?
82
82
  end
83
83
 
84
+ def entries
85
+ @entries ||= []
86
+ end
87
+
84
88
  def remove(klass)
85
89
  entries.delete_if { |entry| entry.klass == klass }
86
90
  end
@@ -106,13 +110,17 @@ module Sidekiq
106
110
  i = entries.index { |entry| entry.klass == newklass }
107
111
  new_entry = i.nil? ? Entry.new(newklass, *args) : entries.delete_at(i)
108
112
  i = entries.index { |entry| entry.klass == oldklass } || entries.count - 1
109
- entries.insert(i+1, new_entry)
113
+ entries.insert(i + 1, new_entry)
110
114
  end
111
115
 
112
116
  def exists?(klass)
113
117
  any? { |entry| entry.klass == klass }
114
118
  end
115
119
 
120
+ def empty?
121
+ @entries.nil? || @entries.empty?
122
+ end
123
+
116
124
  def retrieve
117
125
  map(&:make_new)
118
126
  end
@@ -122,8 +130,10 @@ module Sidekiq
122
130
  end
123
131
 
124
132
  def invoke(*args)
133
+ return yield if empty?
134
+
125
135
  chain = retrieve.dup
126
- traverse_chain = lambda do
136
+ traverse_chain = proc do
127
137
  if chain.empty?
128
138
  yield
129
139
  else
@@ -139,7 +149,7 @@ module Sidekiq
139
149
 
140
150
  def initialize(klass, *args)
141
151
  @klass = klass
142
- @args = args
152
+ @args = args
143
153
  end
144
154
 
145
155
  def make_new
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  #
3
4
  # Simple middleware to save the current locale and restore it when the job executes.
4
5
  # Use it by requiring it in your initializer:
@@ -9,19 +10,16 @@ module Sidekiq::Middleware::I18n
9
10
  # Get the current locale and store it in the message
10
11
  # to be sent to Sidekiq.
11
12
  class Client
12
- def call(worker_class, msg, queue, redis_pool)
13
- msg['locale'] ||= I18n.locale
13
+ def call(_worker, msg, _queue, _redis)
14
+ msg["locale"] ||= I18n.locale
14
15
  yield
15
16
  end
16
17
  end
17
18
 
18
19
  # Pull the msg locale out and set the current thread to use it.
19
20
  class Server
20
- def call(worker, msg, queue)
21
- I18n.locale = msg['locale'] || I18n.default_locale
22
- yield
23
- ensure
24
- I18n.locale = I18n.default_locale
21
+ def call(_worker, msg, _queue, &block)
22
+ I18n.with_locale(msg.fetch("locale", I18n.default_locale), &block)
25
23
  end
26
24
  end
27
25
  end
@@ -0,0 +1,133 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "fileutils"
4
+ require "sidekiq/api"
5
+
6
+ class Sidekiq::Monitor
7
+ class Status
8
+ VALID_SECTIONS = %w[all version overview processes queues]
9
+ COL_PAD = 2
10
+
11
+ def display(section = nil)
12
+ section ||= "all"
13
+ unless VALID_SECTIONS.include? section
14
+ puts "I don't know how to check the status of '#{section}'!"
15
+ puts "Try one of these: #{VALID_SECTIONS.join(", ")}"
16
+ return
17
+ end
18
+ send(section)
19
+ rescue => e
20
+ puts "Couldn't get status: #{e}"
21
+ end
22
+
23
+ def all
24
+ version
25
+ puts
26
+ overview
27
+ puts
28
+ processes
29
+ puts
30
+ queues
31
+ end
32
+
33
+ def version
34
+ puts "Sidekiq #{Sidekiq::VERSION}"
35
+ puts Time.now.utc
36
+ end
37
+
38
+ def overview
39
+ puts "---- Overview ----"
40
+ puts " Processed: #{delimit stats.processed}"
41
+ puts " Failed: #{delimit stats.failed}"
42
+ puts " Busy: #{delimit stats.workers_size}"
43
+ puts " Enqueued: #{delimit stats.enqueued}"
44
+ puts " Retries: #{delimit stats.retry_size}"
45
+ puts " Scheduled: #{delimit stats.scheduled_size}"
46
+ puts " Dead: #{delimit stats.dead_size}"
47
+ end
48
+
49
+ def processes
50
+ puts "---- Processes (#{process_set.size}) ----"
51
+ process_set.each_with_index do |process, index|
52
+ puts "#{process["identity"]} #{tags_for(process)}"
53
+ puts " Started: #{Time.at(process["started_at"])} (#{time_ago(process["started_at"])})"
54
+ puts " Threads: #{process["concurrency"]} (#{process["busy"]} busy)"
55
+ puts " Queues: #{split_multiline(process["queues"].sort, pad: 11)}"
56
+ puts "" unless (index + 1) == process_set.size
57
+ end
58
+ end
59
+
60
+ def queues
61
+ puts "---- Queues (#{queue_data.size}) ----"
62
+ columns = {
63
+ name: [:ljust, (["name"] + queue_data.map(&:name)).map(&:length).max + COL_PAD],
64
+ size: [:rjust, (["size"] + queue_data.map(&:size)).map(&:length).max + COL_PAD],
65
+ latency: [:rjust, (["latency"] + queue_data.map(&:latency)).map(&:length).max + COL_PAD]
66
+ }
67
+ columns.each { |col, (dir, width)| print col.to_s.upcase.public_send(dir, width) }
68
+ puts
69
+ queue_data.each do |q|
70
+ columns.each do |col, (dir, width)|
71
+ print q.send(col).public_send(dir, width)
72
+ end
73
+ puts
74
+ end
75
+ end
76
+
77
+ private
78
+
79
+ def delimit(number)
80
+ number.to_s.reverse.scan(/.{1,3}/).join(",").reverse
81
+ end
82
+
83
+ def split_multiline(values, opts = {})
84
+ return "none" unless values
85
+ pad = opts[:pad] || 0
86
+ max_length = opts[:max_length] || (80 - pad)
87
+ out = []
88
+ line = ""
89
+ values.each do |value|
90
+ if (line.length + value.length) > max_length
91
+ out << line
92
+ line = " " * pad
93
+ end
94
+ line << value + ", "
95
+ end
96
+ out << line[0..-3]
97
+ out.join("\n")
98
+ end
99
+
100
+ def tags_for(process)
101
+ tags = [
102
+ process["tag"],
103
+ process["labels"],
104
+ (process["quiet"] == "true" ? "quiet" : nil)
105
+ ].flatten.compact
106
+ tags.any? ? "[#{tags.join("] [")}]" : nil
107
+ end
108
+
109
+ def time_ago(timestamp)
110
+ seconds = Time.now - Time.at(timestamp)
111
+ return "just now" if seconds < 60
112
+ return "a minute ago" if seconds < 120
113
+ return "#{seconds.floor / 60} minutes ago" if seconds < 3600
114
+ return "an hour ago" if seconds < 7200
115
+ "#{seconds.floor / 60 / 60} hours ago"
116
+ end
117
+
118
+ QUEUE_STRUCT = Struct.new(:name, :size, :latency)
119
+ def queue_data
120
+ @queue_data ||= Sidekiq::Queue.all.map { |q|
121
+ QUEUE_STRUCT.new(q.name, q.size.to_s, sprintf("%#.2f", q.latency))
122
+ }
123
+ end
124
+
125
+ def process_set
126
+ @process_set ||= Sidekiq::ProcessSet.new
127
+ end
128
+
129
+ def stats
130
+ @stats ||= Sidekiq::Stats.new
131
+ end
132
+ end
133
+ end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Sidekiq
3
4
  module Paginator
4
-
5
- def page(key, pageidx=1, page_size=25, opts=nil)
5
+ def page(key, pageidx = 1, page_size = 25, opts = nil)
6
6
  current_page = pageidx.to_i < 1 ? 1 : pageidx.to_i
7
7
  pageidx = current_page - 1
8
8
  total_size = 0
@@ -12,32 +12,36 @@ module Sidekiq
12
12
 
13
13
  Sidekiq.redis do |conn|
14
14
  type = conn.type(key)
15
+ rev = opts && opts[:reverse]
15
16
 
16
17
  case type
17
- when 'zset'
18
- rev = opts && opts[:reverse]
19
- total_size, items = conn.multi do
18
+ when "zset"
19
+ total_size, items = conn.multi {
20
20
  conn.zcard(key)
21
21
  if rev
22
- conn.zrevrange(key, starting, ending, :with_scores => true)
22
+ conn.zrevrange(key, starting, ending, with_scores: true)
23
23
  else
24
- conn.zrange(key, starting, ending, :with_scores => true)
24
+ conn.zrange(key, starting, ending, with_scores: true)
25
25
  end
26
- end
26
+ }
27
27
  [current_page, total_size, items]
28
- when 'list'
29
- total_size, items = conn.multi do
28
+ when "list"
29
+ total_size, items = conn.multi {
30
30
  conn.llen(key)
31
- conn.lrange(key, starting, ending)
32
- end
31
+ if rev
32
+ conn.lrange(key, -ending - 1, -starting - 1)
33
+ else
34
+ conn.lrange(key, starting, ending)
35
+ end
36
+ }
37
+ items.reverse! if rev
33
38
  [current_page, total_size, items]
34
- when 'none'
39
+ when "none"
35
40
  [1, 0, []]
36
41
  else
37
42
  raise "can't page a #{type}"
38
43
  end
39
44
  end
40
45
  end
41
-
42
46
  end
43
47
  end