sidekiq 3.3.4 → 3.4.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.
- checksums.yaml +4 -4
- data/3.0-Upgrade.md +1 -1
- data/Changes.md +18 -1
- data/Gemfile +1 -1
- data/Pro-Changes.md +17 -2
- data/lib/sidekiq.rb +19 -3
- data/lib/sidekiq/api.rb +5 -1
- data/lib/sidekiq/cli.rb +6 -2
- data/lib/sidekiq/client.rb +6 -2
- data/lib/sidekiq/exception_handler.rb +1 -1
- data/lib/sidekiq/logging.rb +7 -1
- data/lib/sidekiq/manager.rb +15 -9
- data/lib/sidekiq/processor.rb +6 -2
- data/lib/sidekiq/scheduled.rb +21 -15
- data/lib/sidekiq/testing.rb +2 -0
- data/lib/sidekiq/util.rb +4 -2
- data/lib/sidekiq/version.rb +1 -1
- data/lib/sidekiq/web.rb +2 -2
- data/lib/sidekiq/web_helpers.rb +1 -0
- data/test/test_manager.rb +3 -1
- data/test/test_scheduled.rb +49 -15
- data/test/test_scheduling.rb +9 -0
- data/test/test_sidekiq.rb +1 -1
- data/test/test_web_helpers.rb +6 -0
- data/web/assets/javascripts/application.js +2 -0
- data/web/assets/stylesheets/application.css +34 -8
- data/web/views/_job_info.erb +68 -66
- data/web/views/_nav.erb +0 -1
- data/web/views/busy.erb +66 -62
- data/web/views/dead.erb +21 -18
- data/web/views/morgue.erb +40 -38
- data/web/views/queue.erb +31 -29
- data/web/views/queues.erb +25 -23
- data/web/views/retries.erb +42 -40
- data/web/views/retry.erb +21 -18
- data/web/views/scheduled.erb +32 -30
- metadata +2 -2
data/test/test_scheduled.rb
CHANGED
@@ -55,32 +55,66 @@ class TestScheduled < Sidekiq::Test
|
|
55
55
|
end
|
56
56
|
|
57
57
|
it 'should empty the retry and scheduled queues up to the current time' do
|
58
|
+
created_time = Time.new(2013, 2, 3)
|
58
59
|
enqueued_time = Time.new(2013, 2, 4)
|
59
60
|
|
60
|
-
Time.stub(:now,
|
61
|
-
@retry.schedule (
|
62
|
-
@retry.schedule (
|
63
|
-
@retry.schedule (
|
64
|
-
@scheduled.schedule (
|
65
|
-
@scheduled.schedule (
|
66
|
-
@scheduled.schedule (
|
61
|
+
Time.stub(:now, created_time) do
|
62
|
+
@retry.schedule (enqueued_time - 60).to_f, @error_1.merge!('created_at' => created_time.to_f)
|
63
|
+
@retry.schedule (enqueued_time - 50).to_f, @error_2.merge!('created_at' => created_time.to_f)
|
64
|
+
@retry.schedule (enqueued_time + 60).to_f, @error_3.merge!('created_at' => created_time.to_f)
|
65
|
+
@scheduled.schedule (enqueued_time - 60).to_f, @future_1.merge!('created_at' => created_time.to_f)
|
66
|
+
@scheduled.schedule (enqueued_time - 50).to_f, @future_2.merge!('created_at' => created_time.to_f)
|
67
|
+
@scheduled.schedule (enqueued_time + 60).to_f, @future_3.merge!('created_at' => created_time.to_f)
|
68
|
+
end
|
67
69
|
|
70
|
+
Time.stub(:now, enqueued_time) do
|
68
71
|
@poller.poll
|
69
72
|
|
70
73
|
Sidekiq.redis do |conn|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
assert_equal 1, conn.llen("queue:queue_5")
|
78
|
-
assert_equal enqueued_time.to_f, Sidekiq.load_json(conn.lrange("queue:queue_5", 0, -1)[0])['enqueued_at']
|
74
|
+
%w(queue:queue_1 queue:queue_2 queue:queue_4 queue:queue_5).each do |queue_name|
|
75
|
+
assert_equal 1, conn.llen(queue_name)
|
76
|
+
job = Sidekiq.load_json(conn.lrange(queue_name, 0, -1)[0])
|
77
|
+
assert_equal enqueued_time.to_f, job['enqueued_at']
|
78
|
+
assert_equal created_time.to_f, job['created_at']
|
79
|
+
end
|
79
80
|
end
|
80
81
|
|
81
82
|
assert_equal 1, @retry.size
|
82
83
|
assert_equal 1, @scheduled.size
|
83
84
|
end
|
84
85
|
end
|
86
|
+
|
87
|
+
def with_sidekiq_option(name, value)
|
88
|
+
_original, Sidekiq.options[name] = Sidekiq.options[name], value
|
89
|
+
begin
|
90
|
+
yield
|
91
|
+
ensure
|
92
|
+
Sidekiq.options[name] = _original
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'generates random intervals that target a configured average' do
|
97
|
+
with_sidekiq_option(:poll_interval_average, 10) do
|
98
|
+
i = 500
|
99
|
+
intervals = i.times.map{ @poller.send(:random_poll_interval) }
|
100
|
+
|
101
|
+
assert intervals.all?{|i| i >= 5}
|
102
|
+
assert intervals.all?{|i| i <= 15}
|
103
|
+
assert_in_delta 10, intervals.reduce(&:+).to_f / i, 0.5
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'calculates an average poll interval based on the number of known Sidekiq processes' do
|
108
|
+
with_sidekiq_option(:average_scheduled_poll_interval, 10) do
|
109
|
+
3.times do |i|
|
110
|
+
Sidekiq.redis do |conn|
|
111
|
+
conn.sadd("processes", "process-#{i}")
|
112
|
+
conn.hset("process-#{i}", "info", nil)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
assert_equal 30, @poller.send(:scaled_poll_interval)
|
117
|
+
end
|
118
|
+
end
|
85
119
|
end
|
86
120
|
end
|
data/test/test_scheduling.rb
CHANGED
@@ -57,6 +57,15 @@ class TestScheduling < Sidekiq::Test
|
|
57
57
|
assert Sidekiq::Client.push_bulk('class' => ScheduledWorker, 'args' => [['mike'], ['mike']], 'at' => 600)
|
58
58
|
@redis.verify
|
59
59
|
end
|
60
|
+
|
61
|
+
it 'removes the enqueued_at field when scheduling' do
|
62
|
+
@redis.expect :zadd, true do |key, args|
|
63
|
+
job = Sidekiq.load_json(args.first.last)
|
64
|
+
job.key?('created_at') && !job.key?('enqueued_at')
|
65
|
+
end
|
66
|
+
assert ScheduledWorker.perform_in(1.month, 'mike')
|
67
|
+
@redis.verify
|
68
|
+
end
|
60
69
|
end
|
61
70
|
|
62
71
|
end
|
data/test/test_sidekiq.rb
CHANGED
@@ -31,7 +31,7 @@ class TestSidekiq < Sidekiq::Test
|
|
31
31
|
|
32
32
|
it "allows angry developers to express their emotional constitution and remedies it" do
|
33
33
|
Sidekiq.❨╯°□°❩╯︵┻━┻
|
34
|
-
assert_equal "Calm down,
|
34
|
+
assert_equal "Calm down, yo.\n", $stdout.string
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
data/test/test_web_helpers.rb
CHANGED
@@ -42,5 +42,11 @@ class TestWebHelpers < Sidekiq::Test
|
|
42
42
|
|
43
43
|
obj = Helpers.new('HTTP_ACCEPT_LANGUAGE' => 'zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4,ru;q=0.2')
|
44
44
|
assert_equal 'zh-cn', obj.locale
|
45
|
+
|
46
|
+
obj = Helpers.new('HTTP_ACCEPT_LANGUAGE' => 'en-us; *')
|
47
|
+
assert_equal 'en', obj.locale
|
48
|
+
|
49
|
+
obj = Helpers.new('HTTP_ACCEPT_LANGUAGE' => '*')
|
50
|
+
assert_equal 'en', obj.locale
|
45
51
|
end
|
46
52
|
end
|
@@ -165,6 +165,10 @@ header.row .pagination {
|
|
165
165
|
width: 100%;
|
166
166
|
}
|
167
167
|
|
168
|
+
.table_container {
|
169
|
+
overflow: overlay;
|
170
|
+
}
|
171
|
+
|
168
172
|
table.table-white {
|
169
173
|
background-color: #fff;
|
170
174
|
}
|
@@ -738,14 +742,36 @@ div.interval-slider input {
|
|
738
742
|
}
|
739
743
|
}
|
740
744
|
|
741
|
-
.redis-url
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
+
.redis-url, .redis-namespace {
|
746
|
+
overflow: scroll;
|
747
|
+
white-space: nowrap;
|
748
|
+
}
|
749
|
+
|
750
|
+
@media (min-width: 768px) {
|
751
|
+
.redis-url {
|
752
|
+
max-width: 200px;
|
753
|
+
}
|
754
|
+
|
755
|
+
.redis-namespace {
|
756
|
+
max-width: 150px;
|
757
|
+
}
|
745
758
|
}
|
746
759
|
|
747
|
-
|
748
|
-
{
|
749
|
-
max-width:
|
750
|
-
|
760
|
+
@media (min-width: 992px) {
|
761
|
+
.redis-url {
|
762
|
+
max-width: 340px;
|
763
|
+
}
|
764
|
+
|
765
|
+
.redis-namespace {
|
766
|
+
max-width: 350px;
|
767
|
+
}
|
768
|
+
}
|
769
|
+
@media (min-width: 1200px) {
|
770
|
+
.redis-url {
|
771
|
+
max-width: 540px;
|
772
|
+
}
|
773
|
+
|
774
|
+
.redis-namespace {
|
775
|
+
max-width: 350px;
|
776
|
+
}
|
751
777
|
}
|
data/web/views/_job_info.erb
CHANGED
@@ -2,81 +2,83 @@
|
|
2
2
|
<h3><%= t('Job') %></h3>
|
3
3
|
</header>
|
4
4
|
|
5
|
-
<
|
6
|
-
<
|
7
|
-
<
|
8
|
-
<th><%= t('Queue') %></th>
|
9
|
-
<td>
|
10
|
-
<a href="<%= root_path %>queues/<%= job.queue %>"><%= job.queue %></a>
|
11
|
-
</td>
|
12
|
-
</tr>
|
13
|
-
<tr>
|
14
|
-
<th><%= t('Job') %></th>
|
15
|
-
<td>
|
16
|
-
<code><%= job.display_class %></code>
|
17
|
-
</td>
|
18
|
-
</tr>
|
19
|
-
<tr>
|
20
|
-
<th><%= t('Arguments') %></th>
|
21
|
-
<td>
|
22
|
-
<code class="code-wrap">
|
23
|
-
<!-- We don't want to truncate any job arguments when viewing a single job's status page -->
|
24
|
-
<div class="args-extended"><%= display_args(job.display_args, nil) %></div>
|
25
|
-
</code>
|
26
|
-
</td>
|
27
|
-
</tr>
|
28
|
-
<tr>
|
29
|
-
<th>JID</th>
|
30
|
-
<td>
|
31
|
-
<code><%= job.jid %></code>
|
32
|
-
</td>
|
33
|
-
</tr>
|
34
|
-
<tr>
|
35
|
-
<th><%= t('Enqueued') %></th>
|
36
|
-
<td><%= relative_time(job.enqueued_at) %></td>
|
37
|
-
</tr>
|
38
|
-
<% unless retry_extra_items(job).empty? %>
|
5
|
+
<div class="table_container">
|
6
|
+
<table class="table table-bordered table-striped">
|
7
|
+
<tbody>
|
39
8
|
<tr>
|
40
|
-
<th><%= t('
|
9
|
+
<th><%= t('Queue') %></th>
|
41
10
|
<td>
|
42
|
-
<
|
43
|
-
|
11
|
+
<a href="<%= root_path %>queues/<%= job.queue %>"><%= job.queue %></a>
|
12
|
+
</td>
|
13
|
+
</tr>
|
14
|
+
<tr>
|
15
|
+
<th><%= t('Job') %></th>
|
16
|
+
<td>
|
17
|
+
<code><%= job.display_class %></code>
|
18
|
+
</td>
|
19
|
+
</tr>
|
20
|
+
<tr>
|
21
|
+
<th><%= t('Arguments') %></th>
|
22
|
+
<td>
|
23
|
+
<code class="code-wrap">
|
24
|
+
<!-- We don't want to truncate any job arguments when viewing a single job's status page -->
|
25
|
+
<div class="args-extended"><%= display_args(job.display_args, nil) %></div>
|
44
26
|
</code>
|
45
27
|
</td>
|
46
28
|
</tr>
|
47
|
-
|
48
|
-
|
49
|
-
|
29
|
+
<tr>
|
30
|
+
<th>JID</th>
|
31
|
+
<td>
|
32
|
+
<code><%= job.jid %></code>
|
33
|
+
</td>
|
34
|
+
</tr>
|
35
|
+
<tr>
|
36
|
+
<th><%= t('Enqueued') %></th>
|
37
|
+
<td><%= relative_time(job.enqueued_at) %></td>
|
38
|
+
</tr>
|
39
|
+
<% unless retry_extra_items(job).empty? %>
|
50
40
|
<tr>
|
51
|
-
<th><%= t('
|
52
|
-
<td
|
41
|
+
<th><%= t('Extras') %></th>
|
42
|
+
<td>
|
43
|
+
<code>
|
44
|
+
<%= retry_extra_items(job).inspect %>
|
45
|
+
</code>
|
46
|
+
</td>
|
53
47
|
</tr>
|
48
|
+
<% end %>
|
49
|
+
<% if type == :retry %>
|
50
|
+
<% if job['retry_count'] && job['retry_count'] > 0 %>
|
51
|
+
<tr>
|
52
|
+
<th><%= t('RetryCount') %></th>
|
53
|
+
<td><%= job['retry_count'] %></td>
|
54
|
+
</tr>
|
55
|
+
<tr>
|
56
|
+
<th><%= t('LastRetry') %></th>
|
57
|
+
<td><%= relative_time(Time.at(job['retried_at'])) %></td>
|
58
|
+
</tr>
|
59
|
+
<% else %>
|
60
|
+
<tr>
|
61
|
+
<th><%= t('OriginallyFailed') %></th>
|
62
|
+
<td><%= relative_time(Time.at(job['failed_at'])) %></td>
|
63
|
+
</tr>
|
64
|
+
<% end %>
|
54
65
|
<tr>
|
55
|
-
<th><%= t('
|
56
|
-
<td><%= relative_time(
|
66
|
+
<th><%= t('NextRetry') %></th>
|
67
|
+
<td><%= relative_time(job.at) %></td>
|
57
68
|
</tr>
|
58
|
-
<%
|
69
|
+
<% end %>
|
70
|
+
<% if type == :scheduled %>
|
59
71
|
<tr>
|
60
|
-
<th><%= t('
|
61
|
-
<td><%= relative_time(
|
72
|
+
<th><%= t('Scheduled') %></th>
|
73
|
+
<td><%= relative_time(job.at) %></td>
|
62
74
|
</tr>
|
63
75
|
<% end %>
|
64
|
-
|
65
|
-
<
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
</tr>
|
74
|
-
<% end %>
|
75
|
-
<% if type == :dead %>
|
76
|
-
<tr>
|
77
|
-
<th><%= t('LastRetry') %></th>
|
78
|
-
<td><%= relative_time(job.at) %></td>
|
79
|
-
</tr>
|
80
|
-
<% end %>
|
81
|
-
</tbody>
|
82
|
-
</table>
|
76
|
+
<% if type == :dead %>
|
77
|
+
<tr>
|
78
|
+
<th><%= t('LastRetry') %></th>
|
79
|
+
<td><%= relative_time(job.at) %></td>
|
80
|
+
</tr>
|
81
|
+
<% end %>
|
82
|
+
</tbody>
|
83
|
+
</table>
|
84
|
+
</div>
|
data/web/views/_nav.erb
CHANGED
data/web/views/busy.erb
CHANGED
@@ -13,41 +13,43 @@
|
|
13
13
|
</div>
|
14
14
|
</div>
|
15
15
|
|
16
|
-
<
|
17
|
-
<
|
18
|
-
<
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
<
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
<
|
41
|
-
<
|
42
|
-
<
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
16
|
+
<div class="table_container">
|
17
|
+
<table class="processes table table-hover table-bordered table-striped table-white">
|
18
|
+
<thead>
|
19
|
+
<th><%= t('Name') %></th>
|
20
|
+
<th><%= t('Started') %></th>
|
21
|
+
<th><%= t('Threads') %></th>
|
22
|
+
<th><%= t('Busy') %></th>
|
23
|
+
<th> </th>
|
24
|
+
</thead>
|
25
|
+
<% processes.each do |process| %>
|
26
|
+
<tr>
|
27
|
+
<td width="50%">
|
28
|
+
<%= "#{process['hostname']}:#{process['pid']}" %>
|
29
|
+
<span class="label label-success"><%= process.tag %></span>
|
30
|
+
<% process.labels.each do |label| %>
|
31
|
+
<span class="label label-info"><%= label %></span>
|
32
|
+
<% end %>
|
33
|
+
<br>
|
34
|
+
<b><%= "#{t('Queues')}: " %></b>
|
35
|
+
<%= process['queues'] * ", " %>
|
36
|
+
</td>
|
37
|
+
<td><%= relative_time(Time.at(process['started_at'])) %></td>
|
38
|
+
<td><%= process['concurrency'] %></td>
|
39
|
+
<td><%= process['busy'] %></td>
|
40
|
+
<td>
|
41
|
+
<div class="btn-group pull-right">
|
42
|
+
<form method="POST">
|
43
|
+
<input type="hidden" name="identity" value="<%= process['identity'] %>"/>
|
44
|
+
<button class="btn btn-warn" type="submit" name="quiet" value="1"><%= t('Quiet') %></button>
|
45
|
+
<button class="btn btn-danger" type="submit" name="stop" value="1"><%= t('Stop') %></button>
|
46
|
+
</form>
|
47
|
+
</div>
|
48
|
+
</td>
|
49
|
+
</tr>
|
50
|
+
<% end %>
|
51
|
+
</table>
|
52
|
+
</div>
|
51
53
|
|
52
54
|
<div class="row header">
|
53
55
|
<div class="col-sm-7">
|
@@ -55,30 +57,32 @@
|
|
55
57
|
</div>
|
56
58
|
</div>
|
57
59
|
|
58
|
-
<
|
59
|
-
<
|
60
|
-
<
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
<%
|
70
|
-
|
71
|
-
<
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
<
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
<
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
60
|
+
<div class="table_container">
|
61
|
+
<table class="workers table table-hover table-bordered table-striped table-white">
|
62
|
+
<thead>
|
63
|
+
<th><%= t('Process') %></th>
|
64
|
+
<th><%= t('TID') %></th>
|
65
|
+
<th><%= t('JID') %></th>
|
66
|
+
<th><%= t('Queue') %></th>
|
67
|
+
<th><%= t('Job') %></th>
|
68
|
+
<th><%= t('Arguments') %></th>
|
69
|
+
<th><%= t('Started') %></th>
|
70
|
+
</thead>
|
71
|
+
<% workers.each do |process, thread, msg| %>
|
72
|
+
<% job = Sidekiq::Job.new(msg['payload']) %>
|
73
|
+
<tr>
|
74
|
+
<td><%= process %></td>
|
75
|
+
<td><%= thread %></td>
|
76
|
+
<td><%= job.jid %></td>
|
77
|
+
<td>
|
78
|
+
<a href="<%= root_path %>queues/<%= msg['queue'] %>"><%= msg['queue'] %></a>
|
79
|
+
</td>
|
80
|
+
<td><%= job.display_class %></td>
|
81
|
+
<td>
|
82
|
+
<div class="args"><%= display_args(job.display_args) %></div>
|
83
|
+
</td>
|
84
|
+
<td><%= relative_time(Time.at(msg['run_at'])) %></td>
|
85
|
+
</tr>
|
86
|
+
<% end %>
|
87
|
+
</table>
|
88
|
+
</div>
|