sidekiq 8.1.0 → 8.1.2
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 +4 -4
- data/Changes.md +29 -0
- data/README.md +1 -1
- data/bin/kiq +17 -0
- data/lib/active_job/queue_adapters/sidekiq_adapter.rb +11 -8
- data/lib/generators/sidekiq/job_generator.rb +15 -3
- data/lib/sidekiq/api.rb +130 -76
- data/lib/sidekiq/client.rb +3 -1
- data/lib/sidekiq/component.rb +3 -0
- data/lib/sidekiq/launcher.rb +1 -1
- data/lib/sidekiq/manager.rb +1 -1
- data/lib/sidekiq/paginator.rb +6 -1
- data/lib/sidekiq/profiler.rb +1 -1
- data/lib/sidekiq/test_api.rb +331 -0
- data/lib/sidekiq/testing/inline.rb +2 -30
- data/lib/sidekiq/testing.rb +2 -334
- data/lib/sidekiq/tui/controls.rb +53 -0
- data/lib/sidekiq/tui/filtering.rb +53 -0
- data/lib/sidekiq/tui/tabs/base_tab.rb +187 -0
- data/lib/sidekiq/tui/tabs/busy.rb +118 -0
- data/lib/sidekiq/tui/tabs/dead.rb +19 -0
- data/lib/sidekiq/tui/tabs/home.rb +144 -0
- data/lib/sidekiq/tui/tabs/metrics.rb +131 -0
- data/lib/sidekiq/tui/tabs/queues.rb +95 -0
- data/lib/sidekiq/tui/tabs/retries.rb +19 -0
- data/lib/sidekiq/tui/tabs/scheduled.rb +19 -0
- data/lib/sidekiq/tui/tabs/set_tab.rb +96 -0
- data/lib/sidekiq/tui/tabs.rb +15 -0
- data/lib/sidekiq/tui.rb +380 -0
- data/lib/sidekiq/version.rb +1 -1
- data/lib/sidekiq/web/application.rb +2 -2
- data/lib/sidekiq/web/helpers.rb +11 -0
- data/lib/sidekiq.rb +7 -0
- data/sidekiq.gemspec +1 -1
- data/web/assets/javascripts/application.js +1 -1
- data/web/locales/zh-TW.yml +1 -1
- data/web/views/busy.html.erb +1 -1
- metadata +18 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0d21db4cf06c0b4d0b5fb770162e289403a76ed996d6c99613cf45083f0e671d
|
|
4
|
+
data.tar.gz: 07cf848cd5de112f3153ecd0014991cbf2abf9e66bc0847d2b7845ec7a726329
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 395d346f8b5227480e4d830b3c1f219a35bb0e2527283f9c00a6a4043c1ebe271998874ae53240b6e7dabca89ce8ad939d0a3969da2b33c3e4155fccbebae9ba
|
|
7
|
+
data.tar.gz: 20f44288fd8990544569af7f2a87d90d4ce898b2ce760cc95dd2f30c5a0c4ffc90bcc087cbfa22dbc188a904cc2e817756a83b5b3ffd648f75dc0413d3bec3ff
|
data/Changes.md
CHANGED
|
@@ -2,6 +2,35 @@
|
|
|
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.2
|
|
6
|
+
----------
|
|
7
|
+
|
|
8
|
+
- Initial release for `kiq`, Sidekiq's official terminal UI:
|
|
9
|
+
```
|
|
10
|
+
bundle exec kiq
|
|
11
|
+
```
|
|
12
|
+
Use REDIS_URL or REDIS_PROVIDER to point `kiq` to Redis.
|
|
13
|
+
- Mutation during iteration in `SortedSet#each` caused it to miss half of the jobs [#6936]
|
|
14
|
+
- Fix edge case resulting in nil crash on /busy page [#6954]
|
|
15
|
+
|
|
16
|
+
8.1.1
|
|
17
|
+
----------
|
|
18
|
+
|
|
19
|
+
- **DEPRECATION** `require 'sidekiq/testing'` and
|
|
20
|
+
`require 'sidekiq/testing/inline'`.
|
|
21
|
+
Add new `Sidekiq.testing!(mode)` API [#6931]
|
|
22
|
+
Requiring code should not enable process-wide changes.
|
|
23
|
+
```ruby
|
|
24
|
+
# Old, implicit
|
|
25
|
+
require "sidekiq/testing"
|
|
26
|
+
require "sidekiq/testing/inline"
|
|
27
|
+
# New, more explicit
|
|
28
|
+
Sidekiq.testing!(:fake)
|
|
29
|
+
Sidekiq.testing!(:inline)
|
|
30
|
+
```
|
|
31
|
+
- Fix race condition with Stop button in UI [#6935]
|
|
32
|
+
- Fix javascript error handler [#6893]
|
|
33
|
+
|
|
5
34
|
8.1.0
|
|
6
35
|
----------
|
|
7
36
|
|
data/README.md
CHANGED
|
@@ -90,7 +90,7 @@ Useful resources:
|
|
|
90
90
|
* The [Sidekiq tag](https://stackoverflow.com/questions/tagged/sidekiq) on Stack Overflow has lots of useful Q & A.
|
|
91
91
|
|
|
92
92
|
Every Thursday morning is Sidekiq Office Hour: I video chat and answer questions.
|
|
93
|
-
See the [Sidekiq support page](https://sidekiq.org/support
|
|
93
|
+
See the [Sidekiq support page](https://sidekiq.org/support/) for details.
|
|
94
94
|
|
|
95
95
|
Contributing
|
|
96
96
|
-----------------
|
data/bin/kiq
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
# This requires the default gemset so Sidekiq Pro
|
|
4
|
+
# and Sidekiq Enterprise can load any code extensions.
|
|
5
|
+
Bundler.require(:default, :tui)
|
|
6
|
+
|
|
7
|
+
require_relative "../lib/sidekiq/tui"
|
|
8
|
+
|
|
9
|
+
# Run any load hooks registered during Bundler.require
|
|
10
|
+
Sidekiq.loader.run_load_hooks(:tui)
|
|
11
|
+
|
|
12
|
+
tt = Sidekiq::TUI.new(Sidekiq.default_configuration)
|
|
13
|
+
|
|
14
|
+
RatatuiRuby.run do |tui|
|
|
15
|
+
tt.prepare(tui)
|
|
16
|
+
tt.run_loop
|
|
17
|
+
end
|
|
@@ -61,18 +61,21 @@ begin
|
|
|
61
61
|
|
|
62
62
|
# @api private
|
|
63
63
|
def enqueue(job)
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
64
|
+
# NB: Active Job only serializes keys it recognizes. We
|
|
65
|
+
# cannot set arbitrary key/values here.
|
|
66
|
+
options = {wrapped: job.class, queue: job.queue_name}
|
|
67
|
+
options[:profile] = job.profile if job.respond_to?(:profile) && !job.profile.nil?
|
|
68
|
+
|
|
69
|
+
wrapper = Sidekiq::ActiveJob::Wrapper.set(options)
|
|
70
|
+
job.provider_job_id = wrapper.perform_async(job.serialize)
|
|
68
71
|
end
|
|
69
72
|
|
|
70
73
|
# @api private
|
|
71
74
|
def enqueue_at(job, timestamp)
|
|
72
|
-
job.
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
).perform_at(timestamp, job.serialize)
|
|
75
|
+
options = {wrapped: job.class, queue: job.queue_name}
|
|
76
|
+
options[:profile] = job.profile if job.respond_to?(:profile) && !job.profile.nil?
|
|
77
|
+
|
|
78
|
+
job.provider_job_id = Sidekiq::ActiveJob::Wrapper.set(options).perform_at(timestamp, job.serialize)
|
|
76
79
|
end
|
|
77
80
|
|
|
78
81
|
# @api private
|
|
@@ -14,7 +14,10 @@ module Sidekiq
|
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
def create_job_file
|
|
17
|
-
template
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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 -
|
|
624
|
+
conn.zincrby(@parent.name, at.to_f - score, Sidekiq.dump_json(@item))
|
|
587
625
|
end
|
|
588
626
|
end
|
|
589
627
|
|
|
@@ -619,38 +657,8 @@ module Sidekiq
|
|
|
619
657
|
|
|
620
658
|
private
|
|
621
659
|
|
|
622
|
-
def remove_job
|
|
623
|
-
|
|
624
|
-
results = conn.multi { |transaction|
|
|
625
|
-
transaction.zrange(parent.name, score, score, "BYSCORE")
|
|
626
|
-
transaction.zremrangebyscore(parent.name, score, score)
|
|
627
|
-
}.first
|
|
628
|
-
|
|
629
|
-
if results.size == 1
|
|
630
|
-
yield results.first
|
|
631
|
-
else
|
|
632
|
-
# multiple jobs with the same score
|
|
633
|
-
# find the one with the right JID and push it
|
|
634
|
-
matched, nonmatched = results.partition { |message|
|
|
635
|
-
if message.index(jid)
|
|
636
|
-
msg = Sidekiq.load_json(message)
|
|
637
|
-
msg["jid"] == jid
|
|
638
|
-
else
|
|
639
|
-
false
|
|
640
|
-
end
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
msg = matched.first
|
|
644
|
-
yield msg if msg
|
|
645
|
-
|
|
646
|
-
# push the rest back onto the sorted set
|
|
647
|
-
conn.multi do |transaction|
|
|
648
|
-
nonmatched.each do |message|
|
|
649
|
-
transaction.zadd(parent.name, score.to_f.to_s, message)
|
|
650
|
-
end
|
|
651
|
-
end
|
|
652
|
-
end
|
|
653
|
-
end
|
|
660
|
+
def remove_job(&)
|
|
661
|
+
parent.remove_job(self, &)
|
|
654
662
|
end
|
|
655
663
|
end
|
|
656
664
|
|
|
@@ -819,6 +827,46 @@ module Sidekiq
|
|
|
819
827
|
nil
|
|
820
828
|
end
|
|
821
829
|
|
|
830
|
+
def remove_job(entry)
|
|
831
|
+
score = entry.score
|
|
832
|
+
jid = entry.jid
|
|
833
|
+
Sidekiq.redis do |conn|
|
|
834
|
+
results = conn.multi { |transaction|
|
|
835
|
+
transaction.zrange(name, score, score, "BYSCORE")
|
|
836
|
+
transaction.zremrangebyscore(name, score, score)
|
|
837
|
+
}.first
|
|
838
|
+
|
|
839
|
+
if results.size == 1
|
|
840
|
+
yield results.first
|
|
841
|
+
@_size -= 1
|
|
842
|
+
else
|
|
843
|
+
# multiple jobs with the same score
|
|
844
|
+
# find the one with the right JID and push it
|
|
845
|
+
matched, nonmatched = results.partition { |message|
|
|
846
|
+
if message.index(jid)
|
|
847
|
+
msg = Sidekiq.load_json(message)
|
|
848
|
+
msg["jid"] == jid
|
|
849
|
+
else
|
|
850
|
+
false
|
|
851
|
+
end
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
msg = matched.first
|
|
855
|
+
if msg
|
|
856
|
+
yield msg
|
|
857
|
+
@_size -= 1
|
|
858
|
+
end
|
|
859
|
+
|
|
860
|
+
# push the rest back onto the sorted set
|
|
861
|
+
conn.multi do |transaction|
|
|
862
|
+
nonmatched.each do |message|
|
|
863
|
+
transaction.zadd(name, score.to_f.to_s, message)
|
|
864
|
+
end
|
|
865
|
+
end
|
|
866
|
+
end
|
|
867
|
+
end
|
|
868
|
+
end
|
|
869
|
+
|
|
822
870
|
# :nodoc:
|
|
823
871
|
# @api private
|
|
824
872
|
def delete_by_value(name, value)
|
|
@@ -992,19 +1040,20 @@ module Sidekiq
|
|
|
992
1040
|
# you'll be happier this way
|
|
993
1041
|
conn.pipelined do |pipeline|
|
|
994
1042
|
procs.each do |key|
|
|
995
|
-
pipeline.hmget(key, "info", "busy", "beat", "quiet", "rss", "rtt_us")
|
|
1043
|
+
pipeline.hmget(key, "info", "concurrency", "busy", "beat", "quiet", "rss", "rtt_us")
|
|
996
1044
|
end
|
|
997
1045
|
end
|
|
998
1046
|
}
|
|
999
1047
|
|
|
1000
|
-
result.each do |info, busy, beat, quiet, rss, rtt_us|
|
|
1048
|
+
result.each do |info, concurrency, busy, beat, quiet, rss, rtt_us|
|
|
1001
1049
|
# If a process is stopped between when we query Redis for `procs` and
|
|
1002
1050
|
# when we query for `result`, we will have an item in `result` that is
|
|
1003
1051
|
# composed of `nil` values.
|
|
1004
1052
|
next if info.nil?
|
|
1005
1053
|
|
|
1006
1054
|
hash = Sidekiq.load_json(info)
|
|
1007
|
-
yield Process.new(hash.merge("
|
|
1055
|
+
yield Process.new(hash.merge("concurrency" => concurrency.to_i,
|
|
1056
|
+
"busy" => busy.to_i,
|
|
1008
1057
|
"beat" => beat.to_f,
|
|
1009
1058
|
"quiet" => quiet,
|
|
1010
1059
|
"rss" => rss.to_i,
|
|
@@ -1088,6 +1137,7 @@ module Sidekiq
|
|
|
1088
1137
|
def identity
|
|
1089
1138
|
self["identity"]
|
|
1090
1139
|
end
|
|
1140
|
+
alias_method :id, :identity
|
|
1091
1141
|
|
|
1092
1142
|
# deprecated, use capsules below
|
|
1093
1143
|
def queues
|
|
@@ -1161,6 +1211,10 @@ module Sidekiq
|
|
|
1161
1211
|
self["quiet"] == "true"
|
|
1162
1212
|
end
|
|
1163
1213
|
|
|
1214
|
+
def leader?
|
|
1215
|
+
Sidekiq.redis { |c| c.get("dear-leader") == identity }
|
|
1216
|
+
end
|
|
1217
|
+
|
|
1164
1218
|
private
|
|
1165
1219
|
|
|
1166
1220
|
def signal(sig)
|
data/lib/sidekiq/client.rb
CHANGED
|
@@ -132,12 +132,14 @@ module Sidekiq
|
|
|
132
132
|
# push_bulk('class' => MyJob, 'args' => (1..100_000).to_a, batch_size: 1_000)
|
|
133
133
|
#
|
|
134
134
|
def push_bulk(items)
|
|
135
|
-
batch_size = items.delete(:batch_size) || items.delete("batch_size") || 1_000
|
|
136
135
|
args = items["args"]
|
|
137
136
|
at = items.delete("at") || items.delete(:at)
|
|
138
137
|
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) })
|
|
139
138
|
raise ArgumentError, "Job 'at' Array must have same size as 'args' Array" if at.is_a?(Array) && at.size != args.size
|
|
140
139
|
|
|
140
|
+
# Use a smaller batch size by default for scheduled jobs since adding to sorted sets is more costly.
|
|
141
|
+
batch_size = items.delete(:batch_size) || items.delete("batch_size") || (at ? 100 : 1_000)
|
|
142
|
+
|
|
141
143
|
jid = items.delete("jid")
|
|
142
144
|
raise ArgumentError, "Explicitly passing 'jid' when pushing more than one job is not supported" if jid && args.size > 1
|
|
143
145
|
|
data/lib/sidekiq/component.rb
CHANGED
|
@@ -57,6 +57,9 @@ module Sidekiq
|
|
|
57
57
|
end
|
|
58
58
|
|
|
59
59
|
def tid
|
|
60
|
+
# We XOR with PID to ensure Thread IDs changes after fork.
|
|
61
|
+
# I'm unclear why we don't multiply the two values to better guarantee
|
|
62
|
+
# a unique value but it's been this way for quite a while now. #3685
|
|
60
63
|
Thread.current["sidekiq_tid"] ||= (Thread.current.object_id ^ ::Process.pid).to_s(36)
|
|
61
64
|
end
|
|
62
65
|
|
data/lib/sidekiq/launcher.rb
CHANGED
|
@@ -176,6 +176,7 @@ module Sidekiq
|
|
|
176
176
|
transaction.sadd("processes", [key])
|
|
177
177
|
transaction.exists(key)
|
|
178
178
|
transaction.hset(key, "info", to_json,
|
|
179
|
+
"concurrency", @config.total_concurrency,
|
|
179
180
|
"busy", curstate.size,
|
|
180
181
|
"beat", Time.now.to_f,
|
|
181
182
|
"rtt_us", rtt,
|
|
@@ -257,7 +258,6 @@ module Sidekiq
|
|
|
257
258
|
"started_at" => Time.now.to_f,
|
|
258
259
|
"pid" => ::Process.pid,
|
|
259
260
|
"tag" => @config[:tag] || "",
|
|
260
|
-
"concurrency" => @config.total_concurrency,
|
|
261
261
|
"capsules" => @config.capsules.each_with_object({}) { |(name, cap), memo|
|
|
262
262
|
memo[name] = cap.to_h
|
|
263
263
|
},
|
data/lib/sidekiq/manager.rb
CHANGED
data/lib/sidekiq/paginator.rb
CHANGED
|
@@ -62,7 +62,12 @@ module Sidekiq
|
|
|
62
62
|
pageidx = current_page - 1
|
|
63
63
|
starting = pageidx * page_size
|
|
64
64
|
items = items.to_a
|
|
65
|
-
|
|
65
|
+
total_size = items.size
|
|
66
|
+
if starting > total_size
|
|
67
|
+
starting = 0
|
|
68
|
+
current_page = 1
|
|
69
|
+
end
|
|
70
|
+
[current_page, total_size, items[starting, page_size]]
|
|
66
71
|
end
|
|
67
72
|
end
|
|
68
73
|
end
|