sidekiq 6.3.1 → 7.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (120) hide show
  1. checksums.yaml +4 -4
  2. data/Changes.md +285 -11
  3. data/LICENSE.txt +9 -0
  4. data/README.md +47 -34
  5. data/bin/sidekiq +4 -9
  6. data/bin/sidekiqload +207 -117
  7. data/bin/sidekiqmon +4 -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 +333 -190
  13. data/lib/sidekiq/capsule.rb +127 -0
  14. data/lib/sidekiq/cli.rb +86 -80
  15. data/lib/sidekiq/client.rb +104 -95
  16. data/lib/sidekiq/{util.rb → component.rb} +14 -41
  17. data/lib/sidekiq/config.rb +282 -0
  18. data/lib/sidekiq/deploy.rb +62 -0
  19. data/lib/sidekiq/embedded.rb +61 -0
  20. data/lib/sidekiq/fetch.rb +23 -24
  21. data/lib/sidekiq/job.rb +371 -10
  22. data/lib/sidekiq/job_logger.rb +16 -28
  23. data/lib/sidekiq/job_retry.rb +99 -58
  24. data/lib/sidekiq/job_util.rb +107 -0
  25. data/lib/sidekiq/launcher.rb +103 -95
  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 +136 -0
  31. data/lib/sidekiq/middleware/chain.rb +96 -51
  32. data/lib/sidekiq/middleware/current_attributes.rb +59 -16
  33. data/lib/sidekiq/middleware/i18n.rb +6 -4
  34. data/lib/sidekiq/middleware/modules.rb +21 -0
  35. data/lib/sidekiq/monitor.rb +17 -4
  36. data/lib/sidekiq/paginator.rb +17 -9
  37. data/lib/sidekiq/processor.rb +81 -80
  38. data/lib/sidekiq/rails.rb +21 -14
  39. data/lib/sidekiq/redis_client_adapter.rb +95 -0
  40. data/lib/sidekiq/redis_connection.rb +14 -82
  41. data/lib/sidekiq/ring_buffer.rb +29 -0
  42. data/lib/sidekiq/scheduled.rb +76 -38
  43. data/lib/sidekiq/testing/inline.rb +4 -4
  44. data/lib/sidekiq/testing.rb +42 -69
  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 +95 -11
  49. data/lib/sidekiq/web/csrf_protection.rb +4 -4
  50. data/lib/sidekiq/web/helpers.rb +58 -30
  51. data/lib/sidekiq/web.rb +22 -17
  52. data/lib/sidekiq/worker_compatibility_alias.rb +13 -0
  53. data/lib/sidekiq.rb +85 -202
  54. data/sidekiq.gemspec +12 -10
  55. data/web/assets/javascripts/application.js +77 -26
  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 +168 -0
  60. data/web/assets/javascripts/dashboard.js +3 -240
  61. data/web/assets/javascripts/metrics.js +264 -0
  62. data/web/assets/stylesheets/application-dark.css +17 -17
  63. data/web/assets/stylesheets/application-rtl.css +2 -91
  64. data/web/assets/stylesheets/application.css +69 -302
  65. data/web/locales/ar.yml +70 -70
  66. data/web/locales/cs.yml +62 -62
  67. data/web/locales/da.yml +60 -53
  68. data/web/locales/de.yml +65 -65
  69. data/web/locales/el.yml +43 -24
  70. data/web/locales/en.yml +84 -69
  71. data/web/locales/es.yml +68 -68
  72. data/web/locales/fa.yml +65 -65
  73. data/web/locales/fr.yml +81 -67
  74. data/web/locales/gd.yml +99 -0
  75. data/web/locales/he.yml +65 -64
  76. data/web/locales/hi.yml +59 -59
  77. data/web/locales/it.yml +53 -53
  78. data/web/locales/ja.yml +73 -68
  79. data/web/locales/ko.yml +52 -52
  80. data/web/locales/lt.yml +66 -66
  81. data/web/locales/nb.yml +61 -61
  82. data/web/locales/nl.yml +52 -52
  83. data/web/locales/pl.yml +45 -45
  84. data/web/locales/pt-br.yml +83 -55
  85. data/web/locales/pt.yml +51 -51
  86. data/web/locales/ru.yml +67 -66
  87. data/web/locales/sv.yml +53 -53
  88. data/web/locales/ta.yml +60 -60
  89. data/web/locales/uk.yml +62 -61
  90. data/web/locales/ur.yml +64 -64
  91. data/web/locales/vi.yml +67 -67
  92. data/web/locales/zh-cn.yml +43 -16
  93. data/web/locales/zh-tw.yml +42 -8
  94. data/web/views/_footer.erb +5 -2
  95. data/web/views/_job_info.erb +18 -2
  96. data/web/views/_metrics_period_select.erb +12 -0
  97. data/web/views/_nav.erb +1 -1
  98. data/web/views/_paging.erb +2 -0
  99. data/web/views/_poll_link.erb +1 -1
  100. data/web/views/_summary.erb +1 -1
  101. data/web/views/busy.erb +44 -28
  102. data/web/views/dashboard.erb +36 -4
  103. data/web/views/filtering.erb +7 -0
  104. data/web/views/metrics.erb +82 -0
  105. data/web/views/metrics_for_job.erb +68 -0
  106. data/web/views/morgue.erb +5 -9
  107. data/web/views/queue.erb +15 -15
  108. data/web/views/queues.erb +3 -1
  109. data/web/views/retries.erb +5 -9
  110. data/web/views/scheduled.erb +12 -13
  111. metadata +62 -31
  112. data/LICENSE +0 -9
  113. data/lib/generators/sidekiq/worker_generator.rb +0 -57
  114. data/lib/sidekiq/delay.rb +0 -41
  115. data/lib/sidekiq/exception_handler.rb +0 -27
  116. data/lib/sidekiq/extensions/action_mailer.rb +0 -48
  117. data/lib/sidekiq/extensions/active_record.rb +0 -43
  118. data/lib/sidekiq/extensions/class_methods.rb +0 -43
  119. data/lib/sidekiq/extensions/generic_proxy.rb +0 -33
  120. data/lib/sidekiq/worker.rb +0 -311
@@ -2,9 +2,12 @@
2
2
 
3
3
  require "securerandom"
4
4
  require "sidekiq/middleware/chain"
5
+ require "sidekiq/job_util"
5
6
 
6
7
  module Sidekiq
7
8
  class Client
9
+ include Sidekiq::JobUtil
10
+
8
11
  ##
9
12
  # Define client-side middleware:
10
13
  #
@@ -12,13 +15,12 @@ module Sidekiq
12
15
  # client.middleware do |chain|
13
16
  # chain.use MyClientMiddleware
14
17
  # end
15
- # client.push('class' => 'SomeWorker', 'args' => [1,2,3])
18
+ # client.push('class' => 'SomeJob', 'args' => [1,2,3])
16
19
  #
17
20
  # All client instances default to the globally-defined
18
21
  # Sidekiq.client_middleware but you can change as necessary.
19
22
  #
20
23
  def middleware(&block)
21
- @chain ||= Sidekiq.client_middleware
22
24
  if block
23
25
  @chain = @chain.dup
24
26
  yield @chain
@@ -28,34 +30,49 @@ module Sidekiq
28
30
 
29
31
  attr_accessor :redis_pool
30
32
 
31
- # Sidekiq::Client normally uses the default Redis pool but you may
32
- # pass a custom ConnectionPool if you want to shard your
33
- # Sidekiq jobs across several Redis instances (for scalability
34
- # reasons, e.g.)
33
+ # Sidekiq::Client is responsible for pushing job payloads to Redis.
34
+ # Requires the :pool or :config keyword argument.
35
35
  #
36
- # Sidekiq::Client.new(ConnectionPool.new { Redis.new })
36
+ # Sidekiq::Client.new(pool: Sidekiq::RedisConnection.create)
37
37
  #
38
- # Generally this is only needed for very large Sidekiq installs processing
39
- # thousands of jobs per second. I don't recommend sharding unless you
40
- # cannot scale any other way (e.g. splitting your app into smaller apps).
41
- def initialize(redis_pool = nil)
42
- @redis_pool = redis_pool || Thread.current[:sidekiq_via_pool] || Sidekiq.redis_pool
38
+ # Inside the Sidekiq process, you can reuse the configured resources:
39
+ #
40
+ # Sidekiq::Client.new(config: config)
41
+ #
42
+ # @param pool [ConnectionPool] explicit Redis pool to use
43
+ # @param config [Sidekiq::Config] use the pool and middleware from the given Sidekiq container
44
+ # @param chain [Sidekiq::Middleware::Chain] use the given middleware chain
45
+ def initialize(*args, **kwargs)
46
+ if args.size == 1 && kwargs.size == 0
47
+ warn "Sidekiq::Client.new(pool) is deprecated, please use Sidekiq::Client.new(pool: pool), #{caller(0..3)}"
48
+ # old calling method, accept 1 pool argument
49
+ @redis_pool = args[0]
50
+ @chain = Sidekiq.default_configuration.client_middleware
51
+ @config = Sidekiq.default_configuration
52
+ else
53
+ # new calling method: keyword arguments
54
+ @config = kwargs[:config] || Sidekiq.default_configuration
55
+ @redis_pool = kwargs[:pool] || Thread.current[:sidekiq_redis_pool] || @config&.redis_pool
56
+ @chain = kwargs[:chain] || @config&.client_middleware
57
+ raise ArgumentError, "No Redis pool available for Sidekiq::Client" unless @redis_pool
58
+ end
43
59
  end
44
60
 
45
61
  ##
46
62
  # The main method used to push a job to Redis. Accepts a number of options:
47
63
  #
48
64
  # queue - the named queue to use, default 'default'
49
- # class - the worker class to call, required
65
+ # class - the job class to call, required
50
66
  # args - an array of simple arguments to the perform method, must be JSON-serializable
51
67
  # at - timestamp to schedule the job (optional), must be Numeric (e.g. Time.now.to_f)
52
68
  # retry - whether to retry this job if it fails, default true or an integer number of retries
69
+ # retry_for - relative amount of time to retry this job if it fails, default nil
53
70
  # backtrace - whether to save any error backtrace, default false
54
71
  #
55
72
  # If class is set to the class name, the jobs' options will be based on Sidekiq's default
56
- # worker options. Otherwise, they will be based on the job class's options.
73
+ # job options. Otherwise, they will be based on the job class's options.
57
74
  #
58
- # Any options valid for a worker class's sidekiq_options are also available here.
75
+ # Any options valid for a job class's sidekiq_options are also available here.
59
76
  #
60
77
  # All options must be strings, not symbols. NB: because we are serializing to JSON, all
61
78
  # symbols in 'args' will be converted to strings. Note that +backtrace: true+ can take quite a bit of
@@ -64,13 +81,15 @@ module Sidekiq
64
81
  # Returns a unique Job ID. If middleware stops the job, nil will be returned instead.
65
82
  #
66
83
  # Example:
67
- # push('queue' => 'my_queue', 'class' => MyWorker, 'args' => ['foo', 1, :bat => 'bar'])
84
+ # push('queue' => 'my_queue', 'class' => MyJob, 'args' => ['foo', 1, :bat => 'bar'])
68
85
  #
69
86
  def push(item)
70
87
  normed = normalize_item(item)
71
- payload = process_single(item["class"], normed)
72
-
88
+ payload = middleware.invoke(item["class"], normed, normed["queue"], @redis_pool) do
89
+ normed
90
+ end
73
91
  if payload
92
+ verify_json(payload)
74
93
  raw_push([payload])
75
94
  payload["jid"]
76
95
  end
@@ -78,8 +97,9 @@ module Sidekiq
78
97
 
79
98
  ##
80
99
  # Push a large number of jobs to Redis. This method cuts out the redis
81
- # network round trip latency. I wouldn't recommend pushing more than
82
- # 1000 per call but YMMV based on network quality, size of job args, etc.
100
+ # network round trip latency. It pushes jobs in batches if more than
101
+ # `:batch_size` (1000 by default) of jobs are passed. I wouldn't recommend making `:batch_size`
102
+ # larger than 1000 but YMMV based on network quality, size of job args, etc.
83
103
  # A large number of jobs can cause a bit of Redis command processing latency.
84
104
  #
85
105
  # Takes the same arguments as #push except that args is expected to be
@@ -87,28 +107,45 @@ module Sidekiq
87
107
  # is run through the client middleware pipeline and each job gets its own Job ID
88
108
  # as normal.
89
109
  #
90
- # Returns an array of the of pushed jobs' jids. The number of jobs pushed can be less
91
- # than the number given if the middleware stopped processing for one or more jobs.
110
+ # Returns an array of the of pushed jobs' jids, may contain nils if any client middleware
111
+ # prevented a job push.
112
+ #
113
+ # Example (pushing jobs in batches):
114
+ # push_bulk('class' => 'MyJob', 'args' => (1..100_000).to_a, batch_size: 1_000)
115
+ #
92
116
  def push_bulk(items)
117
+ batch_size = items.delete(:batch_size) || items.delete("batch_size") || 1_000
93
118
  args = items["args"]
94
- raise ArgumentError, "Bulk arguments must be an Array of Arrays: [[1], [2]]" unless args.is_a?(Array) && args.all?(Array)
95
- return [] if args.empty? # no jobs to push
96
-
97
119
  at = items.delete("at")
98
120
  raise ArgumentError, "Job 'at' must be a Numeric or an Array of Numeric timestamps" if at && (Array(at).empty? || !Array(at).all? { |entry| entry.is_a?(Numeric) })
99
121
  raise ArgumentError, "Job 'at' Array must have same size as 'args' Array" if at.is_a?(Array) && at.size != args.size
100
122
 
123
+ jid = items.delete("jid")
124
+ raise ArgumentError, "Explicitly passing 'jid' when pushing more than one job is not supported" if jid && args.size > 1
125
+
101
126
  normed = normalize_item(items)
102
- payloads = args.map.with_index { |job_args, index|
103
- copy = normed.merge("args" => job_args, "jid" => SecureRandom.hex(12), "enqueued_at" => Time.now.to_f)
104
- copy["at"] = (at.is_a?(Array) ? at[index] : at) if at
127
+ slice_index = 0
128
+ result = args.each_slice(batch_size).flat_map do |slice|
129
+ raise ArgumentError, "Bulk arguments must be an Array of Arrays: [[1], [2]]" unless slice.is_a?(Array) && slice.all?(Array)
130
+ break [] if slice.empty? # no jobs to push
131
+
132
+ payloads = slice.map.with_index { |job_args, index|
133
+ copy = normed.merge("args" => job_args, "jid" => SecureRandom.hex(12))
134
+ copy["at"] = (at.is_a?(Array) ? at[slice_index + index] : at) if at
135
+ result = middleware.invoke(items["class"], copy, copy["queue"], @redis_pool) do
136
+ verify_json(copy)
137
+ copy
138
+ end
139
+ result || nil
140
+ }
141
+ slice_index += batch_size
105
142
 
106
- result = process_single(items["class"], copy)
107
- result || nil
108
- }.compact
143
+ to_push = payloads.compact
144
+ raw_push(to_push) unless to_push.empty?
145
+ payloads.map { |payload| payload&.[]("jid") }
146
+ end
109
147
 
110
- raw_push(payloads) unless payloads.empty?
111
- payloads.collect { |payload| payload["jid"] }
148
+ result.is_a?(Enumerator::Lazy) ? result.force : result
112
149
  end
113
150
 
114
151
  # Allows sharding of jobs across any number of Redis instances. All jobs
@@ -116,8 +153,8 @@ module Sidekiq
116
153
  #
117
154
  # pool = ConnectionPool.new { Redis.new }
118
155
  # Sidekiq::Client.via(pool) do
119
- # SomeWorker.perform_async(1,2,3)
120
- # SomeOtherWorker.perform_async(1,2,3)
156
+ # SomeJob.perform_async(1,2,3)
157
+ # SomeOtherJob.perform_async(1,2,3)
121
158
  # end
122
159
  #
123
160
  # Generally this is only needed for very large Sidekiq installs processing
@@ -125,11 +162,11 @@ module Sidekiq
125
162
  # you cannot scale any other way (e.g. splitting your app into smaller apps).
126
163
  def self.via(pool)
127
164
  raise ArgumentError, "No pool given" if pool.nil?
128
- current_sidekiq_pool = Thread.current[:sidekiq_via_pool]
129
- Thread.current[:sidekiq_via_pool] = pool
165
+ current_sidekiq_pool = Thread.current[:sidekiq_redis_pool]
166
+ Thread.current[:sidekiq_redis_pool] = pool
130
167
  yield
131
168
  ensure
132
- Thread.current[:sidekiq_via_pool] = current_sidekiq_pool
169
+ Thread.current[:sidekiq_redis_pool] = current_sidekiq_pool
133
170
  end
134
171
 
135
172
  class << self
@@ -137,15 +174,15 @@ module Sidekiq
137
174
  new.push(item)
138
175
  end
139
176
 
140
- def push_bulk(items)
141
- new.push_bulk(items)
177
+ def push_bulk(...)
178
+ new.push_bulk(...)
142
179
  end
143
180
 
144
181
  # Resque compatibility helpers. Note all helpers
145
- # should go through Worker#client_push.
182
+ # should go through Sidekiq::Job#client_push.
146
183
  #
147
184
  # Example usage:
148
- # Sidekiq::Client.enqueue(MyWorker, 'foo', 1, :bat => 'bar')
185
+ # Sidekiq::Client.enqueue(MyJob, 'foo', 1, :bat => 'bar')
149
186
  #
150
187
  # Messages are enqueued to the 'default' queue.
151
188
  #
@@ -154,19 +191,19 @@ module Sidekiq
154
191
  end
155
192
 
156
193
  # Example usage:
157
- # Sidekiq::Client.enqueue_to(:queue_name, MyWorker, 'foo', 1, :bat => 'bar')
194
+ # Sidekiq::Client.enqueue_to(:queue_name, MyJob, 'foo', 1, :bat => 'bar')
158
195
  #
159
196
  def enqueue_to(queue, klass, *args)
160
197
  klass.client_push("queue" => queue, "class" => klass, "args" => args)
161
198
  end
162
199
 
163
200
  # Example usage:
164
- # Sidekiq::Client.enqueue_to_in(:queue_name, 3.minutes, MyWorker, 'foo', 1, :bat => 'bar')
201
+ # Sidekiq::Client.enqueue_to_in(:queue_name, 3.minutes, MyJob, 'foo', 1, :bat => 'bar')
165
202
  #
166
203
  def enqueue_to_in(queue, interval, klass, *args)
167
204
  int = interval.to_f
168
205
  now = Time.now.to_f
169
- ts = (int < 1_000_000_000 ? now + int : int)
206
+ ts = ((int < 1_000_000_000) ? now + int : int)
170
207
 
171
208
  item = {"class" => klass, "args" => args, "at" => ts, "queue" => queue}
172
209
  item.delete("at") if ts <= now
@@ -175,7 +212,7 @@ module Sidekiq
175
212
  end
176
213
 
177
214
  # Example usage:
178
- # Sidekiq::Client.enqueue_in(3.minutes, MyWorker, 'foo', 1, :bat => 'bar')
215
+ # Sidekiq::Client.enqueue_in(3.minutes, MyJob, 'foo', 1, :bat => 'bar')
179
216
  #
180
217
  def enqueue_in(interval, klass, *args)
181
218
  klass.perform_in(interval, *args)
@@ -186,8 +223,23 @@ module Sidekiq
186
223
 
187
224
  def raw_push(payloads)
188
225
  @redis_pool.with do |conn|
189
- conn.pipelined do
190
- atomic_push(conn, payloads)
226
+ retryable = true
227
+ begin
228
+ conn.pipelined do |pipeline|
229
+ atomic_push(pipeline, payloads)
230
+ end
231
+ rescue RedisClient::Error => ex
232
+ # 2550 Failover can cause the server to become a replica, need
233
+ # to disconnect and reopen the socket to get back to the primary.
234
+ # 4495 Use the same logic if we have a "Not enough replicas" error from the primary
235
+ # 4985 Use the same logic when a blocking command is force-unblocked
236
+ # The retry logic is copied from sidekiq.rb
237
+ if retryable && ex.message =~ /READONLY|NOREPLICAS|UNBLOCKED/
238
+ conn.close
239
+ retryable = false
240
+ retry
241
+ end
242
+ raise
191
243
  end
192
244
  end
193
245
  true
@@ -195,8 +247,10 @@ module Sidekiq
195
247
 
196
248
  def atomic_push(conn, payloads)
197
249
  if payloads.first.key?("at")
198
- conn.zadd("schedule", payloads.map { |hash|
250
+ conn.zadd("schedule", payloads.flat_map { |hash|
199
251
  at = hash.delete("at").to_s
252
+ # ActiveJob sets this but the job has not been enqueued yet
253
+ hash.delete("enqueued_at")
200
254
  [at, Sidekiq.dump_json(hash)]
201
255
  })
202
256
  else
@@ -206,54 +260,9 @@ module Sidekiq
206
260
  entry["enqueued_at"] = now
207
261
  Sidekiq.dump_json(entry)
208
262
  }
209
- conn.sadd("queues", queue)
263
+ conn.sadd("queues", [queue])
210
264
  conn.lpush("queue:#{queue}", to_push)
211
265
  end
212
266
  end
213
-
214
- def process_single(worker_class, item)
215
- queue = item["queue"]
216
-
217
- middleware.invoke(worker_class, item, queue, @redis_pool) do
218
- item
219
- end
220
- end
221
-
222
- def validate(item)
223
- raise(ArgumentError, "Job must be a Hash with 'class' and 'args' keys: `#{item}`") unless item.is_a?(Hash) && item.key?("class") && item.key?("args")
224
- raise(ArgumentError, "Job args must be an Array: `#{item}`") unless item["args"].is_a?(Array)
225
- raise(ArgumentError, "Job class must be either a Class or String representation of the class name: `#{item}`") unless item["class"].is_a?(Class) || item["class"].is_a?(String)
226
- raise(ArgumentError, "Job 'at' must be a Numeric timestamp: `#{item}`") if item.key?("at") && !item["at"].is_a?(Numeric)
227
- raise(ArgumentError, "Job tags must be an Array: `#{item}`") if item["tags"] && !item["tags"].is_a?(Array)
228
- end
229
-
230
- def normalize_item(item)
231
- validate(item)
232
- # raise(ArgumentError, "Arguments must be native JSON types, see https://github.com/mperham/sidekiq/wiki/Best-Practices") unless JSON.load(JSON.dump(item['args'])) == item['args']
233
-
234
- # merge in the default sidekiq_options for the item's class and/or wrapped element
235
- # this allows ActiveJobs to control sidekiq_options too.
236
- defaults = normalized_hash(item["class"])
237
- defaults = defaults.merge(item["wrapped"].get_sidekiq_options) if item["wrapped"].respond_to?("get_sidekiq_options")
238
- item = defaults.merge(item)
239
-
240
- raise(ArgumentError, "Job must include a valid queue name") if item["queue"].nil? || item["queue"] == ""
241
-
242
- item["class"] = item["class"].to_s
243
- item["queue"] = item["queue"].to_s
244
- item["jid"] ||= SecureRandom.hex(12)
245
- item["created_at"] ||= Time.now.to_f
246
-
247
- item
248
- end
249
-
250
- def normalized_hash(item_class)
251
- if item_class.is_a?(Class)
252
- raise(ArgumentError, "Message must include a Sidekiq::Worker class, not class name: #{item_class.ancestors.inspect}") unless item_class.respond_to?("get_sidekiq_options")
253
- item_class.get_sidekiq_options
254
- else
255
- Sidekiq.default_worker_options
256
- end
257
- end
258
267
  end
259
268
  end
@@ -1,43 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "forwardable"
4
- require "socket"
5
- require "securerandom"
6
- require "sidekiq/exception_handler"
7
-
8
3
  module Sidekiq
9
4
  ##
10
- # This module is part of Sidekiq core and not intended for extensions.
11
- #
12
-
13
- class RingBuffer
14
- include Enumerable
15
- extend Forwardable
16
- def_delegators :@buf, :[], :each, :size
17
-
18
- def initialize(size, default = 0)
19
- @size = size
20
- @buf = Array.new(size, default)
21
- @index = 0
22
- end
23
-
24
- def <<(element)
25
- @buf[@index % @size] = element
26
- @index += 1
27
- element
28
- end
29
-
30
- def buffer
31
- @buf
32
- end
33
-
34
- def reset(default = 0)
35
- @buf.fill(default)
36
- end
37
- end
38
-
39
- module Util
40
- include ExceptionHandler
5
+ # Sidekiq::Component assumes a config instance is available at @config
6
+ module Component # :nodoc:
7
+ attr_reader :config
41
8
 
42
9
  def watchdog(last_words)
43
10
  yield
@@ -48,17 +15,17 @@ module Sidekiq
48
15
 
49
16
  def safe_thread(name, &block)
50
17
  Thread.new do
51
- Thread.current.name = name
18
+ Thread.current.name = "sidekiq.#{name}"
52
19
  watchdog(name, &block)
53
20
  end
54
21
  end
55
22
 
56
23
  def logger
57
- Sidekiq.logger
24
+ config.logger
58
25
  end
59
26
 
60
27
  def redis(&block)
61
- Sidekiq.redis(&block)
28
+ config.redis(&block)
62
29
  end
63
30
 
64
31
  def tid
@@ -77,11 +44,17 @@ module Sidekiq
77
44
  @@identity ||= "#{hostname}:#{::Process.pid}:#{process_nonce}"
78
45
  end
79
46
 
47
+ def handle_exception(ex, ctx = {})
48
+ config.handle_exception(ex, ctx)
49
+ end
50
+
80
51
  def fire_event(event, options = {})
52
+ oneshot = options.fetch(:oneshot, true)
81
53
  reverse = options[:reverse]
82
54
  reraise = options[:reraise]
55
+ logger.debug("Firing #{event} event") if oneshot
83
56
 
84
- arr = Sidekiq.options[:lifecycle_events][event]
57
+ arr = config[:lifecycle_events][event]
85
58
  arr.reverse! if reverse
86
59
  arr.each do |block|
87
60
  block.call
@@ -89,7 +62,7 @@ module Sidekiq
89
62
  handle_exception(ex, {context: "Exception during Sidekiq lifecycle event.", event: event})
90
63
  raise ex if reraise
91
64
  end
92
- arr.clear
65
+ arr.clear if oneshot # once we've fired an event, we never fire it again
93
66
  end
94
67
  end
95
68
  end