sidekiq 3.4.1 → 4.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.
- checksums.yaml +4 -4
- data/4.0-Upgrade.md +50 -0
- data/COMM-LICENSE +55 -45
- data/Changes.md +73 -1
- data/Ent-Changes.md +66 -0
- data/Gemfile +7 -1
- data/Pro-2.0-Upgrade.md +2 -2
- data/Pro-3.0-Upgrade.md +46 -0
- data/Pro-Changes.md +65 -2
- data/README.md +8 -9
- data/bin/sidekiq +5 -0
- data/bin/sidekiqctl +8 -2
- data/bin/sidekiqload +167 -0
- data/lib/sidekiq/api.rb +29 -31
- data/lib/sidekiq/cli.rb +41 -42
- data/lib/sidekiq/client.rb +5 -10
- data/lib/sidekiq/fetch.rb +35 -111
- data/lib/sidekiq/launcher.rb +102 -42
- data/lib/sidekiq/manager.rb +78 -180
- data/lib/sidekiq/middleware/server/logging.rb +10 -5
- data/lib/sidekiq/middleware/server/retry_jobs.rb +5 -5
- data/lib/sidekiq/processor.rb +126 -97
- data/lib/sidekiq/redis_connection.rb +23 -5
- data/lib/sidekiq/scheduled.rb +47 -26
- data/lib/sidekiq/testing.rb +96 -17
- data/lib/sidekiq/util.rb +20 -0
- data/lib/sidekiq/version.rb +1 -1
- data/lib/sidekiq/web.rb +17 -1
- data/lib/sidekiq/web_helpers.rb +26 -4
- data/lib/sidekiq/worker.rb +14 -0
- data/lib/sidekiq.rb +37 -14
- data/sidekiq.gemspec +11 -11
- data/test/helper.rb +45 -10
- data/test/test_actors.rb +137 -0
- data/test/test_api.rb +388 -388
- data/test/test_cli.rb +29 -59
- data/test/test_client.rb +60 -135
- data/test/test_extensions.rb +29 -23
- data/test/test_fetch.rb +2 -57
- data/test/test_launcher.rb +80 -0
- data/test/test_logging.rb +1 -1
- data/test/test_manager.rb +16 -131
- data/test/test_middleware.rb +3 -5
- data/test/test_processor.rb +110 -76
- data/test/test_rails.rb +21 -0
- data/test/test_redis_connection.rb +0 -1
- data/test/test_retry.rb +114 -162
- data/test/test_scheduled.rb +11 -17
- data/test/test_scheduling.rb +20 -42
- data/test/test_sidekiq.rb +46 -16
- data/test/test_testing.rb +80 -20
- data/test/test_testing_fake.rb +68 -8
- data/test/test_testing_inline.rb +3 -3
- data/test/test_util.rb +16 -0
- data/test/test_web.rb +17 -3
- data/test/test_web_helpers.rb +3 -2
- data/web/assets/images/favicon.ico +0 -0
- data/web/assets/javascripts/application.js +6 -1
- data/web/assets/javascripts/dashboard.js +2 -8
- data/web/assets/javascripts/locales/jquery.timeago.pt-br.js +14 -14
- data/web/assets/stylesheets/application.css +33 -56
- data/web/locales/de.yml +1 -1
- data/web/locales/en.yml +1 -0
- data/web/locales/{no.yml → nb.yml} +10 -2
- data/web/locales/uk.yml +76 -0
- data/web/views/_footer.erb +2 -7
- data/web/views/_job_info.erb +1 -1
- data/web/views/_nav.erb +2 -2
- data/web/views/_poll_js.erb +5 -0
- data/web/views/{_poll.erb → _poll_link.erb} +0 -3
- data/web/views/busy.erb +2 -1
- data/web/views/dead.erb +1 -0
- data/web/views/layout.erb +2 -0
- data/web/views/morgue.erb +3 -0
- data/web/views/queue.erb +1 -0
- data/web/views/queues.erb +1 -0
- data/web/views/retries.erb +3 -0
- data/web/views/retry.erb +1 -0
- data/web/views/scheduled.erb +1 -0
- data/web/views/scheduled_job_info.erb +1 -0
- metadata +81 -47
- data/lib/sidekiq/actor.rb +0 -39
- data/test/test_worker_generator.rb +0 -17
data/README.md
CHANGED
@@ -4,7 +4,6 @@ Sidekiq
|
|
4
4
|
[![Gem Version](https://badge.fury.io/rb/sidekiq.svg)](https://rubygems.org/gems/sidekiq)
|
5
5
|
[![Code Climate](https://codeclimate.com/github/mperham/sidekiq.svg)](https://codeclimate.com/github/mperham/sidekiq)
|
6
6
|
[![Build Status](https://travis-ci.org/mperham/sidekiq.svg)](https://travis-ci.org/mperham/sidekiq)
|
7
|
-
[![Coverage Status](https://coveralls.io/repos/mperham/sidekiq/badge.svg?branch=master)](https://coveralls.io/r/mperham/sidekiq)
|
8
7
|
[![Gitter Chat](https://badges.gitter.im/mperham/sidekiq.svg)](https://gitter.im/mperham/sidekiq)
|
9
8
|
|
10
9
|
|
@@ -33,7 +32,7 @@ are untested but might work fine. MRI 1.9 is no longer supported.
|
|
33
32
|
|
34
33
|
All Rails releases starting from 3.2 are officially supported.
|
35
34
|
|
36
|
-
Redis 2.
|
35
|
+
Redis 2.8 or greater is required.
|
37
36
|
|
38
37
|
|
39
38
|
Installation
|
@@ -45,7 +44,7 @@ Installation
|
|
45
44
|
Getting Started
|
46
45
|
-----------------
|
47
46
|
|
48
|
-
See the [
|
47
|
+
See the [Getting Started wiki page](https://github.com/mperham/sidekiq/wiki/Getting-Started) and follow the simple setup process.
|
49
48
|
You can watch [Railscast #366](http://railscasts.com/episodes/366-sidekiq) to see Sidekiq in action. If you do everything right, you should see this:
|
50
49
|
|
51
50
|
![Web UI](https://github.com/mperham/sidekiq/raw/master/examples/web-ui.png)
|
@@ -54,10 +53,10 @@ You can watch [Railscast #366](http://railscasts.com/episodes/366-sidekiq) to se
|
|
54
53
|
Want to Upgrade?
|
55
54
|
-------------------
|
56
55
|
|
57
|
-
I also sell Sidekiq Pro,
|
58
|
-
features, a commercial-friendly license and
|
56
|
+
I also sell Sidekiq Pro and Sidekiq Enterprise, extensions to Sidekiq which provide more
|
57
|
+
features, a commercial-friendly license and allow you to support high
|
59
58
|
quality open source development all at the same time. Please see the
|
60
|
-
[Sidekiq
|
59
|
+
[Sidekiq](http://sidekiq.org/) homepage for more detail.
|
61
60
|
|
62
61
|
|
63
62
|
More Information
|
@@ -67,7 +66,7 @@ Please see the [sidekiq wiki](https://github.com/mperham/sidekiq/wiki) for the o
|
|
67
66
|
[mperham/sidekiq on Gitter](https://gitter.im/mperham/sidekiq) is dedicated to this project,
|
68
67
|
but bug reports or feature requests suggestions should still go through [issues on Github](https://github.com/mperham/sidekiq/issues). Release announcements are made to the [@sidekiq](https://twitter.com/sidekiq) Twitter account.
|
69
68
|
|
70
|
-
You may also find useful a [
|
69
|
+
You may also find useful a [Reddit area](https://reddit.com/r/sidekiq) dedicated to Sidekiq discussion and [a Sidekiq tag](https://stackoverflow.com/questions/tagged/sidekiq) on Stack Overflow.
|
71
70
|
|
72
71
|
|
73
72
|
Problems?
|
@@ -76,14 +75,14 @@ Problems?
|
|
76
75
|
**Please do not directly email any Sidekiq committers with questions or problems.** A community is best served when discussions are held in public.
|
77
76
|
|
78
77
|
If you have a problem, please review the [FAQ](https://github.com/mperham/sidekiq/wiki/FAQ) and [Troubleshooting](https://github.com/mperham/sidekiq/wiki/Problems-and-Troubleshooting) wiki pages. Searching the issues for your problem is also a good idea. If that doesn't help, feel free to email the Sidekiq mailing list, chat in Gitter, or open a new issue.
|
79
|
-
|
78
|
+
StackOverflow or Reddit is the preferred place to ask questions on usage. If you are encountering what you think is a bug, please open an issue.
|
80
79
|
|
81
80
|
|
82
81
|
Thanks
|
83
82
|
-----------------
|
84
83
|
|
85
84
|
Sidekiq stays fast by using the [JProfiler java profiler](http://www.ej-technologies.com/products/jprofiler/overview.html) to find and fix
|
86
|
-
performance problems on JRuby. Unfortunately MRI does not have good
|
85
|
+
performance problems on JRuby. Unfortunately MRI does not have good multithreaded profiling tools.
|
87
86
|
|
88
87
|
|
89
88
|
License
|
data/bin/sidekiq
CHANGED
data/bin/sidekiqctl
CHANGED
@@ -41,9 +41,13 @@ class Sidekiqctl
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def fetch_process
|
44
|
-
Process.
|
44
|
+
Process.kill(0, pid)
|
45
45
|
rescue Errno::ESRCH
|
46
46
|
done "Process doesn't exist", :error
|
47
|
+
# We were not allowed to send a signal, but the process must have existed
|
48
|
+
# when Process.kill() was called.
|
49
|
+
rescue Errno::EPERM
|
50
|
+
return pid
|
47
51
|
end
|
48
52
|
|
49
53
|
def done(msg, error = nil)
|
@@ -67,10 +71,12 @@ class Sidekiqctl
|
|
67
71
|
`kill -TERM #{pid}`
|
68
72
|
kill_timeout.times do
|
69
73
|
begin
|
70
|
-
Process.
|
74
|
+
Process.kill(0, pid)
|
71
75
|
rescue Errno::ESRCH
|
72
76
|
FileUtils.rm_f pidfile
|
73
77
|
done 'Sidekiq shut down gracefully.'
|
78
|
+
rescue Errno::EPERM
|
79
|
+
done 'Not permitted to shut down Sidekiq.'
|
74
80
|
end
|
75
81
|
sleep 1
|
76
82
|
end
|
data/bin/sidekiqload
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Quiet some warnings we see when running in warning mode:
|
4
|
+
# RUBYOPT=-w bundle exec sidekiq
|
5
|
+
$TESTING = false
|
6
|
+
|
7
|
+
#require 'ruby-prof'
|
8
|
+
Bundler.require(:default)
|
9
|
+
|
10
|
+
require_relative '../lib/sidekiq/cli'
|
11
|
+
require_relative '../lib/sidekiq/launcher'
|
12
|
+
|
13
|
+
include Sidekiq::Util
|
14
|
+
|
15
|
+
# brew tap shopify/shopify
|
16
|
+
# brew install toxiproxy
|
17
|
+
# gem install toxiproxy
|
18
|
+
require 'toxiproxy'
|
19
|
+
# simulate a non-localhost network for realer-world conditions.
|
20
|
+
# adding 1ms of network latency has an ENORMOUS impact on benchmarks
|
21
|
+
Toxiproxy.populate([{
|
22
|
+
"name": "redis",
|
23
|
+
"listen": "127.0.0.1:6380",
|
24
|
+
"upstream": "127.0.0.1:6379"
|
25
|
+
}])
|
26
|
+
|
27
|
+
|
28
|
+
Sidekiq.configure_server do |config|
|
29
|
+
config.redis = { db: 13, port: 6380 }
|
30
|
+
#config.redis = { db: 13 }
|
31
|
+
config.options[:queues] << 'default'
|
32
|
+
config.logger.level = Logger::ERROR
|
33
|
+
config.average_scheduled_poll_interval = 2
|
34
|
+
config.reliable! if defined?(Sidekiq::Pro)
|
35
|
+
end
|
36
|
+
|
37
|
+
class LoadWorker
|
38
|
+
include Sidekiq::Worker
|
39
|
+
sidekiq_options retry: 1
|
40
|
+
sidekiq_retry_in do |x|
|
41
|
+
1
|
42
|
+
end
|
43
|
+
|
44
|
+
def perform(idx)
|
45
|
+
#raise idx.to_s if idx % 100 == 1
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# brew tap shopify/shopify
|
50
|
+
# brew install toxiproxy
|
51
|
+
# gem install toxiproxy
|
52
|
+
require 'toxiproxy'
|
53
|
+
# simulate a non-localhost network for realer-world conditions.
|
54
|
+
# adding 1ms of network latency has an ENORMOUS impact on benchmarks
|
55
|
+
Toxiproxy.populate([{
|
56
|
+
"name": "redis",
|
57
|
+
"listen": "127.0.0.1:6380",
|
58
|
+
"upstream": "127.0.0.1:6379"
|
59
|
+
}])
|
60
|
+
|
61
|
+
self_read, self_write = IO.pipe
|
62
|
+
%w(INT TERM USR1 USR2 TTIN).each do |sig|
|
63
|
+
begin
|
64
|
+
trap sig do
|
65
|
+
self_write.puts(sig)
|
66
|
+
end
|
67
|
+
rescue ArgumentError
|
68
|
+
puts "Signal #{sig} not supported"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
Sidekiq.redis {|c| c.flushdb}
|
73
|
+
def handle_signal(launcher, sig)
|
74
|
+
Sidekiq.logger.debug "Got #{sig} signal"
|
75
|
+
case sig
|
76
|
+
when 'INT'
|
77
|
+
# Handle Ctrl-C in JRuby like MRI
|
78
|
+
# http://jira.codehaus.org/browse/JRUBY-4637
|
79
|
+
raise Interrupt
|
80
|
+
when 'TERM'
|
81
|
+
# Heroku sends TERM and then waits 10 seconds for process to exit.
|
82
|
+
raise Interrupt
|
83
|
+
when 'USR1'
|
84
|
+
Sidekiq.logger.info "Received USR1, no longer accepting new work"
|
85
|
+
launcher.quiet
|
86
|
+
when 'USR2'
|
87
|
+
if Sidekiq.options[:logfile]
|
88
|
+
Sidekiq.logger.info "Received USR2, reopening log file"
|
89
|
+
Sidekiq::Logging.reopen_logs
|
90
|
+
end
|
91
|
+
when 'TTIN'
|
92
|
+
Thread.list.each do |thread|
|
93
|
+
Sidekiq.logger.warn "Thread TID-#{thread.object_id.to_s(36)} #{thread['label']}"
|
94
|
+
if thread.backtrace
|
95
|
+
Sidekiq.logger.warn thread.backtrace.join("\n")
|
96
|
+
else
|
97
|
+
Sidekiq.logger.warn "<no backtrace available>"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def Process.rss
|
104
|
+
`ps -o rss= -p #{Process.pid}`.chomp.to_i
|
105
|
+
end
|
106
|
+
|
107
|
+
iter = 10
|
108
|
+
count = 10_000
|
109
|
+
|
110
|
+
iter.times do
|
111
|
+
arr = Array.new(count) do
|
112
|
+
[]
|
113
|
+
end
|
114
|
+
count.times do |idx|
|
115
|
+
arr[idx][0] = idx
|
116
|
+
end
|
117
|
+
Sidekiq::Client.push_bulk('class' => LoadWorker, 'args' => arr)
|
118
|
+
end
|
119
|
+
Sidekiq.logger.error "Created #{count*iter} jobs"
|
120
|
+
|
121
|
+
Monitoring = Thread.new do
|
122
|
+
watchdog("monitor thread") do
|
123
|
+
while true
|
124
|
+
sleep 2
|
125
|
+
qsize, retries = Sidekiq.redis do |conn|
|
126
|
+
conn.pipelined do
|
127
|
+
conn.llen "queue:default"
|
128
|
+
conn.zcard "retry"
|
129
|
+
end
|
130
|
+
end.map(&:to_i)
|
131
|
+
total = qsize + retries
|
132
|
+
#GC.start
|
133
|
+
Sidekiq.logger.error("RSS: #{Process.rss} Pending: #{total}")
|
134
|
+
if total == 0
|
135
|
+
Sidekiq.logger.error("Done")
|
136
|
+
exit(0)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
begin
|
143
|
+
#RubyProf::exclude_threads = [ Monitoring ]
|
144
|
+
#RubyProf.start
|
145
|
+
fire_event(:startup)
|
146
|
+
Sidekiq.logger.error "Simulating 1ms of latency between Sidekiq and redis"
|
147
|
+
Toxiproxy[:redis].downstream(:latency, latency: 1).apply do
|
148
|
+
launcher = Sidekiq::Launcher.new(Sidekiq.options)
|
149
|
+
launcher.run
|
150
|
+
|
151
|
+
while readable_io = IO.select([self_read])
|
152
|
+
signal = readable_io.first[0].gets.strip
|
153
|
+
handle_signal(launcher, signal)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
rescue SystemExit => e
|
157
|
+
#Sidekiq.logger.error("Profiling...")
|
158
|
+
#result = RubyProf.stop
|
159
|
+
#printer = RubyProf::GraphHtmlPrinter.new(result)
|
160
|
+
#printer.print(File.new("output.html", "w"), :min_percent => 1)
|
161
|
+
# normal
|
162
|
+
rescue => e
|
163
|
+
raise e if $DEBUG
|
164
|
+
STDERR.puts e.message
|
165
|
+
STDERR.puts e.backtrace.join("\n")
|
166
|
+
exit 1
|
167
|
+
end
|
data/lib/sidekiq/api.rb
CHANGED
@@ -159,14 +159,15 @@ module Sidekiq
|
|
159
159
|
|
160
160
|
while i < @days_previous
|
161
161
|
date = @start_date - i
|
162
|
-
|
163
|
-
|
162
|
+
datestr = date.strftime("%Y-%m-%d".freeze)
|
163
|
+
keys << "stat:#{stat}:#{datestr}"
|
164
|
+
dates << datestr
|
164
165
|
i += 1
|
165
166
|
end
|
166
167
|
|
167
168
|
Sidekiq.redis do |conn|
|
168
169
|
conn.mget(keys).each_with_index do |value, idx|
|
169
|
-
stat_hash[dates[idx]
|
170
|
+
stat_hash[dates[idx]] = value ? value.to_i : 0
|
170
171
|
end
|
171
172
|
end
|
172
173
|
|
@@ -224,7 +225,7 @@ module Sidekiq
|
|
224
225
|
page = 0
|
225
226
|
page_size = 50
|
226
227
|
|
227
|
-
|
228
|
+
while true do
|
228
229
|
range_start = page * page_size - deleted_size
|
229
230
|
range_end = page * page_size - deleted_size + (page_size - 1)
|
230
231
|
entries = Sidekiq.redis do |conn|
|
@@ -262,7 +263,6 @@ module Sidekiq
|
|
262
263
|
# removed from the queue via Job#delete.
|
263
264
|
#
|
264
265
|
class Job
|
265
|
-
KNOWN_WRAPPERS = [/\ASidekiq::Extensions::Delayed/, "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper"]
|
266
266
|
attr_reader :item
|
267
267
|
|
268
268
|
def initialize(item, queue_name=nil)
|
@@ -312,7 +312,7 @@ module Sidekiq
|
|
312
312
|
end
|
313
313
|
|
314
314
|
def enqueued_at
|
315
|
-
Time.at(@item['enqueued_at']
|
315
|
+
@item['enqueued_at'] ? Time.at(@item['enqueued_at']).utc : nil
|
316
316
|
end
|
317
317
|
|
318
318
|
def created_at
|
@@ -369,11 +369,15 @@ module Sidekiq
|
|
369
369
|
end
|
370
370
|
|
371
371
|
def delete
|
372
|
-
@
|
372
|
+
if @value
|
373
|
+
@parent.delete_by_value(@parent.name, @value)
|
374
|
+
else
|
375
|
+
@parent.delete_by_jid(score, jid)
|
376
|
+
end
|
373
377
|
end
|
374
378
|
|
375
379
|
def reschedule(at)
|
376
|
-
|
380
|
+
delete
|
377
381
|
@parent.schedule(at, item)
|
378
382
|
end
|
379
383
|
|
@@ -484,7 +488,7 @@ module Sidekiq
|
|
484
488
|
page = -1
|
485
489
|
page_size = 50
|
486
490
|
|
487
|
-
|
491
|
+
while true do
|
488
492
|
range_start = page * page_size + offset_size
|
489
493
|
range_end = page * page_size + offset_size + (page_size - 1)
|
490
494
|
elements = Sidekiq.redis do |conn|
|
@@ -519,36 +523,30 @@ module Sidekiq
|
|
519
523
|
self.detect { |j| j.jid == jid }
|
520
524
|
end
|
521
525
|
|
522
|
-
def
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
526
|
+
def delete_by_value(name, value)
|
527
|
+
Sidekiq.redis do |conn|
|
528
|
+
ret = conn.zrem(name, value)
|
529
|
+
@_size -= 1 if ret
|
530
|
+
ret
|
531
|
+
end
|
532
|
+
end
|
527
533
|
|
528
|
-
|
534
|
+
def delete_by_jid(score, jid)
|
535
|
+
Sidekiq.redis do |conn|
|
536
|
+
elements = conn.zrangebyscore(name, score, score)
|
537
|
+
elements.each do |element|
|
529
538
|
message = Sidekiq.load_json(element)
|
530
|
-
|
531
539
|
if message["jid"] == jid
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
conn.zcard name
|
536
|
-
end
|
537
|
-
end
|
538
|
-
end
|
539
|
-
end
|
540
|
-
elements_with_jid.count != 0
|
541
|
-
else
|
542
|
-
count, @_size = Sidekiq.redis do |conn|
|
543
|
-
conn.multi do
|
544
|
-
conn.zremrangebyscore(name, score, score)
|
545
|
-
conn.zcard name
|
540
|
+
ret = conn.zrem(name, element)
|
541
|
+
@_size -= 1 if ret
|
542
|
+
break ret
|
546
543
|
end
|
544
|
+
false
|
547
545
|
end
|
548
|
-
count != 0
|
549
546
|
end
|
550
547
|
end
|
551
548
|
|
549
|
+
alias_method :delete, :delete_by_jid
|
552
550
|
end
|
553
551
|
|
554
552
|
##
|
data/lib/sidekiq/cli.rb
CHANGED
@@ -11,18 +11,18 @@ require 'sidekiq'
|
|
11
11
|
require 'sidekiq/util'
|
12
12
|
|
13
13
|
module Sidekiq
|
14
|
-
# We are shutting down Sidekiq but what about workers that
|
15
|
-
# are working on some long job? This error is
|
16
|
-
# raised in workers that have not finished within the hard
|
17
|
-
# timeout limit. This is needed to rollback db transactions,
|
18
|
-
# otherwise Ruby's Thread#kill will commit. See #377.
|
19
|
-
# DO NOT RESCUE THIS ERROR.
|
20
|
-
class Shutdown < Interrupt; end
|
21
|
-
|
22
14
|
class CLI
|
23
15
|
include Util
|
24
16
|
include Singleton unless $TESTING
|
25
17
|
|
18
|
+
PROCTITLES = [
|
19
|
+
proc { 'sidekiq'.freeze },
|
20
|
+
proc { Sidekiq::VERSION },
|
21
|
+
proc { |me, data| data['tag'] },
|
22
|
+
proc { |me, data| "[#{Processor::WORKER_STATE.size} of #{data['concurrency']} busy]" },
|
23
|
+
proc { |me, data| "stopping" if me.stopping? },
|
24
|
+
]
|
25
|
+
|
26
26
|
# Used for CLI testing
|
27
27
|
attr_accessor :code
|
28
28
|
attr_accessor :launcher
|
@@ -40,7 +40,6 @@ module Sidekiq
|
|
40
40
|
validate!
|
41
41
|
daemonize
|
42
42
|
write_pid
|
43
|
-
load_celluloid
|
44
43
|
end
|
45
44
|
|
46
45
|
# Code within this method is not tested because it alters
|
@@ -64,15 +63,23 @@ module Sidekiq
|
|
64
63
|
|
65
64
|
logger.info "Running in #{RUBY_DESCRIPTION}"
|
66
65
|
logger.info Sidekiq::LICENSE
|
67
|
-
logger.info "Upgrade to Sidekiq Pro for more features and support: http://sidekiq.org
|
68
|
-
|
69
|
-
fire_event(:startup)
|
66
|
+
logger.info "Upgrade to Sidekiq Pro for more features and support: http://sidekiq.org" unless defined?(::Sidekiq::Pro)
|
70
67
|
|
71
68
|
Sidekiq.redis do |conn|
|
72
69
|
# touch the connection pool so it is created before we
|
73
|
-
#
|
70
|
+
# fire startup and start multithreading.
|
71
|
+
ver = conn.info['redis_version']
|
72
|
+
raise "You are using Redis v#{ver}, Sidekiq requires Redis v2.8.0 or greater" if ver < '2.8'
|
74
73
|
end
|
75
74
|
|
75
|
+
# Before this point, the process is initializing with just the main thread.
|
76
|
+
# Starting here the process will now have multiple threads running.
|
77
|
+
fire_event(:startup)
|
78
|
+
|
79
|
+
logger.debug {
|
80
|
+
"Middleware: #{Sidekiq.server_middleware.map(&:klass).join(', ')}"
|
81
|
+
}
|
82
|
+
|
76
83
|
if !options[:daemon]
|
77
84
|
logger.info 'Starting processing, hit Ctrl-C to stop'
|
78
85
|
end
|
@@ -90,26 +97,28 @@ module Sidekiq
|
|
90
97
|
rescue Interrupt
|
91
98
|
logger.info 'Shutting down'
|
92
99
|
launcher.stop
|
93
|
-
fire_event(:shutdown, true)
|
94
100
|
# Explicitly exit so busy Processor threads can't block
|
95
101
|
# process shutdown.
|
102
|
+
logger.info "Bye!"
|
96
103
|
exit(0)
|
97
104
|
end
|
98
105
|
end
|
99
106
|
|
100
107
|
def self.banner
|
101
|
-
%q{
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
108
|
+
%q{
|
109
|
+
m,
|
110
|
+
`$b
|
111
|
+
.ss, $$: .,d$
|
112
|
+
`$$P,d$P' .,md$P"'
|
113
|
+
,$$$$$bmmd$$$P^'
|
114
|
+
.d$$$$$$$$$$P'
|
115
|
+
$$^' `"^$$$' ____ _ _ _ _
|
116
|
+
$: ,$$: / ___|(_) __| | ___| | _(_) __ _
|
117
|
+
`b :$$ \___ \| |/ _` |/ _ \ |/ / |/ _` |
|
118
|
+
$$: ___) | | (_| | __/ <| | (_| |
|
119
|
+
$$ |____/|_|\__,_|\___|_|\_\_|\__, |
|
120
|
+
.d$$ |_|
|
121
|
+
}
|
113
122
|
end
|
114
123
|
|
115
124
|
def handle_signal(sig)
|
@@ -124,8 +133,7 @@ module Sidekiq
|
|
124
133
|
raise Interrupt
|
125
134
|
when 'USR1'
|
126
135
|
Sidekiq.logger.info "Received USR1, no longer accepting new work"
|
127
|
-
launcher.
|
128
|
-
fire_event(:quiet, true)
|
136
|
+
launcher.quiet
|
129
137
|
when 'USR2'
|
130
138
|
if Sidekiq.options[:logfile]
|
131
139
|
Sidekiq.logger.info "Received USR2, reopening log file"
|
@@ -154,19 +162,6 @@ module Sidekiq
|
|
154
162
|
end
|
155
163
|
end
|
156
164
|
|
157
|
-
def load_celluloid
|
158
|
-
raise "Celluloid cannot be required until here, or it will break Sidekiq's daemonization" if defined?(::Celluloid) && options[:daemon]
|
159
|
-
|
160
|
-
# Celluloid can't be loaded until after we've daemonized
|
161
|
-
# because it spins up threads and creates locks which get
|
162
|
-
# into a very bad state if forked.
|
163
|
-
require 'celluloid/autostart'
|
164
|
-
Celluloid.logger = (options[:verbose] ? Sidekiq.logger : nil)
|
165
|
-
|
166
|
-
require 'sidekiq/manager'
|
167
|
-
require 'sidekiq/scheduled'
|
168
|
-
end
|
169
|
-
|
170
165
|
def daemonize
|
171
166
|
return unless options[:daemon]
|
172
167
|
|
@@ -340,7 +335,11 @@ module Sidekiq
|
|
340
335
|
die 1
|
341
336
|
end
|
342
337
|
@parser.parse!(argv)
|
343
|
-
|
338
|
+
|
339
|
+
%w[config/sidekiq.yml config/sidekiq.yml.erb].each do |filename|
|
340
|
+
opts[:config_file] ||= filename if File.exist?(filename)
|
341
|
+
end
|
342
|
+
|
344
343
|
opts
|
345
344
|
end
|
346
345
|
|
data/lib/sidekiq/client.rb
CHANGED
@@ -119,16 +119,12 @@ module Sidekiq
|
|
119
119
|
|
120
120
|
class << self
|
121
121
|
|
122
|
-
def default
|
123
|
-
@default ||= new
|
124
|
-
end
|
125
|
-
|
126
122
|
def push(item)
|
127
|
-
|
123
|
+
new.push(item)
|
128
124
|
end
|
129
125
|
|
130
126
|
def push_bulk(items)
|
131
|
-
|
127
|
+
new.push_bulk(items)
|
132
128
|
end
|
133
129
|
|
134
130
|
# Resque compatibility helpers. Note all helpers
|
@@ -210,10 +206,9 @@ module Sidekiq
|
|
210
206
|
end
|
211
207
|
|
212
208
|
def normalize_item(item)
|
213
|
-
raise(ArgumentError, "
|
214
|
-
raise(ArgumentError, "
|
215
|
-
raise(ArgumentError, "
|
216
|
-
raise(ArgumentError, "Message class must be either a Class or String representation of the class name") unless item['class'].is_a?(Class) || item['class'].is_a?(String)
|
209
|
+
raise(ArgumentError, "Job must be a Hash with 'class' and 'args' keys: { 'class' => SomeWorker, 'args' => ['bob', 1, :foo => 'bar'] }") unless item.is_a?(Hash) && item.has_key?('class'.freeze) && item.has_key?('args'.freeze)
|
210
|
+
raise(ArgumentError, "Job args must be an Array") unless item['args'].is_a?(Array)
|
211
|
+
raise(ArgumentError, "Job class must be either a Class or String representation of the class name") unless item['class'.freeze].is_a?(Class) || item['class'.freeze].is_a?(String)
|
217
212
|
|
218
213
|
normalized_hash(item['class'.freeze])
|
219
214
|
.each{ |key, value| item[key] = value if item[key].nil? }
|