sidekiq 6.2.0 → 7.0.0

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 (118) hide show
  1. checksums.yaml +4 -4
  2. data/Changes.md +203 -5
  3. data/LICENSE.txt +9 -0
  4. data/README.md +20 -14
  5. data/bin/sidekiq +4 -9
  6. data/bin/sidekiqload +71 -76
  7. data/bin/sidekiqmon +1 -1
  8. data/lib/generators/sidekiq/job_generator.rb +57 -0
  9. data/lib/generators/sidekiq/templates/{worker.rb.erb → job.rb.erb} +2 -2
  10. data/lib/generators/sidekiq/templates/{worker_spec.rb.erb → job_spec.rb.erb} +1 -1
  11. data/lib/generators/sidekiq/templates/{worker_test.rb.erb → job_test.rb.erb} +1 -1
  12. data/lib/sidekiq/api.rb +334 -229
  13. data/lib/sidekiq/capsule.rb +110 -0
  14. data/lib/sidekiq/cli.rb +91 -79
  15. data/lib/sidekiq/client.rb +74 -85
  16. data/lib/sidekiq/{util.rb → component.rb} +13 -14
  17. data/lib/sidekiq/config.rb +271 -0
  18. data/lib/sidekiq/deploy.rb +62 -0
  19. data/lib/sidekiq/embedded.rb +61 -0
  20. data/lib/sidekiq/fetch.rb +26 -24
  21. data/lib/sidekiq/{worker.rb → job.rb} +162 -28
  22. data/lib/sidekiq/job_logger.rb +17 -29
  23. data/lib/sidekiq/job_retry.rb +79 -60
  24. data/lib/sidekiq/job_util.rb +71 -0
  25. data/lib/sidekiq/launcher.rb +96 -96
  26. data/lib/sidekiq/logger.rb +9 -44
  27. data/lib/sidekiq/manager.rb +40 -41
  28. data/lib/sidekiq/metrics/query.rb +153 -0
  29. data/lib/sidekiq/metrics/shared.rb +95 -0
  30. data/lib/sidekiq/metrics/tracking.rb +134 -0
  31. data/lib/sidekiq/middleware/chain.rb +89 -45
  32. data/lib/sidekiq/middleware/current_attributes.rb +58 -0
  33. data/lib/sidekiq/middleware/i18n.rb +6 -4
  34. data/lib/sidekiq/middleware/modules.rb +21 -0
  35. data/lib/sidekiq/monitor.rb +1 -1
  36. data/lib/sidekiq/paginator.rb +16 -8
  37. data/lib/sidekiq/processor.rb +56 -59
  38. data/lib/sidekiq/rails.rb +17 -5
  39. data/lib/sidekiq/redis_client_adapter.rb +118 -0
  40. data/lib/sidekiq/redis_connection.rb +17 -88
  41. data/lib/sidekiq/ring_buffer.rb +29 -0
  42. data/lib/sidekiq/scheduled.rb +102 -39
  43. data/lib/sidekiq/testing/inline.rb +4 -4
  44. data/lib/sidekiq/testing.rb +42 -71
  45. data/lib/sidekiq/transaction_aware_client.rb +44 -0
  46. data/lib/sidekiq/version.rb +2 -1
  47. data/lib/sidekiq/web/action.rb +3 -3
  48. data/lib/sidekiq/web/application.rb +33 -12
  49. data/lib/sidekiq/web/csrf_protection.rb +12 -9
  50. data/lib/sidekiq/web/helpers.rb +30 -40
  51. data/lib/sidekiq/web.rb +9 -19
  52. data/lib/sidekiq/worker_compatibility_alias.rb +13 -0
  53. data/lib/sidekiq.rb +86 -201
  54. data/sidekiq.gemspec +30 -6
  55. data/web/assets/javascripts/application.js +113 -60
  56. data/web/assets/javascripts/base-charts.js +106 -0
  57. data/web/assets/javascripts/chart.min.js +13 -0
  58. data/web/assets/javascripts/chartjs-plugin-annotation.min.js +7 -0
  59. data/web/assets/javascripts/dashboard-charts.js +166 -0
  60. data/web/assets/javascripts/dashboard.js +36 -273
  61. data/web/assets/javascripts/metrics.js +236 -0
  62. data/web/assets/stylesheets/application-dark.css +28 -45
  63. data/web/assets/stylesheets/application-rtl.css +2 -95
  64. data/web/assets/stylesheets/application.css +84 -529
  65. data/web/locales/ar.yml +71 -65
  66. data/web/locales/cs.yml +62 -62
  67. data/web/locales/da.yml +52 -52
  68. data/web/locales/de.yml +65 -65
  69. data/web/locales/el.yml +43 -24
  70. data/web/locales/en.yml +83 -67
  71. data/web/locales/es.yml +70 -54
  72. data/web/locales/fa.yml +65 -65
  73. data/web/locales/fr.yml +69 -62
  74. data/web/locales/he.yml +65 -64
  75. data/web/locales/hi.yml +59 -59
  76. data/web/locales/it.yml +53 -53
  77. data/web/locales/ja.yml +72 -66
  78. data/web/locales/ko.yml +52 -52
  79. data/web/locales/lt.yml +66 -66
  80. data/web/locales/nb.yml +61 -61
  81. data/web/locales/nl.yml +52 -52
  82. data/web/locales/pl.yml +45 -45
  83. data/web/locales/pt-br.yml +63 -55
  84. data/web/locales/pt.yml +51 -51
  85. data/web/locales/ru.yml +67 -66
  86. data/web/locales/sv.yml +53 -53
  87. data/web/locales/ta.yml +60 -60
  88. data/web/locales/uk.yml +62 -61
  89. data/web/locales/ur.yml +64 -64
  90. data/web/locales/vi.yml +67 -67
  91. data/web/locales/zh-cn.yml +37 -11
  92. data/web/locales/zh-tw.yml +42 -8
  93. data/web/views/_footer.erb +6 -3
  94. data/web/views/_job_info.erb +1 -1
  95. data/web/views/_nav.erb +1 -1
  96. data/web/views/_poll_link.erb +2 -5
  97. data/web/views/_summary.erb +7 -7
  98. data/web/views/busy.erb +17 -11
  99. data/web/views/dashboard.erb +58 -18
  100. data/web/views/dead.erb +1 -1
  101. data/web/views/layout.erb +1 -1
  102. data/web/views/metrics.erb +80 -0
  103. data/web/views/metrics_for_job.erb +69 -0
  104. data/web/views/morgue.erb +6 -6
  105. data/web/views/queue.erb +15 -11
  106. data/web/views/queues.erb +3 -3
  107. data/web/views/retries.erb +7 -7
  108. data/web/views/retry.erb +1 -1
  109. data/web/views/scheduled.erb +1 -1
  110. metadata +78 -28
  111. data/LICENSE +0 -9
  112. data/lib/generators/sidekiq/worker_generator.rb +0 -57
  113. data/lib/sidekiq/delay.rb +0 -41
  114. data/lib/sidekiq/exception_handler.rb +0 -27
  115. data/lib/sidekiq/extensions/action_mailer.rb +0 -48
  116. data/lib/sidekiq/extensions/active_record.rb +0 -43
  117. data/lib/sidekiq/extensions/class_methods.rb +0 -43
  118. data/lib/sidekiq/extensions/generic_proxy.rb +0 -31
@@ -1,82 +1,93 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "sidekiq/middleware/modules"
4
+
3
5
  module Sidekiq
4
6
  # Middleware is code configured to run before/after
5
- # a message is processed. It is patterned after Rack
7
+ # a job is processed. It is patterned after Rack
6
8
  # middleware. Middleware exists for the client side
7
9
  # (pushing jobs onto the queue) as well as the server
8
10
  # side (when jobs are actually processed).
9
11
  #
12
+ # Callers will register middleware Classes and Sidekiq will
13
+ # create new instances of the middleware for every job. This
14
+ # is important so that instance state is not shared accidentally
15
+ # between job executions.
16
+ #
10
17
  # To add middleware for the client:
11
18
  #
12
- # Sidekiq.configure_client do |config|
13
- # config.client_middleware do |chain|
14
- # chain.add MyClientHook
19
+ # Sidekiq.configure_client do |config|
20
+ # config.client_middleware do |chain|
21
+ # chain.add MyClientHook
22
+ # end
15
23
  # end
16
- # end
17
24
  #
18
25
  # To modify middleware for the server, just call
19
26
  # with another block:
20
27
  #
21
- # Sidekiq.configure_server do |config|
22
- # config.server_middleware do |chain|
23
- # chain.add MyServerHook
24
- # chain.remove ActiveRecord
28
+ # Sidekiq.configure_server do |config|
29
+ # config.server_middleware do |chain|
30
+ # chain.add MyServerHook
31
+ # chain.remove ActiveRecord
32
+ # end
25
33
  # end
26
- # end
27
34
  #
28
35
  # To insert immediately preceding another entry:
29
36
  #
30
- # Sidekiq.configure_client do |config|
31
- # config.client_middleware do |chain|
32
- # chain.insert_before ActiveRecord, MyClientHook
37
+ # Sidekiq.configure_client do |config|
38
+ # config.client_middleware do |chain|
39
+ # chain.insert_before ActiveRecord, MyClientHook
40
+ # end
33
41
  # end
34
- # end
35
42
  #
36
43
  # To insert immediately after another entry:
37
44
  #
38
- # Sidekiq.configure_client do |config|
39
- # config.client_middleware do |chain|
40
- # chain.insert_after ActiveRecord, MyClientHook
45
+ # Sidekiq.configure_client do |config|
46
+ # config.client_middleware do |chain|
47
+ # chain.insert_after ActiveRecord, MyClientHook
48
+ # end
41
49
  # end
42
- # end
43
50
  #
44
51
  # This is an example of a minimal server middleware:
45
52
  #
46
- # class MyServerHook
47
- # def call(worker_instance, msg, queue)
48
- # puts "Before work"
49
- # yield
50
- # puts "After work"
53
+ # class MyServerHook
54
+ # include Sidekiq::ServerMiddleware
55
+ #
56
+ # def call(job_instance, msg, queue)
57
+ # logger.info "Before job"
58
+ # redis {|conn| conn.get("foo") } # do something in Redis
59
+ # yield
60
+ # logger.info "After job"
61
+ # end
51
62
  # end
52
- # end
53
63
  #
54
64
  # This is an example of a minimal client middleware, note
55
65
  # the method must return the result or the job will not push
56
66
  # to Redis:
57
67
  #
58
- # class MyClientHook
59
- # def call(worker_class, msg, queue, redis_pool)
60
- # puts "Before push"
61
- # result = yield
62
- # puts "After push"
63
- # result
68
+ # class MyClientHook
69
+ # include Sidekiq::ClientMiddleware
70
+ #
71
+ # def call(job_class, msg, queue, redis_pool)
72
+ # logger.info "Before push"
73
+ # result = yield
74
+ # logger.info "After push"
75
+ # result
76
+ # end
64
77
  # end
65
- # end
66
78
  #
67
79
  module Middleware
68
80
  class Chain
69
81
  include Enumerable
70
82
 
71
- def initialize_copy(copy)
72
- copy.instance_variable_set(:@entries, entries.dup)
73
- end
74
-
83
+ # Iterate through each middleware in the chain
75
84
  def each(&block)
76
85
  entries.each(&block)
77
86
  end
78
87
 
79
- def initialize
88
+ # @api private
89
+ def initialize(config = nil) # :nodoc:
90
+ @config = config
80
91
  @entries = nil
81
92
  yield self if block_given?
82
93
  end
@@ -85,38 +96,62 @@ module Sidekiq
85
96
  @entries ||= []
86
97
  end
87
98
 
99
+ def copy_for(capsule)
100
+ chain = Sidekiq::Middleware::Chain.new(capsule)
101
+ chain.instance_variable_set(:@entries, entries.dup)
102
+ chain
103
+ end
104
+
105
+ # Remove all middleware matching the given Class
106
+ # @param klass [Class]
88
107
  def remove(klass)
89
108
  entries.delete_if { |entry| entry.klass == klass }
90
109
  end
91
110
 
111
+ # Add the given middleware to the end of the chain.
112
+ # Sidekiq will call `klass.new(*args)` to create a clean
113
+ # copy of your middleware for every job executed.
114
+ #
115
+ # chain.add(Statsd::Metrics, { collector: "localhost:8125" })
116
+ #
117
+ # @param klass [Class] Your middleware class
118
+ # @param *args [Array<Object>] Set of arguments to pass to every instance of your middleware
92
119
  def add(klass, *args)
93
- remove(klass) if exists?(klass)
94
- entries << Entry.new(klass, *args)
120
+ remove(klass)
121
+ entries << Entry.new(@config, klass, *args)
95
122
  end
96
123
 
124
+ # Identical to {#add} except the middleware is added to the front of the chain.
97
125
  def prepend(klass, *args)
98
- remove(klass) if exists?(klass)
99
- entries.insert(0, Entry.new(klass, *args))
126
+ remove(klass)
127
+ entries.insert(0, Entry.new(@config, klass, *args))
100
128
  end
101
129
 
130
+ # Inserts +newklass+ before +oldklass+ in the chain.
131
+ # Useful if one middleware must run before another middleware.
102
132
  def insert_before(oldklass, newklass, *args)
103
133
  i = entries.index { |entry| entry.klass == newklass }
104
- new_entry = i.nil? ? Entry.new(newklass, *args) : entries.delete_at(i)
134
+ new_entry = i.nil? ? Entry.new(@config, newklass, *args) : entries.delete_at(i)
105
135
  i = entries.index { |entry| entry.klass == oldklass } || 0
106
136
  entries.insert(i, new_entry)
107
137
  end
108
138
 
139
+ # Inserts +newklass+ after +oldklass+ in the chain.
140
+ # Useful if one middleware must run after another middleware.
109
141
  def insert_after(oldklass, newklass, *args)
110
142
  i = entries.index { |entry| entry.klass == newklass }
111
- new_entry = i.nil? ? Entry.new(newklass, *args) : entries.delete_at(i)
143
+ new_entry = i.nil? ? Entry.new(@config, newklass, *args) : entries.delete_at(i)
112
144
  i = entries.index { |entry| entry.klass == oldklass } || entries.count - 1
113
145
  entries.insert(i + 1, new_entry)
114
146
  end
115
147
 
148
+ # @return [Boolean] if the given class is already in the chain
116
149
  def exists?(klass)
117
150
  any? { |entry| entry.klass == klass }
118
151
  end
152
+ alias_method :include?, :exists?
119
153
 
154
+ # @return [Boolean] if the chain contains no middleware
120
155
  def empty?
121
156
  @entries.nil? || @entries.empty?
122
157
  end
@@ -129,10 +164,12 @@ module Sidekiq
129
164
  entries.clear
130
165
  end
131
166
 
167
+ # Used by Sidekiq to execute the middleware at runtime
168
+ # @api private
132
169
  def invoke(*args)
133
170
  return yield if empty?
134
171
 
135
- chain = retrieve.dup
172
+ chain = retrieve
136
173
  traverse_chain = proc do
137
174
  if chain.empty?
138
175
  yield
@@ -144,16 +181,23 @@ module Sidekiq
144
181
  end
145
182
  end
146
183
 
184
+ private
185
+
186
+ # Represents each link in the middleware chain
187
+ # @api private
147
188
  class Entry
148
189
  attr_reader :klass
149
190
 
150
- def initialize(klass, *args)
191
+ def initialize(config, klass, *args)
192
+ @config = config
151
193
  @klass = klass
152
194
  @args = args
153
195
  end
154
196
 
155
197
  def make_new
156
- @klass.new(*@args)
198
+ x = @klass.new(*@args)
199
+ x.config = @config if @config && x.respond_to?(:config=)
200
+ x
157
201
  end
158
202
  end
159
203
  end
@@ -0,0 +1,58 @@
1
+ require "active_support/current_attributes"
2
+
3
+ module Sidekiq
4
+ ##
5
+ # Automatically save and load any current attributes in the execution context
6
+ # so context attributes "flow" from Rails actions into any associated jobs.
7
+ # This can be useful for multi-tenancy, i18n locale, timezone, any implicit
8
+ # per-request attribute. See +ActiveSupport::CurrentAttributes+.
9
+ #
10
+ # @example
11
+ #
12
+ # # in your initializer
13
+ # require "sidekiq/middleware/current_attributes"
14
+ # Sidekiq::CurrentAttributes.persist("Myapp::Current")
15
+ #
16
+ module CurrentAttributes
17
+ class Save
18
+ include Sidekiq::ClientMiddleware
19
+
20
+ def initialize(cattr)
21
+ @strklass = cattr
22
+ end
23
+
24
+ def call(_, job, _, _)
25
+ attrs = @strklass.constantize.attributes
26
+ if attrs.any?
27
+ if job.has_key?("cattr")
28
+ job["cattr"].merge!(attrs)
29
+ else
30
+ job["cattr"] = attrs
31
+ end
32
+ end
33
+ yield
34
+ end
35
+ end
36
+
37
+ class Load
38
+ include Sidekiq::ServerMiddleware
39
+
40
+ def initialize(cattr)
41
+ @strklass = cattr
42
+ end
43
+
44
+ def call(_, job, _, &block)
45
+ if job.has_key?("cattr")
46
+ @strklass.constantize.set(job["cattr"], &block)
47
+ else
48
+ yield
49
+ end
50
+ end
51
+ end
52
+
53
+ def self.persist(klass, config = Sidekiq.default_configuration)
54
+ config.client_middleware.add Save, klass.to_s
55
+ config.server_middleware.add Load, klass.to_s
56
+ end
57
+ end
58
+ end
@@ -10,16 +10,18 @@ module Sidekiq::Middleware::I18n
10
10
  # Get the current locale and store it in the message
11
11
  # to be sent to Sidekiq.
12
12
  class Client
13
- def call(_worker, msg, _queue, _redis)
14
- msg["locale"] ||= I18n.locale
13
+ include Sidekiq::ClientMiddleware
14
+ def call(_jobclass, job, _queue, _redis)
15
+ job["locale"] ||= I18n.locale
15
16
  yield
16
17
  end
17
18
  end
18
19
 
19
20
  # Pull the msg locale out and set the current thread to use it.
20
21
  class Server
21
- def call(_worker, msg, _queue, &block)
22
- I18n.with_locale(msg.fetch("locale", I18n.default_locale), &block)
22
+ include Sidekiq::ServerMiddleware
23
+ def call(_jobclass, job, _queue, &block)
24
+ I18n.with_locale(job.fetch("locale", I18n.default_locale), &block)
23
25
  end
24
26
  end
25
27
  end
@@ -0,0 +1,21 @@
1
+ module Sidekiq
2
+ # Server-side middleware must import this Module in order
3
+ # to get access to server resources during `call`.
4
+ module ServerMiddleware
5
+ attr_accessor :config
6
+ def redis_pool
7
+ config.redis_pool
8
+ end
9
+
10
+ def logger
11
+ config.logger
12
+ end
13
+
14
+ def redis(&block)
15
+ config.redis(&block)
16
+ end
17
+ end
18
+
19
+ # no difference for now
20
+ ClientMiddleware = ServerMiddleware
21
+ end
@@ -17,7 +17,7 @@ class Sidekiq::Monitor
17
17
  end
18
18
  send(section)
19
19
  rescue => e
20
- puts "Couldn't get status: #{e}"
20
+ abort "Couldn't get status: #{e}"
21
21
  end
22
22
 
23
23
  def all
@@ -16,22 +16,22 @@ module Sidekiq
16
16
 
17
17
  case type
18
18
  when "zset"
19
- total_size, items = conn.multi {
20
- conn.zcard(key)
19
+ total_size, items = conn.multi { |transaction|
20
+ transaction.zcard(key)
21
21
  if rev
22
- conn.zrevrange(key, starting, ending, with_scores: true)
22
+ transaction.zrevrange(key, starting, ending, withscores: true)
23
23
  else
24
- conn.zrange(key, starting, ending, with_scores: true)
24
+ transaction.zrange(key, starting, ending, withscores: true)
25
25
  end
26
26
  }
27
27
  [current_page, total_size, items]
28
28
  when "list"
29
- total_size, items = conn.multi {
30
- conn.llen(key)
29
+ total_size, items = conn.multi { |transaction|
30
+ transaction.llen(key)
31
31
  if rev
32
- conn.lrange(key, -ending - 1, -starting - 1)
32
+ transaction.lrange(key, -ending - 1, -starting - 1)
33
33
  else
34
- conn.lrange(key, starting, ending)
34
+ transaction.lrange(key, starting, ending)
35
35
  end
36
36
  }
37
37
  items.reverse! if rev
@@ -43,5 +43,13 @@ module Sidekiq
43
43
  end
44
44
  end
45
45
  end
46
+
47
+ def page_items(items, pageidx = 1, page_size = 25)
48
+ current_page = pageidx.to_i < 1 ? 1 : pageidx.to_i
49
+ pageidx = current_page - 1
50
+ starting = pageidx * page_size
51
+ items = items.to_a
52
+ [current_page, items.size, items[starting, page_size]]
53
+ end
46
54
  end
47
55
  end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "sidekiq/util"
4
3
  require "sidekiq/fetch"
5
4
  require "sidekiq/job_logger"
6
5
  require "sidekiq/job_retry"
@@ -11,33 +10,34 @@ module Sidekiq
11
10
  #
12
11
  # 1. fetches a job from Redis
13
12
  # 2. executes the job
14
- # a. instantiate the Worker
13
+ # a. instantiate the job class
15
14
  # b. run the middleware chain
16
15
  # c. call #perform
17
16
  #
18
- # A Processor can exit due to shutdown (processor_stopped)
19
- # or due to an error during job execution (processor_died)
17
+ # A Processor can exit due to shutdown or due to
18
+ # an error during job execution.
20
19
  #
21
20
  # If an error occurs in the job execution, the
22
21
  # Processor calls the Manager to create a new one
23
22
  # to replace itself and exits.
24
23
  #
25
24
  class Processor
26
- include Util
25
+ include Sidekiq::Component
27
26
 
28
27
  attr_reader :thread
29
28
  attr_reader :job
29
+ attr_reader :capsule
30
30
 
31
- def initialize(mgr, options)
32
- @mgr = mgr
31
+ def initialize(capsule, &block)
32
+ @config = @capsule = capsule
33
+ @callback = block
33
34
  @down = false
34
35
  @done = false
35
36
  @job = nil
36
37
  @thread = nil
37
- @strategy = options[:fetch]
38
- @reloader = options[:reloader] || proc { |&block| block.call }
39
- @job_logger = (options[:job_logger] || Sidekiq::JobLogger).new
40
- @retrier = Sidekiq::JobRetry.new
38
+ @reloader = Sidekiq.default_configuration[:reloader]
39
+ @job_logger = (capsule.config[:job_logger] || Sidekiq::JobLogger).new(logger)
40
+ @retrier = Sidekiq::JobRetry.new(capsule)
41
41
  end
42
42
 
43
43
  def terminate(wait = false)
@@ -59,33 +59,37 @@ module Sidekiq
59
59
  end
60
60
 
61
61
  def start
62
- @thread ||= safe_thread("processor", &method(:run))
62
+ @thread ||= safe_thread("#{config.name}/processor", &method(:run))
63
63
  end
64
64
 
65
65
  private unless $TESTING
66
66
 
67
67
  def run
68
+ # By setting this thread-local, Sidekiq.redis will access +Sidekiq::Capsule#redis_pool+
69
+ # instead of the global pool in +Sidekiq::Config#redis_pool+.
70
+ Thread.current[:sidekiq_capsule] = @capsule
71
+
68
72
  process_one until @done
69
- @mgr.processor_stopped(self)
73
+ @callback.call(self)
70
74
  rescue Sidekiq::Shutdown
71
- @mgr.processor_stopped(self)
75
+ @callback.call(self)
72
76
  rescue Exception => ex
73
- @mgr.processor_died(self, ex)
77
+ @callback.call(self, ex)
74
78
  end
75
79
 
76
- def process_one
80
+ def process_one(&block)
77
81
  @job = fetch
78
82
  process(@job) if @job
79
83
  @job = nil
80
84
  end
81
85
 
82
86
  def get_one
83
- work = @strategy.retrieve_work
87
+ uow = capsule.fetcher.retrieve_work
84
88
  if @down
85
89
  logger.info { "Redis is online, #{::Process.clock_gettime(::Process::CLOCK_MONOTONIC) - @down} sec downtime" }
86
90
  @down = nil
87
91
  end
88
- work
92
+ uow
89
93
  rescue Sidekiq::Shutdown
90
94
  rescue => ex
91
95
  handle_fetch_exception(ex)
@@ -129,11 +133,11 @@ module Sidekiq
129
133
  # the Reloader. It handles code loading, db connection management, etc.
130
134
  # Effectively this block denotes a "unit of work" to Rails.
131
135
  @reloader.call do
132
- klass = constantize(job_hash["class"])
133
- worker = klass.new
134
- worker.jid = job_hash["jid"]
135
- @retrier.local(worker, jobstr, queue) do
136
- yield worker
136
+ klass = Object.const_get(job_hash["class"])
137
+ inst = klass.new
138
+ inst.jid = job_hash["jid"]
139
+ @retrier.local(inst, jobstr, queue) do
140
+ yield inst
137
141
  end
138
142
  end
139
143
  end
@@ -142,9 +146,9 @@ module Sidekiq
142
146
  end
143
147
  end
144
148
 
145
- def process(work)
146
- jobstr = work.job
147
- queue = work.queue_name
149
+ def process(uow)
150
+ jobstr = uow.job
151
+ queue = uow.queue_name
148
152
 
149
153
  # Treat malformed JSON as a special case: job goes straight to the morgue.
150
154
  job_hash = nil
@@ -152,16 +156,22 @@ module Sidekiq
152
156
  job_hash = Sidekiq.load_json(jobstr)
153
157
  rescue => ex
154
158
  handle_exception(ex, {context: "Invalid JSON for job", jobstr: jobstr})
155
- # we can't notify because the job isn't a valid hash payload.
156
- DeadSet.new.kill(jobstr, notify_failure: false)
157
- return work.acknowledge
159
+ now = Time.now.to_f
160
+ redis do |conn|
161
+ conn.multi do |xa|
162
+ xa.zadd("dead", now.to_s, jobstr)
163
+ xa.zremrangebyscore("dead", "-inf", now - @capsule.config[:dead_timeout_in_seconds])
164
+ xa.zremrangebyrank("dead", 0, - @capsule.config[:dead_max_jobs])
165
+ end
166
+ end
167
+ return uow.acknowledge
158
168
  end
159
169
 
160
170
  ack = false
161
171
  begin
162
- dispatch(job_hash, queue, jobstr) do |worker|
163
- Sidekiq.server_middleware.invoke(worker, job_hash, queue) do
164
- execute_job(worker, job_hash["args"])
172
+ dispatch(job_hash, queue, jobstr) do |inst|
173
+ config.server_middleware.invoke(inst, job_hash, queue) do
174
+ execute_job(inst, job_hash["args"])
165
175
  end
166
176
  end
167
177
  ack = true
@@ -174,7 +184,7 @@ module Sidekiq
174
184
  # signals that we created a retry successfully. We can acknowlege the job.
175
185
  ack = true
176
186
  e = h.cause || h
177
- handle_exception(e, {context: "Job raised exception", job: job_hash, jobstr: jobstr})
187
+ handle_exception(e, {context: "Job raised exception", job: job_hash})
178
188
  raise e
179
189
  rescue Exception => ex
180
190
  # Unexpected error! This is very bad and indicates an exception that got past
@@ -186,14 +196,14 @@ module Sidekiq
186
196
  if ack
187
197
  # We don't want a shutdown signal to interrupt job acknowledgment.
188
198
  Thread.handle_interrupt(Sidekiq::Shutdown => :never) do
189
- work.acknowledge
199
+ uow.acknowledge
190
200
  end
191
201
  end
192
202
  end
193
203
  end
194
204
 
195
- def execute_job(worker, cloned_args)
196
- worker.perform(*cloned_args)
205
+ def execute_job(inst, cloned_args)
206
+ inst.perform(*cloned_args)
197
207
  end
198
208
 
199
209
  # Ruby doesn't provide atomic counters out of the box so we'll
@@ -219,39 +229,39 @@ module Sidekiq
219
229
  end
220
230
 
221
231
  # jruby's Hash implementation is not threadsafe, so we wrap it in a mutex here
222
- class SharedWorkerState
232
+ class SharedWorkState
223
233
  def initialize
224
- @worker_state = {}
234
+ @work_state = {}
225
235
  @lock = Mutex.new
226
236
  end
227
237
 
228
238
  def set(tid, hash)
229
- @lock.synchronize { @worker_state[tid] = hash }
239
+ @lock.synchronize { @work_state[tid] = hash }
230
240
  end
231
241
 
232
242
  def delete(tid)
233
- @lock.synchronize { @worker_state.delete(tid) }
243
+ @lock.synchronize { @work_state.delete(tid) }
234
244
  end
235
245
 
236
246
  def dup
237
- @lock.synchronize { @worker_state.dup }
247
+ @lock.synchronize { @work_state.dup }
238
248
  end
239
249
 
240
250
  def size
241
- @lock.synchronize { @worker_state.size }
251
+ @lock.synchronize { @work_state.size }
242
252
  end
243
253
 
244
254
  def clear
245
- @lock.synchronize { @worker_state.clear }
255
+ @lock.synchronize { @work_state.clear }
246
256
  end
247
257
  end
248
258
 
249
259
  PROCESSED = Counter.new
250
260
  FAILURE = Counter.new
251
- WORKER_STATE = SharedWorkerState.new
261
+ WORK_STATE = SharedWorkState.new
252
262
 
253
263
  def stats(jobstr, queue)
254
- WORKER_STATE.set(tid, {queue: queue, payload: jobstr, run_at: Time.now.to_i})
264
+ WORK_STATE.set(tid, {queue: queue, payload: jobstr, run_at: Time.now.to_i})
255
265
 
256
266
  begin
257
267
  yield
@@ -259,22 +269,9 @@ module Sidekiq
259
269
  FAILURE.incr
260
270
  raise
261
271
  ensure
262
- WORKER_STATE.delete(tid)
272
+ WORK_STATE.delete(tid)
263
273
  PROCESSED.incr
264
274
  end
265
275
  end
266
-
267
- def constantize(str)
268
- return Object.const_get(str) unless str.include?("::")
269
-
270
- names = str.split("::")
271
- names.shift if names.empty? || names.first.empty?
272
-
273
- names.inject(Object) do |constant, name|
274
- # the false flag limits search for name to under the constant namespace
275
- # which mimics Rails' behaviour
276
- constant.const_get(name, false)
277
- end
278
- end
279
276
  end
280
277
  end