sidekiq 8.1.0 → 8.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 63658318932ac6b7045211590b07f84ed9e1e6398f908ace790a0df20d5ac1f0
4
- data.tar.gz: 0c3f5e69ada7529bdac7392acb1c56ef2a19b8ed13210be8c36aac19858c6df4
3
+ metadata.gz: 4fb090d79e2cf2b320fdd47ee55a574a68a46b77a23db27b849ddb6f54acb00a
4
+ data.tar.gz: 4863ef28ecdd8ad2cd868caf2f47cc9302b8eb88f4ff9da4f2b5641beca50d88
5
5
  SHA512:
6
- metadata.gz: 9a5e95a2faccbbf42f8e651c4882c9495ad72b0500bb8fe77fa2a93fb4aa6f8cb96fc820621cd1910fb4b00accf35d75a99d548b3cc8ccdd41a18b5620a9ad73
7
- data.tar.gz: 1bc66490ee07c548c71f680fb280e876efa7eeb8c6f234277df73211ce05c5ae29f5c9bc13064972da945568d1df6634252a6c22a7c5298bdd436b7266246c53
6
+ metadata.gz: 4ba71a2c43cec613337119cd29830339e213a8f876db4db84c62ac67890ee020ab841a4f7fe478f7f0fcd135571b885e54c9af12998ea6947ac51b543d52b42c
7
+ data.tar.gz: 9cabfc243aacec3c57c697b83374a5b934cc985c1e4ee86185a6faba7fe18f6540e3fa0b203c5dbfc0e22c03513f66e973be4152d8c8e12db29e97e21a94360f
data/Changes.md CHANGED
@@ -2,6 +2,20 @@
2
2
 
3
3
  [Sidekiq Changes](https://github.com/sidekiq/sidekiq/blob/main/Changes.md) | [Sidekiq Pro Changes](https://github.com/sidekiq/sidekiq/blob/main/Pro-Changes.md) | [Sidekiq Enterprise Changes](https://github.com/sidekiq/sidekiq/blob/main/Ent-Changes.md)
4
4
 
5
+ 8.1.1
6
+ ----------
7
+
8
+ - Add new `Sidekiq.testing!(mode)` API [#6931]
9
+ Requiring code should not enable process-wide changes.
10
+ ```ruby
11
+ # Old, implicit
12
+ require "sidekiq/testing"
13
+ # New, more explicit
14
+ Sidekiq.testing!(:fake)
15
+ ```
16
+ - Fix race condition with Stop button in UI [#6935]
17
+ - Fix javascript error handler [#6893]
18
+
5
19
  8.1.0
6
20
  ----------
7
21
 
data/bin/tui ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative "../lib/sidekiq/tui"
4
+
5
+ Sidekiq::TUI.new.run
@@ -61,10 +61,13 @@ begin
61
61
 
62
62
  # @api private
63
63
  def enqueue(job)
64
- job.provider_job_id = Sidekiq::ActiveJob::Wrapper.set(
64
+ # NB: Active Job only serializes keys it recognizes. We
65
+ # cannot set arbitrary key/values here.
66
+ wrapper = Sidekiq::ActiveJob::Wrapper.set(
65
67
  wrapped: job.class,
66
68
  queue: job.queue_name
67
- ).perform_async(job.serialize)
69
+ )
70
+ job.provider_job_id = wrapper.perform_async(job.serialize)
68
71
  end
69
72
 
70
73
  # @api private
@@ -14,7 +14,10 @@ module Sidekiq
14
14
  end
15
15
 
16
16
  def create_job_file
17
- template "job.rb.erb", File.join("app/sidekiq", class_path, "#{file_name}_job.rb")
17
+ template(
18
+ "job.rb.erb",
19
+ File.join(jobs_directory, class_path, "#{file_name}_job.rb")
20
+ )
18
21
  end
19
22
 
20
23
  def create_test_file
@@ -31,7 +34,8 @@ module Sidekiq
31
34
 
32
35
  def create_job_spec
33
36
  template_file = File.join(
34
- "spec/sidekiq",
37
+ "spec",
38
+ jobs_directory.gsub("app/", ""),
35
39
  class_path,
36
40
  "#{file_name}_job_spec.rb"
37
41
  )
@@ -40,7 +44,8 @@ module Sidekiq
40
44
 
41
45
  def create_job_test
42
46
  template_file = File.join(
43
- "test/sidekiq",
47
+ "test",
48
+ jobs_directory.gsub("app/", ""),
44
49
  class_path,
45
50
  "#{file_name}_job_test.rb"
46
51
  )
@@ -54,6 +59,13 @@ module Sidekiq
54
59
  def test_framework
55
60
  ::Rails.application.config.generators.options[:rails][:test_framework]
56
61
  end
62
+
63
+ # Can be set in an initializer or in application configuration
64
+ # with Rails.application.config.generators.options[:sidekiq][:jobs_directory] = "app/jobs"
65
+ # to change the directory that the job files are generated in to.
66
+ def jobs_directory
67
+ ::Rails.application.config.generators.options[:sidekiq].fetch(:jobs_directory, "app/sidekiq")
68
+ end
57
69
  end
58
70
  end
59
71
  end
data/lib/sidekiq/api.rb CHANGED
@@ -17,12 +17,37 @@ require "sidekiq/metrics/query"
17
17
  #
18
18
 
19
19
  module Sidekiq
20
+ module ApiUtils
21
+ # @api private
22
+ # Calculate the latency in seconds for a job based on its enqueued timestamp
23
+ # @param job [Hash] the job hash
24
+ # @return [Float] latency in seconds
25
+ def calculate_latency(job)
26
+ timestamp = job["enqueued_at"] || job["created_at"]
27
+ return 0.0 unless timestamp
28
+
29
+ if timestamp.is_a?(Float)
30
+ # old format
31
+ Time.now.to_f - timestamp
32
+ else
33
+ now = ::Process.clock_gettime(::Process::CLOCK_REALTIME, :millisecond)
34
+ (now - timestamp) / 1000.0
35
+ end
36
+ end
37
+ end
38
+
20
39
  # Retrieve runtime statistics from Redis regarding
21
40
  # this Sidekiq cluster.
22
41
  #
23
42
  # stat = Sidekiq::Stats.new
24
43
  # stat.processed
25
44
  class Stats
45
+ QueueSummary = Data.define(:name, :size, :latency, :paused) do
46
+ alias_method :paused?, :paused
47
+ end
48
+
49
+ include ApiUtils
50
+
26
51
  def initialize
27
52
  fetch_stats_fast!
28
53
  end
@@ -63,6 +88,7 @@ module Sidekiq
63
88
  stat :default_queue_latency
64
89
  end
65
90
 
91
+ # @return [Hash{String => Integer}] a hash of queue names to their lengths
66
92
  def queues
67
93
  Sidekiq.redis do |conn|
68
94
  queues = conn.sscan("queues").to_a
@@ -78,6 +104,41 @@ module Sidekiq
78
104
  end
79
105
  end
80
106
 
107
+ # More detailed information about each queue: name, size, latency, paused status
108
+ # @return [Array<QueueSummary>]
109
+ def queue_summaries
110
+ Sidekiq.redis do |conn|
111
+ queues = conn.sscan("queues").to_a
112
+ return [] if queues.empty?
113
+
114
+ results = conn.pipelined { |pipeline|
115
+ queues.each do |queue|
116
+ pipeline.llen("queue:#{queue}")
117
+ pipeline.lindex("queue:#{queue}", -1)
118
+ pipeline.sismember("paused", queue)
119
+ end
120
+ }
121
+
122
+ queue_summaries = []
123
+ queues.each_with_index do |name, idx|
124
+ size = results[idx * 3]
125
+ last_item = results[idx * 3 + 1]
126
+ paused = results[idx * 3 + 2] > 0
127
+
128
+ latency = if last_item
129
+ job = Sidekiq.load_json(last_item)
130
+ calculate_latency(job)
131
+ else
132
+ 0.0
133
+ end
134
+
135
+ queue_summaries << QueueSummary.new(name:, size:, latency:, paused:)
136
+ end
137
+
138
+ queue_summaries.sort_by { |qd| -qd.size }
139
+ end
140
+ end
141
+
81
142
  # O(1) redis calls
82
143
  # @api private
83
144
  def fetch_stats_fast!
@@ -100,19 +161,7 @@ module Sidekiq
100
161
  {}
101
162
  end
102
163
 
103
- enqueued_at = job["enqueued_at"]
104
- if enqueued_at
105
- if enqueued_at.is_a?(Float)
106
- # old format
107
- now = Time.now.to_f
108
- now - enqueued_at
109
- else
110
- now = ::Process.clock_gettime(::Process::CLOCK_REALTIME, :millisecond)
111
- (now - enqueued_at) / 1000.0
112
- end
113
- else
114
- 0.0
115
- end
164
+ calculate_latency(job)
116
165
  else
117
166
  0.0
118
167
  end
@@ -235,6 +284,7 @@ module Sidekiq
235
284
  # end
236
285
  class Queue
237
286
  include Enumerable
287
+ include ApiUtils
238
288
 
239
289
  ##
240
290
  # Fetch all known queues within Redis.
@@ -245,6 +295,7 @@ module Sidekiq
245
295
  end
246
296
 
247
297
  attr_reader :name
298
+ alias_method :id, :name
248
299
 
249
300
  # @param name [String] the name of the queue
250
301
  def initialize(name = "default")
@@ -277,19 +328,7 @@ module Sidekiq
277
328
  return 0.0 unless entry
278
329
 
279
330
  job = Sidekiq.load_json(entry)
280
- enqueued_at = job["enqueued_at"]
281
- if enqueued_at
282
- if enqueued_at.is_a?(Float)
283
- # old format
284
- now = Time.now.to_f
285
- now - enqueued_at
286
- else
287
- now = ::Process.clock_gettime(::Process::CLOCK_REALTIME, :millisecond)
288
- (now - enqueued_at) / 1000.0
289
- end
290
- else
291
- 0.0
292
- end
331
+ calculate_latency(job)
293
332
  end
294
333
 
295
334
  def each
@@ -352,6 +391,8 @@ module Sidekiq
352
391
  # The job should be considered immutable but may be
353
392
  # removed from the queue via JobRecord#delete.
354
393
  class JobRecord
394
+ include ApiUtils
395
+
355
396
  # the parsed Hash of job data
356
397
  # @!attribute [r] Item
357
398
  attr_reader :item
@@ -478,17 +519,7 @@ module Sidekiq
478
519
  end
479
520
 
480
521
  def latency
481
- timestamp = @item["enqueued_at"] || @item["created_at"]
482
- if timestamp
483
- if timestamp.is_a?(Float)
484
- # old format
485
- Time.now.to_f - timestamp
486
- else
487
- (::Process.clock_gettime(::Process::CLOCK_REALTIME, :millisecond) - timestamp) / 1000.0
488
- end
489
- else
490
- 0.0
491
- end
522
+ calculate_latency(@item)
492
523
  end
493
524
 
494
525
  # Remove this job from the queue
@@ -553,17 +584,24 @@ module Sidekiq
553
584
  # could be the scheduled time for it to run (e.g. scheduled set),
554
585
  # or the expiration date after which the entry should be deleted (e.g. dead set).
555
586
  class SortedEntry < JobRecord
556
- attr_reader :score
557
587
  attr_reader :parent
558
588
 
559
589
  # :nodoc:
560
590
  # @api private
561
591
  def initialize(parent, score, item)
562
592
  super(item)
563
- @score = Float(score)
593
+ @score = score
564
594
  @parent = parent
565
595
  end
566
596
 
597
+ def score
598
+ Float(@score)
599
+ end
600
+
601
+ def id
602
+ "#{@score}|#{item["jid"]}"
603
+ end
604
+
567
605
  # The timestamp associated with this entry
568
606
  def at
569
607
  Time.at(score).utc
@@ -574,7 +612,7 @@ module Sidekiq
574
612
  if @value
575
613
  @parent.delete_by_value(@parent.name, @value)
576
614
  else
577
- @parent.delete_by_jid(score, jid)
615
+ @parent.delete_by_jid(@score, jid)
578
616
  end
579
617
  end
580
618
 
@@ -583,7 +621,7 @@ module Sidekiq
583
621
  # @param at [Time] the new timestamp for this job
584
622
  def reschedule(at)
585
623
  Sidekiq.redis do |conn|
586
- conn.zincrby(@parent.name, at.to_f - @score, Sidekiq.dump_json(@item))
624
+ conn.zincrby(@parent.name, at.to_f - score, Sidekiq.dump_json(@item))
587
625
  end
588
626
  end
589
627
 
@@ -1088,6 +1126,7 @@ module Sidekiq
1088
1126
  def identity
1089
1127
  self["identity"]
1090
1128
  end
1129
+ alias_method :id, :identity
1091
1130
 
1092
1131
  # deprecated, use capsules below
1093
1132
  def queues
@@ -1161,6 +1200,10 @@ module Sidekiq
1161
1200
  self["quiet"] == "true"
1162
1201
  end
1163
1202
 
1203
+ def leader?
1204
+ Sidekiq.redis { |c| c.get("dear-leader") == identity }
1205
+ end
1206
+
1164
1207
  private
1165
1208
 
1166
1209
  def signal(sig)
@@ -0,0 +1,331 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "securerandom"
4
+ require "sidekiq"
5
+
6
+ module Sidekiq
7
+ class Testing
8
+ class TestModeAlreadySetError < RuntimeError; end
9
+ class << self
10
+ attr_accessor :__global_test_mode
11
+
12
+ # Calling without a block sets the global test mode, affecting
13
+ # all threads. Calling with a block only affects the current Thread.
14
+ def __set_test_mode(mode)
15
+ if block_given?
16
+ # Reentrant testing modes will lead to a rat's nest of code which is
17
+ # hard to reason about. You can set the testing mode once globally and
18
+ # you can override that global setting once per-thread.
19
+ raise TestModeAlreadySetError, "Nesting test modes is not supported" if __local_test_mode
20
+
21
+ self.__local_test_mode = mode
22
+ begin
23
+ yield
24
+ ensure
25
+ self.__local_test_mode = nil
26
+ end
27
+ else
28
+ self.__global_test_mode = mode
29
+ end
30
+ end
31
+
32
+ def __test_mode
33
+ __local_test_mode || __global_test_mode
34
+ end
35
+
36
+ def __local_test_mode
37
+ Thread.current[:__sidekiq_test_mode]
38
+ end
39
+
40
+ def __local_test_mode=(value)
41
+ Thread.current[:__sidekiq_test_mode] = value
42
+ end
43
+
44
+ def disable!(&block)
45
+ __set_test_mode(:disable, &block)
46
+ end
47
+
48
+ def fake!(&block)
49
+ __set_test_mode(:fake, &block)
50
+ end
51
+
52
+ def inline!(&block)
53
+ __set_test_mode(:inline, &block)
54
+ end
55
+
56
+ def enabled?
57
+ __test_mode != :disable
58
+ end
59
+
60
+ def disabled?
61
+ __test_mode == :disable
62
+ end
63
+
64
+ def fake?
65
+ __test_mode == :fake
66
+ end
67
+
68
+ def inline?
69
+ __test_mode == :inline
70
+ end
71
+
72
+ def server_middleware
73
+ @server_chain ||= Middleware::Chain.new(Sidekiq.default_configuration)
74
+ yield @server_chain if block_given?
75
+ @server_chain
76
+ end
77
+ end
78
+ end
79
+
80
+ class EmptyQueueError < RuntimeError; end
81
+
82
+ module TestingClient
83
+ private def atomic_push(conn, payloads)
84
+ if Sidekiq::Testing.fake?
85
+ payloads.each do |job|
86
+ job = Sidekiq.load_json(Sidekiq.dump_json(job))
87
+ job["enqueued_at"] = ::Process.clock_gettime(::Process::CLOCK_REALTIME, :millisecond) unless job["at"]
88
+ Queues.push(job["queue"], job["class"], job)
89
+ end
90
+ true
91
+ elsif Sidekiq::Testing.inline?
92
+ payloads.each do |job|
93
+ klass = Object.const_get(job["class"])
94
+ job["id"] ||= SecureRandom.hex(12)
95
+ job_hash = Sidekiq.load_json(Sidekiq.dump_json(job))
96
+ klass.process_job(job_hash)
97
+ end
98
+ true
99
+ else
100
+ super
101
+ end
102
+ end
103
+ end
104
+
105
+ Sidekiq::Client.prepend TestingClient
106
+
107
+ module Queues
108
+ ##
109
+ # The Queues class is only for testing the fake queue implementation.
110
+ # There are 2 data structures involved in tandem. This is due to the
111
+ # Rspec syntax of change(HardJob.jobs, :size). It keeps a reference
112
+ # to the array. Because the array was derived from a filter of the total
113
+ # jobs enqueued, it appeared as though the array didn't change.
114
+ #
115
+ # To solve this, we'll keep 2 hashes containing the jobs. One with keys based
116
+ # on the queue, and another with keys of the job type, so the array for
117
+ # HardJob.jobs is a straight reference to a real array.
118
+ #
119
+ # Queue-based hash:
120
+ #
121
+ # {
122
+ # "default"=>[
123
+ # {
124
+ # "class"=>"TestTesting::HardJob",
125
+ # "args"=>[1, 2],
126
+ # "retry"=>true,
127
+ # "queue"=>"default",
128
+ # "jid"=>"abc5b065c5c4b27fc1102833",
129
+ # "created_at"=>1447445554.419934
130
+ # }
131
+ # ]
132
+ # }
133
+ #
134
+ # Job-based hash:
135
+ #
136
+ # {
137
+ # "TestTesting::HardJob"=>[
138
+ # {
139
+ # "class"=>"TestTesting::HardJob",
140
+ # "args"=>[1, 2],
141
+ # "retry"=>true,
142
+ # "queue"=>"default",
143
+ # "jid"=>"abc5b065c5c4b27fc1102833",
144
+ # "created_at"=>1447445554.419934
145
+ # }
146
+ # ]
147
+ # }
148
+ #
149
+ # Example:
150
+ #
151
+ # require 'sidekiq/testing'
152
+ #
153
+ # assert_equal 0, Sidekiq::Queues["default"].size
154
+ # HardJob.perform_async(:something)
155
+ # assert_equal 1, Sidekiq::Queues["default"].size
156
+ # assert_equal :something, Sidekiq::Queues["default"].first['args'][0]
157
+ #
158
+ # You can also clear all jobs:
159
+ #
160
+ # assert_equal 0, Sidekiq::Queues["default"].size
161
+ # HardJob.perform_async(:something)
162
+ # Sidekiq::Queues.clear_all
163
+ # assert_equal 0, Sidekiq::Queues["default"].size
164
+ #
165
+ # This can be useful to make sure jobs don't linger between tests:
166
+ #
167
+ # RSpec.configure do |config|
168
+ # config.before(:each) do
169
+ # Sidekiq::Queues.clear_all
170
+ # end
171
+ # end
172
+ #
173
+ class << self
174
+ def [](queue)
175
+ jobs_by_queue[queue]
176
+ end
177
+
178
+ def push(queue, klass, job)
179
+ jobs_by_queue[queue] << job
180
+ jobs_by_class[klass] << job
181
+ end
182
+
183
+ def jobs_by_queue
184
+ @jobs_by_queue ||= Hash.new { |hash, key| hash[key] = [] }
185
+ end
186
+
187
+ def jobs_by_class
188
+ @jobs_by_class ||= Hash.new { |hash, key| hash[key] = [] }
189
+ end
190
+ alias_method :jobs_by_worker, :jobs_by_class
191
+
192
+ def delete_for(jid, queue, klass)
193
+ jobs_by_queue[queue.to_s].delete_if { |job| job["jid"] == jid }
194
+ jobs_by_class[klass].delete_if { |job| job["jid"] == jid }
195
+ end
196
+
197
+ def clear_for(queue, klass)
198
+ jobs_by_queue[queue.to_s].clear
199
+ jobs_by_class[klass].clear
200
+ end
201
+
202
+ def clear_all
203
+ jobs_by_queue.clear
204
+ jobs_by_class.clear
205
+ end
206
+ end
207
+ end
208
+
209
+ module Job
210
+ ##
211
+ # The Sidekiq testing infrastructure overrides perform_async
212
+ # so that it does not actually touch the network. Instead it
213
+ # stores the asynchronous jobs in a per-class array so that
214
+ # their presence/absence can be asserted by your tests.
215
+ #
216
+ # This is similar to ActionMailer's :test delivery_method and its
217
+ # ActionMailer::Base.deliveries array.
218
+ #
219
+ # Example:
220
+ #
221
+ # require 'sidekiq/testing'
222
+ #
223
+ # assert_equal 0, HardJob.jobs.size
224
+ # HardJob.perform_async(:something)
225
+ # assert_equal 1, HardJob.jobs.size
226
+ # assert_equal :something, HardJob.jobs[0]['args'][0]
227
+ #
228
+ # You can also clear and drain all job types:
229
+ #
230
+ # Sidekiq::Job.clear_all # or .drain_all
231
+ #
232
+ # This can be useful to make sure jobs don't linger between tests:
233
+ #
234
+ # RSpec.configure do |config|
235
+ # config.before(:each) do
236
+ # Sidekiq::Job.clear_all
237
+ # end
238
+ # end
239
+ #
240
+ # or for acceptance testing, i.e. with cucumber:
241
+ #
242
+ # AfterStep do
243
+ # Sidekiq::Job.drain_all
244
+ # end
245
+ #
246
+ # When I sign up as "foo@example.com"
247
+ # Then I should receive a welcome email to "foo@example.com"
248
+ #
249
+ module ClassMethods
250
+ # Queue for this worker
251
+ def queue
252
+ get_sidekiq_options["queue"]
253
+ end
254
+
255
+ # Jobs queued for this worker
256
+ def jobs
257
+ Queues.jobs_by_class[to_s]
258
+ end
259
+
260
+ # Clear all jobs for this worker
261
+ def clear
262
+ Queues.clear_for(queue, to_s)
263
+ end
264
+
265
+ # Drain and run all jobs for this worker
266
+ def drain
267
+ while jobs.any?
268
+ next_job = jobs.first
269
+ Queues.delete_for(next_job["jid"], next_job["queue"], to_s)
270
+ process_job(next_job)
271
+ end
272
+ end
273
+
274
+ # Pop out a single job and perform it
275
+ def perform_one
276
+ raise(EmptyQueueError, "perform_one called with empty job queue") if jobs.empty?
277
+ next_job = jobs.first
278
+ Queues.delete_for(next_job["jid"], next_job["queue"], to_s)
279
+ process_job(next_job)
280
+ end
281
+
282
+ def process_job(job)
283
+ instance = new
284
+ instance.jid = job["jid"]
285
+ instance.bid = job["bid"] if instance.respond_to?(:bid=)
286
+ Sidekiq::Testing.server_middleware.invoke(instance, job, job["queue"]) do
287
+ execute_job(instance, job["args"])
288
+ end
289
+ end
290
+
291
+ def execute_job(worker, args)
292
+ worker.perform(*args)
293
+ end
294
+ end
295
+
296
+ class << self
297
+ def jobs # :nodoc:
298
+ Queues.jobs_by_queue.values.flatten
299
+ end
300
+
301
+ # Clear all queued jobs
302
+ def clear_all
303
+ Queues.clear_all
304
+ end
305
+
306
+ # Drain (execute) all queued jobs
307
+ def drain_all
308
+ while jobs.any?
309
+ job_classes = jobs.map { |job| job["class"] }.uniq
310
+
311
+ job_classes.each do |job_class|
312
+ Object.const_get(job_class).drain
313
+ end
314
+ end
315
+ end
316
+ end
317
+ end
318
+
319
+ module TestingExtensions
320
+ def jobs_for(klass)
321
+ jobs.select do |job|
322
+ marshalled = job["args"][0]
323
+ marshalled.index(klass.to_s) && YAML.safe_load(marshalled)[0] == klass
324
+ end
325
+ end
326
+ end
327
+ end
328
+
329
+ if defined?(::Rails) && Rails.respond_to?(:env) && !Rails.env.test? && !$TESTING # rubocop:disable Style/GlobalVars
330
+ warn("⛔️ WARNING: Sidekiq testing API enabled, but this is not the test environment. Your jobs will not go to Redis.", uplevel: 1)
331
+ end
@@ -1,30 +1,2 @@
1
- # frozen_string_literal: true
2
-
3
- require "sidekiq/testing"
4
-
5
- ##
6
- # The Sidekiq inline infrastructure overrides perform_async so that it
7
- # actually calls perform instead. This allows jobs to be run inline in a
8
- # testing environment.
9
- #
10
- # This is similar to `Resque.inline = true` functionality.
11
- #
12
- # Example:
13
- #
14
- # require 'sidekiq/testing/inline'
15
- #
16
- # $external_variable = 0
17
- #
18
- # class ExternalJob
19
- # include Sidekiq::Job
20
- #
21
- # def perform
22
- # $external_variable = 1
23
- # end
24
- # end
25
- #
26
- # assert_equal 0, $external_variable
27
- # ExternalJob.perform_async
28
- # assert_equal 1, $external_variable
29
- #
30
- Sidekiq::Testing.inline!
1
+ Sidekiq.testing!(:inline)
2
+ warn('⛔️ `require "sidekiq/testing/inline"` is deprecated and will be removed in Sidekiq 9.0. See https://sidekiq.org/wiki/Testing#new-api')