sidekiq 3.5.4 → 7.2.0
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 +5 -5
- data/Changes.md +992 -6
- data/LICENSE.txt +9 -0
- data/README.md +52 -43
- data/bin/sidekiq +22 -4
- data/bin/sidekiqload +209 -115
- data/bin/sidekiqmon +11 -0
- data/lib/generators/sidekiq/job_generator.rb +57 -0
- data/lib/generators/sidekiq/templates/{worker.rb.erb → job.rb.erb} +2 -2
- data/lib/generators/sidekiq/templates/job_spec.rb.erb +6 -0
- data/lib/generators/sidekiq/templates/job_test.rb.erb +8 -0
- data/lib/sidekiq/api.rb +633 -295
- data/lib/sidekiq/capsule.rb +127 -0
- data/lib/sidekiq/cli.rb +270 -248
- data/lib/sidekiq/client.rb +139 -108
- data/lib/sidekiq/component.rb +68 -0
- data/lib/sidekiq/config.rb +287 -0
- data/lib/sidekiq/deploy.rb +62 -0
- data/lib/sidekiq/embedded.rb +61 -0
- data/lib/sidekiq/fetch.rb +53 -121
- data/lib/sidekiq/job.rb +374 -0
- data/lib/sidekiq/job_logger.rb +51 -0
- data/lib/sidekiq/job_retry.rb +301 -0
- data/lib/sidekiq/job_util.rb +107 -0
- data/lib/sidekiq/launcher.rb +241 -69
- data/lib/sidekiq/logger.rb +131 -0
- data/lib/sidekiq/manager.rb +88 -190
- data/lib/sidekiq/metrics/query.rb +155 -0
- data/lib/sidekiq/metrics/shared.rb +95 -0
- data/lib/sidekiq/metrics/tracking.rb +136 -0
- data/lib/sidekiq/middleware/chain.rb +114 -56
- data/lib/sidekiq/middleware/current_attributes.rb +95 -0
- data/lib/sidekiq/middleware/i18n.rb +8 -7
- data/lib/sidekiq/middleware/modules.rb +21 -0
- data/lib/sidekiq/monitor.rb +146 -0
- data/lib/sidekiq/paginator.rb +29 -16
- data/lib/sidekiq/processor.rb +238 -118
- data/lib/sidekiq/rails.rb +57 -27
- data/lib/sidekiq/redis_client_adapter.rb +111 -0
- data/lib/sidekiq/redis_connection.rb +49 -50
- data/lib/sidekiq/ring_buffer.rb +29 -0
- data/lib/sidekiq/scheduled.rb +173 -52
- data/lib/sidekiq/sd_notify.rb +149 -0
- data/lib/sidekiq/systemd.rb +24 -0
- data/lib/sidekiq/testing/inline.rb +7 -5
- data/lib/sidekiq/testing.rb +197 -65
- data/lib/sidekiq/transaction_aware_client.rb +44 -0
- data/lib/sidekiq/version.rb +4 -1
- data/lib/sidekiq/web/action.rb +93 -0
- data/lib/sidekiq/web/application.rb +463 -0
- data/lib/sidekiq/web/csrf_protection.rb +180 -0
- data/lib/sidekiq/web/helpers.rb +364 -0
- data/lib/sidekiq/web/router.rb +104 -0
- data/lib/sidekiq/web.rb +113 -216
- data/lib/sidekiq/worker_compatibility_alias.rb +13 -0
- data/lib/sidekiq.rb +99 -142
- data/sidekiq.gemspec +26 -23
- data/web/assets/images/apple-touch-icon.png +0 -0
- data/web/assets/javascripts/application.js +163 -74
- data/web/assets/javascripts/base-charts.js +106 -0
- data/web/assets/javascripts/chart.min.js +13 -0
- data/web/assets/javascripts/chartjs-plugin-annotation.min.js +7 -0
- data/web/assets/javascripts/dashboard-charts.js +182 -0
- data/web/assets/javascripts/dashboard.js +37 -280
- data/web/assets/javascripts/metrics.js +298 -0
- data/web/assets/stylesheets/application-dark.css +147 -0
- data/web/assets/stylesheets/application-rtl.css +153 -0
- data/web/assets/stylesheets/application.css +181 -198
- data/web/assets/stylesheets/bootstrap-rtl.min.css +9 -0
- data/web/assets/stylesheets/bootstrap.css +4 -8
- data/web/locales/ar.yml +87 -0
- data/web/locales/cs.yml +62 -52
- data/web/locales/da.yml +60 -53
- data/web/locales/de.yml +65 -53
- data/web/locales/el.yml +43 -24
- data/web/locales/en.yml +86 -62
- data/web/locales/es.yml +70 -53
- data/web/locales/fa.yml +80 -0
- data/web/locales/fr.yml +86 -56
- data/web/locales/gd.yml +99 -0
- data/web/locales/he.yml +80 -0
- data/web/locales/hi.yml +59 -59
- data/web/locales/it.yml +53 -53
- data/web/locales/ja.yml +78 -56
- data/web/locales/ko.yml +52 -52
- data/web/locales/lt.yml +83 -0
- data/web/locales/nb.yml +61 -61
- data/web/locales/nl.yml +52 -52
- data/web/locales/pl.yml +45 -45
- data/web/locales/pt-br.yml +83 -55
- data/web/locales/pt.yml +51 -51
- data/web/locales/ru.yml +68 -60
- data/web/locales/sv.yml +53 -53
- data/web/locales/ta.yml +60 -60
- data/web/locales/uk.yml +62 -61
- data/web/locales/ur.yml +80 -0
- data/web/locales/vi.yml +83 -0
- data/web/locales/zh-cn.yml +43 -16
- data/web/locales/zh-tw.yml +42 -8
- data/web/views/_footer.erb +10 -9
- data/web/views/_job_info.erb +26 -5
- data/web/views/_metrics_period_select.erb +12 -0
- data/web/views/_nav.erb +6 -20
- data/web/views/_paging.erb +3 -1
- data/web/views/_poll_link.erb +3 -6
- data/web/views/_summary.erb +7 -7
- data/web/views/busy.erb +87 -28
- data/web/views/dashboard.erb +51 -21
- data/web/views/dead.erb +4 -4
- data/web/views/filtering.erb +7 -0
- data/web/views/layout.erb +15 -5
- data/web/views/metrics.erb +91 -0
- data/web/views/metrics_for_job.erb +59 -0
- data/web/views/morgue.erb +25 -22
- data/web/views/queue.erb +35 -25
- data/web/views/queues.erb +23 -7
- data/web/views/retries.erb +28 -23
- data/web/views/retry.erb +5 -5
- data/web/views/scheduled.erb +19 -17
- data/web/views/scheduled_job_info.erb +1 -1
- metadata +86 -268
- data/.gitignore +0 -12
- data/.travis.yml +0 -16
- data/3.0-Upgrade.md +0 -70
- data/COMM-LICENSE +0 -95
- data/Contributing.md +0 -32
- data/Ent-Changes.md +0 -39
- data/Gemfile +0 -27
- data/LICENSE +0 -9
- data/Pro-2.0-Upgrade.md +0 -138
- data/Pro-Changes.md +0 -454
- data/Rakefile +0 -9
- data/bin/sidekiqctl +0 -93
- data/lib/generators/sidekiq/templates/worker_spec.rb.erb +0 -6
- data/lib/generators/sidekiq/templates/worker_test.rb.erb +0 -8
- data/lib/generators/sidekiq/worker_generator.rb +0 -49
- data/lib/sidekiq/actor.rb +0 -39
- data/lib/sidekiq/core_ext.rb +0 -105
- data/lib/sidekiq/exception_handler.rb +0 -30
- data/lib/sidekiq/extensions/action_mailer.rb +0 -56
- data/lib/sidekiq/extensions/active_record.rb +0 -39
- data/lib/sidekiq/extensions/class_methods.rb +0 -39
- data/lib/sidekiq/extensions/generic_proxy.rb +0 -24
- data/lib/sidekiq/logging.rb +0 -104
- data/lib/sidekiq/middleware/server/active_record.rb +0 -13
- data/lib/sidekiq/middleware/server/logging.rb +0 -40
- data/lib/sidekiq/middleware/server/retry_jobs.rb +0 -206
- data/lib/sidekiq/util.rb +0 -68
- data/lib/sidekiq/web_helpers.rb +0 -249
- data/lib/sidekiq/worker.rb +0 -103
- data/test/config.yml +0 -9
- data/test/env_based_config.yml +0 -11
- data/test/fake_env.rb +0 -0
- data/test/fixtures/en.yml +0 -2
- data/test/helper.rb +0 -49
- data/test/test_api.rb +0 -493
- data/test/test_cli.rb +0 -335
- data/test/test_client.rb +0 -194
- data/test/test_exception_handler.rb +0 -55
- data/test/test_extensions.rb +0 -126
- data/test/test_fetch.rb +0 -104
- data/test/test_logging.rb +0 -34
- data/test/test_manager.rb +0 -168
- data/test/test_middleware.rb +0 -159
- data/test/test_processor.rb +0 -237
- data/test/test_rails.rb +0 -21
- data/test/test_redis_connection.rb +0 -126
- data/test/test_retry.rb +0 -325
- data/test/test_scheduled.rb +0 -114
- data/test/test_scheduling.rb +0 -49
- data/test/test_sidekiq.rb +0 -99
- data/test/test_testing.rb +0 -142
- data/test/test_testing_fake.rb +0 -268
- data/test/test_testing_inline.rb +0 -93
- data/test/test_util.rb +0 -16
- data/test/test_web.rb +0 -608
- data/test/test_web_helpers.rb +0 -53
- data/web/assets/images/bootstrap/glyphicons-halflings-white.png +0 -0
- data/web/assets/images/bootstrap/glyphicons-halflings.png +0 -0
- data/web/assets/images/status/active.png +0 -0
- data/web/assets/images/status/idle.png +0 -0
- data/web/assets/javascripts/locales/README.md +0 -27
- data/web/assets/javascripts/locales/jquery.timeago.ar.js +0 -96
- data/web/assets/javascripts/locales/jquery.timeago.bg.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.bs.js +0 -49
- data/web/assets/javascripts/locales/jquery.timeago.ca.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.cs.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.cy.js +0 -20
- data/web/assets/javascripts/locales/jquery.timeago.da.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.de.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.el.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.en-short.js +0 -20
- data/web/assets/javascripts/locales/jquery.timeago.en.js +0 -20
- data/web/assets/javascripts/locales/jquery.timeago.es.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.et.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.fa.js +0 -22
- data/web/assets/javascripts/locales/jquery.timeago.fi.js +0 -28
- data/web/assets/javascripts/locales/jquery.timeago.fr-short.js +0 -16
- data/web/assets/javascripts/locales/jquery.timeago.fr.js +0 -17
- data/web/assets/javascripts/locales/jquery.timeago.he.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.hr.js +0 -49
- data/web/assets/javascripts/locales/jquery.timeago.hu.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.hy.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.id.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.it.js +0 -16
- data/web/assets/javascripts/locales/jquery.timeago.ja.js +0 -19
- data/web/assets/javascripts/locales/jquery.timeago.ko.js +0 -17
- data/web/assets/javascripts/locales/jquery.timeago.lt.js +0 -20
- data/web/assets/javascripts/locales/jquery.timeago.mk.js +0 -20
- data/web/assets/javascripts/locales/jquery.timeago.nl.js +0 -20
- data/web/assets/javascripts/locales/jquery.timeago.no.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.pl.js +0 -31
- data/web/assets/javascripts/locales/jquery.timeago.pt-br.js +0 -16
- data/web/assets/javascripts/locales/jquery.timeago.pt.js +0 -16
- data/web/assets/javascripts/locales/jquery.timeago.ro.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.rs.js +0 -49
- data/web/assets/javascripts/locales/jquery.timeago.ru.js +0 -34
- data/web/assets/javascripts/locales/jquery.timeago.sk.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.sl.js +0 -44
- data/web/assets/javascripts/locales/jquery.timeago.sv.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.th.js +0 -20
- data/web/assets/javascripts/locales/jquery.timeago.tr.js +0 -16
- data/web/assets/javascripts/locales/jquery.timeago.uk.js +0 -34
- data/web/assets/javascripts/locales/jquery.timeago.uz.js +0 -19
- data/web/assets/javascripts/locales/jquery.timeago.zh-cn.js +0 -20
- data/web/assets/javascripts/locales/jquery.timeago.zh-tw.js +0 -20
- data/web/views/_poll_js.erb +0 -5
- /data/web/assets/images/{status-sd8051fd480.png → status.png} +0 -0
data/lib/sidekiq/cli.rb
CHANGED
|
@@ -1,261 +1,318 @@
|
|
|
1
|
-
#
|
|
2
|
-
$stdout.sync = true
|
|
1
|
+
# frozen_string_literal: true
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
require 'singleton'
|
|
6
|
-
require 'optparse'
|
|
7
|
-
require 'erb'
|
|
8
|
-
require 'fileutils'
|
|
3
|
+
$stdout.sync = true
|
|
9
4
|
|
|
10
|
-
require
|
|
11
|
-
require
|
|
5
|
+
require "yaml"
|
|
6
|
+
require "singleton"
|
|
7
|
+
require "optparse"
|
|
8
|
+
require "erb"
|
|
9
|
+
require "fileutils"
|
|
12
10
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
# otherwise Ruby's Thread#kill will commit. See #377.
|
|
19
|
-
# DO NOT RESCUE THIS ERROR.
|
|
20
|
-
class Shutdown < Interrupt; end
|
|
11
|
+
require "sidekiq"
|
|
12
|
+
require "sidekiq/config"
|
|
13
|
+
require "sidekiq/component"
|
|
14
|
+
require "sidekiq/capsule"
|
|
15
|
+
require "sidekiq/launcher"
|
|
21
16
|
|
|
17
|
+
module Sidekiq # :nodoc:
|
|
22
18
|
class CLI
|
|
23
|
-
include
|
|
19
|
+
include Sidekiq::Component
|
|
24
20
|
include Singleton unless $TESTING
|
|
25
21
|
|
|
26
|
-
# Used for CLI testing
|
|
27
|
-
attr_accessor :code
|
|
28
22
|
attr_accessor :launcher
|
|
29
23
|
attr_accessor :environment
|
|
24
|
+
attr_accessor :config
|
|
30
25
|
|
|
31
|
-
def
|
|
32
|
-
@
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def parse(args=ARGV)
|
|
36
|
-
@code = nil
|
|
26
|
+
def parse(args = ARGV.dup)
|
|
27
|
+
@config ||= Sidekiq.default_configuration
|
|
37
28
|
|
|
38
29
|
setup_options(args)
|
|
39
30
|
initialize_logger
|
|
40
31
|
validate!
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def jruby?
|
|
35
|
+
defined?(::JRUBY_VERSION)
|
|
44
36
|
end
|
|
45
37
|
|
|
46
38
|
# Code within this method is not tested because it alters
|
|
47
39
|
# global process state irreversibly. PRs which improve the
|
|
48
40
|
# test coverage of Sidekiq::CLI are welcomed.
|
|
49
|
-
def run
|
|
50
|
-
|
|
51
|
-
print_banner
|
|
41
|
+
def run(boot_app: true)
|
|
42
|
+
boot_application if boot_app
|
|
52
43
|
|
|
53
|
-
|
|
44
|
+
if environment == "development" && $stdout.tty? && @config.logger.formatter.is_a?(Sidekiq::Logger::Formatters::Pretty)
|
|
45
|
+
print_banner
|
|
46
|
+
end
|
|
47
|
+
logger.info "Booted Rails #{::Rails.version} application in #{environment} environment" if rails_app?
|
|
54
48
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
49
|
+
self_read, self_write = IO.pipe
|
|
50
|
+
sigs = %w[INT TERM TTIN TSTP]
|
|
51
|
+
# USR1 and USR2 don't work on the JVM
|
|
52
|
+
sigs << "USR2" if Sidekiq.pro? && !jruby?
|
|
53
|
+
sigs.each do |sig|
|
|
54
|
+
old_handler = Signal.trap(sig) do
|
|
55
|
+
if old_handler.respond_to?(:call)
|
|
56
|
+
begin
|
|
57
|
+
old_handler.call
|
|
58
|
+
rescue Exception => exc
|
|
59
|
+
# signal handlers can't use Logger so puts only
|
|
60
|
+
puts ["Error in #{sig} handler", exc].inspect
|
|
61
|
+
end
|
|
59
62
|
end
|
|
60
|
-
|
|
61
|
-
puts "Signal #{sig} not supported"
|
|
63
|
+
self_write.puts(sig)
|
|
62
64
|
end
|
|
65
|
+
rescue ArgumentError
|
|
66
|
+
puts "Signal #{sig} not supported"
|
|
63
67
|
end
|
|
64
68
|
|
|
65
69
|
logger.info "Running in #{RUBY_DESCRIPTION}"
|
|
66
70
|
logger.info Sidekiq::LICENSE
|
|
67
|
-
logger.info "Upgrade to Sidekiq Pro for more features and support:
|
|
71
|
+
logger.info "Upgrade to Sidekiq Pro for more features and support: https://sidekiq.org" unless defined?(::Sidekiq::Pro)
|
|
68
72
|
|
|
69
|
-
|
|
73
|
+
# touch the connection pool so it is created before we
|
|
74
|
+
# fire startup and start multithreading.
|
|
75
|
+
info = @config.redis_info
|
|
76
|
+
ver = Gem::Version.new(info["redis_version"])
|
|
77
|
+
raise "You are connecting to Redis #{ver}, Sidekiq requires Redis 6.2.0 or greater" if ver < Gem::Version.new("6.2.0")
|
|
70
78
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
79
|
+
maxmemory_policy = info["maxmemory_policy"]
|
|
80
|
+
if maxmemory_policy != "noeviction" && maxmemory_policy != ""
|
|
81
|
+
# Redis Enterprise Cloud returns "" for their policy 😳
|
|
82
|
+
logger.warn <<~EOM
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
WARNING: Your Redis instance will evict Sidekiq data under heavy load.
|
|
86
|
+
The 'noeviction' maxmemory policy is recommended (current policy: '#{maxmemory_policy}').
|
|
87
|
+
See: https://github.com/sidekiq/sidekiq/wiki/Using-Redis#memory
|
|
88
|
+
|
|
89
|
+
EOM
|
|
90
|
+
end
|
|
74
91
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
92
|
+
# Since the user can pass us a connection pool explicitly in the initializer, we
|
|
93
|
+
# need to verify the size is large enough or else Sidekiq's performance is dramatically slowed.
|
|
94
|
+
@config.capsules.each_pair do |name, cap|
|
|
95
|
+
raise ArgumentError, "Pool size too small for #{name}" if cap.redis_pool.size < cap.concurrency
|
|
78
96
|
end
|
|
79
97
|
|
|
80
|
-
|
|
81
|
-
|
|
98
|
+
# cache process identity
|
|
99
|
+
@config[:identity] = identity
|
|
100
|
+
|
|
101
|
+
# Touch middleware so it isn't lazy loaded by multiple threads, #3043
|
|
102
|
+
@config.server_middleware
|
|
103
|
+
|
|
104
|
+
# Before this point, the process is initializing with just the main thread.
|
|
105
|
+
# Starting here the process will now have multiple threads running.
|
|
106
|
+
fire_event(:startup, reverse: false, reraise: true)
|
|
107
|
+
|
|
108
|
+
logger.debug { "Client Middleware: #{@config.default_capsule.client_middleware.map(&:klass).join(", ")}" }
|
|
109
|
+
logger.debug { "Server Middleware: #{@config.default_capsule.server_middleware.map(&:klass).join(", ")}" }
|
|
110
|
+
|
|
111
|
+
launch(self_read)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def launch(self_read)
|
|
115
|
+
if environment == "development" && $stdout.tty?
|
|
116
|
+
logger.info "Starting processing, hit Ctrl-C to stop"
|
|
82
117
|
end
|
|
83
118
|
|
|
84
|
-
|
|
85
|
-
@launcher = Sidekiq::Launcher.new(options)
|
|
119
|
+
@launcher = Sidekiq::Launcher.new(@config)
|
|
86
120
|
|
|
87
121
|
begin
|
|
88
122
|
launcher.run
|
|
89
123
|
|
|
90
|
-
while
|
|
91
|
-
signal =
|
|
124
|
+
while self_read.wait_readable
|
|
125
|
+
signal = self_read.gets.strip
|
|
92
126
|
handle_signal(signal)
|
|
93
127
|
end
|
|
94
128
|
rescue Interrupt
|
|
95
|
-
logger.info
|
|
129
|
+
logger.info "Shutting down"
|
|
96
130
|
launcher.stop
|
|
97
|
-
|
|
98
|
-
|
|
131
|
+
logger.info "Bye!"
|
|
132
|
+
|
|
133
|
+
# Explicitly exit so busy Processor threads won't block process shutdown.
|
|
134
|
+
#
|
|
135
|
+
# NB: slow at_exit handlers will prevent a timely exit if they take
|
|
136
|
+
# a while to run. If Sidekiq is getting here but the process isn't exiting,
|
|
137
|
+
# use the TTIN signal to determine where things are stuck.
|
|
99
138
|
exit(0)
|
|
100
139
|
end
|
|
101
140
|
end
|
|
102
141
|
|
|
142
|
+
HOLIDAY_COLORS = {
|
|
143
|
+
# got other color-specific holidays from around the world?
|
|
144
|
+
# https://developer-book.com/post/definitive-guide-for-colored-text-in-terminal/#256-color-escape-codes
|
|
145
|
+
"3-17" => "\e[1;32m", # St. Patrick's Day green
|
|
146
|
+
"10-31" => "\e[38;5;208m" # Halloween orange
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
def self.day
|
|
150
|
+
@@day ||= begin
|
|
151
|
+
t = Date.today
|
|
152
|
+
"#{t.month}-#{t.day}"
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def self.r
|
|
157
|
+
@@r ||= HOLIDAY_COLORS[day] || "\e[1;31m"
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def self.b
|
|
161
|
+
@@b ||= HOLIDAY_COLORS[day] || "\e[30m"
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def self.w
|
|
165
|
+
"\e[1;37m"
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def self.reset
|
|
169
|
+
@@b = @@r = @@day = nil
|
|
170
|
+
"\e[0m"
|
|
171
|
+
end
|
|
172
|
+
|
|
103
173
|
def self.banner
|
|
104
|
-
%
|
|
105
|
-
m,
|
|
106
|
-
`$b
|
|
107
|
-
.ss, $$: .,d$
|
|
108
|
-
`$$P,d$P' .,md$P"'
|
|
109
|
-
,$$$$$
|
|
110
|
-
.d
|
|
111
|
-
$$^' `"
|
|
112
|
-
$:
|
|
113
|
-
`b :$$
|
|
114
|
-
$$:
|
|
115
|
-
$$ |____/|_
|
|
116
|
-
.d$$
|
|
117
|
-
}
|
|
174
|
+
%{
|
|
175
|
+
#{w} m,
|
|
176
|
+
#{w} `$b
|
|
177
|
+
#{w} .ss, $$: .,d$
|
|
178
|
+
#{w} `$$P,d$P' .,md$P"'
|
|
179
|
+
#{w} ,$$$$$b#{b}/#{w}md$$$P^'
|
|
180
|
+
#{w} .d$$$$$$#{b}/#{w}$$$P'
|
|
181
|
+
#{w} $$^' `"#{b}/#{w}$$$' #{r}____ _ _ _ _
|
|
182
|
+
#{w} $: #{b}'#{w},$$: #{r} / ___|(_) __| | ___| | _(_) __ _
|
|
183
|
+
#{w} `b :$$ #{r} \\___ \\| |/ _` |/ _ \\ |/ / |/ _` |
|
|
184
|
+
#{w} $$: #{r} ___) | | (_| | __/ <| | (_| |
|
|
185
|
+
#{w} $$ #{r}|____/|_|\\__,_|\\___|_|\\_\\_|\\__, |
|
|
186
|
+
#{w} .d$$ #{r} |_|
|
|
187
|
+
#{reset}}
|
|
118
188
|
end
|
|
119
189
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
Sidekiq.logger.info "Received USR1, no longer accepting new work"
|
|
132
|
-
launcher.manager.async.stop
|
|
133
|
-
fire_event(:quiet, true)
|
|
134
|
-
when 'USR2'
|
|
135
|
-
if Sidekiq.options[:logfile]
|
|
136
|
-
Sidekiq.logger.info "Received USR2, reopening log file"
|
|
137
|
-
Sidekiq::Logging.reopen_logs
|
|
138
|
-
end
|
|
139
|
-
when 'TTIN'
|
|
190
|
+
SIGNAL_HANDLERS = {
|
|
191
|
+
# Ctrl-C in terminal
|
|
192
|
+
"INT" => ->(cli) { raise Interrupt },
|
|
193
|
+
# TERM is the signal that Sidekiq must exit.
|
|
194
|
+
# Heroku sends TERM and then waits 30 seconds for process to exit.
|
|
195
|
+
"TERM" => ->(cli) { raise Interrupt },
|
|
196
|
+
"TSTP" => ->(cli) {
|
|
197
|
+
cli.logger.info "Received TSTP, no longer accepting new work"
|
|
198
|
+
cli.launcher.quiet
|
|
199
|
+
},
|
|
200
|
+
"TTIN" => ->(cli) {
|
|
140
201
|
Thread.list.each do |thread|
|
|
141
|
-
|
|
202
|
+
cli.logger.warn "Thread TID-#{(thread.object_id ^ ::Process.pid).to_s(36)} #{thread.name}"
|
|
142
203
|
if thread.backtrace
|
|
143
|
-
|
|
204
|
+
cli.logger.warn thread.backtrace.join("\n")
|
|
144
205
|
else
|
|
145
|
-
|
|
206
|
+
cli.logger.warn "<no backtrace available>"
|
|
146
207
|
end
|
|
147
208
|
end
|
|
148
|
-
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
UNHANDLED_SIGNAL_HANDLER = ->(cli) { cli.logger.info "No signal handler registered, ignoring" }
|
|
212
|
+
SIGNAL_HANDLERS.default = UNHANDLED_SIGNAL_HANDLER
|
|
213
|
+
|
|
214
|
+
def handle_signal(sig)
|
|
215
|
+
logger.debug "Got #{sig} signal"
|
|
216
|
+
SIGNAL_HANDLERS[sig].call(self)
|
|
149
217
|
end
|
|
150
218
|
|
|
151
219
|
private
|
|
152
220
|
|
|
153
221
|
def print_banner
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
puts Sidekiq::CLI.banner
|
|
158
|
-
puts "\e[0m"
|
|
159
|
-
end
|
|
222
|
+
puts "\e[31m"
|
|
223
|
+
puts Sidekiq::CLI.banner
|
|
224
|
+
puts "\e[0m"
|
|
160
225
|
end
|
|
161
226
|
|
|
162
|
-
def
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
#
|
|
166
|
-
#
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
Celluloid.logger = (options[:verbose] ? Sidekiq.logger : nil)
|
|
170
|
-
|
|
171
|
-
require 'sidekiq/manager'
|
|
172
|
-
require 'sidekiq/scheduled'
|
|
227
|
+
def set_environment(cli_env)
|
|
228
|
+
# See #984 for discussion.
|
|
229
|
+
# APP_ENV is now the preferred ENV term since it is not tech-specific.
|
|
230
|
+
# Both Sinatra 2.0+ and Sidekiq support this term.
|
|
231
|
+
# RAILS_ENV and RACK_ENV are there for legacy support.
|
|
232
|
+
@environment = cli_env || ENV["APP_ENV"] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
|
|
233
|
+
config[:environment] = @environment
|
|
173
234
|
end
|
|
174
235
|
|
|
175
|
-
def
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
ObjectSpace.each_object(File) do |file|
|
|
181
|
-
files_to_reopen << file unless file.closed?
|
|
236
|
+
def symbolize_keys_deep!(hash)
|
|
237
|
+
hash.keys.each do |k|
|
|
238
|
+
symkey = k.respond_to?(:to_sym) ? k.to_sym : k
|
|
239
|
+
hash[symkey] = hash.delete k
|
|
240
|
+
symbolize_keys_deep! hash[symkey] if hash[symkey].is_a? Hash
|
|
182
241
|
end
|
|
183
|
-
|
|
184
|
-
::Process.daemon(true, true)
|
|
185
|
-
|
|
186
|
-
files_to_reopen.each do |file|
|
|
187
|
-
begin
|
|
188
|
-
file.reopen file.path, "a+"
|
|
189
|
-
file.sync = true
|
|
190
|
-
rescue ::Exception
|
|
191
|
-
end
|
|
192
|
-
end
|
|
193
|
-
|
|
194
|
-
[$stdout, $stderr].each do |io|
|
|
195
|
-
File.open(options[:logfile], 'ab') do |f|
|
|
196
|
-
io.reopen(f)
|
|
197
|
-
end
|
|
198
|
-
io.sync = true
|
|
199
|
-
end
|
|
200
|
-
$stdin.reopen('/dev/null')
|
|
201
|
-
|
|
202
|
-
initialize_logger
|
|
203
|
-
end
|
|
204
|
-
|
|
205
|
-
def set_environment(cli_env)
|
|
206
|
-
@environment = cli_env || ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development'
|
|
207
242
|
end
|
|
208
243
|
|
|
209
244
|
alias_method :die, :exit
|
|
210
245
|
alias_method :☠, :exit
|
|
211
246
|
|
|
212
247
|
def setup_options(args)
|
|
248
|
+
# parse CLI options
|
|
213
249
|
opts = parse_options(args)
|
|
250
|
+
|
|
214
251
|
set_environment opts[:environment]
|
|
215
252
|
|
|
216
|
-
|
|
217
|
-
|
|
253
|
+
# check config file presence
|
|
254
|
+
if opts[:config_file]
|
|
255
|
+
unless File.exist?(opts[:config_file])
|
|
256
|
+
raise ArgumentError, "No such file #{opts[:config_file]}"
|
|
257
|
+
end
|
|
258
|
+
else
|
|
259
|
+
config_dir = if File.directory?(opts[:require].to_s)
|
|
260
|
+
File.join(opts[:require], "config")
|
|
261
|
+
else
|
|
262
|
+
File.join(@config[:require], "config")
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
%w[sidekiq.yml sidekiq.yml.erb].each do |config_file|
|
|
266
|
+
path = File.join(config_dir, config_file)
|
|
267
|
+
opts[:config_file] ||= path if File.exist?(path)
|
|
268
|
+
end
|
|
269
|
+
end
|
|
218
270
|
|
|
219
|
-
|
|
271
|
+
# parse config file options
|
|
272
|
+
opts = parse_config(opts[:config_file]).merge(opts) if opts[:config_file]
|
|
220
273
|
|
|
221
|
-
|
|
222
|
-
|
|
274
|
+
# set defaults
|
|
275
|
+
opts[:queues] = ["default"] if opts[:queues].nil?
|
|
276
|
+
opts[:concurrency] = Integer(ENV["RAILS_MAX_THREADS"]) if opts[:concurrency].nil? && ENV["RAILS_MAX_THREADS"]
|
|
223
277
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
end
|
|
278
|
+
# merge with defaults
|
|
279
|
+
@config.merge!(opts)
|
|
227
280
|
|
|
228
|
-
|
|
229
|
-
|
|
281
|
+
@config.default_capsule.tap do |cap|
|
|
282
|
+
cap.queues = opts[:queues]
|
|
283
|
+
cap.concurrency = opts[:concurrency] || @config[:concurrency]
|
|
284
|
+
end
|
|
230
285
|
|
|
231
|
-
|
|
286
|
+
opts[:capsules]&.each do |name, cap_config|
|
|
287
|
+
@config.capsule(name.to_s) do |cap|
|
|
288
|
+
cap.queues = cap_config[:queues]
|
|
289
|
+
cap.concurrency = cap_config[:concurrency]
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
end
|
|
232
293
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
# Painful contortions, see 1791 for discussion
|
|
241
|
-
require File.expand_path("#{options[:require]}/config/application.rb")
|
|
242
|
-
::Rails::Application.initializer "sidekiq.eager_load" do
|
|
243
|
-
::Rails.application.config.eager_load = true
|
|
244
|
-
end
|
|
245
|
-
require 'sidekiq/rails'
|
|
246
|
-
require File.expand_path("#{options[:require]}/config/environment.rb")
|
|
294
|
+
def boot_application
|
|
295
|
+
ENV["RACK_ENV"] = ENV["RAILS_ENV"] = environment
|
|
296
|
+
|
|
297
|
+
if File.directory?(@config[:require])
|
|
298
|
+
require "rails"
|
|
299
|
+
if ::Rails::VERSION::MAJOR < 6
|
|
300
|
+
warn "Sidekiq #{Sidekiq::VERSION} only supports Rails 6+"
|
|
247
301
|
end
|
|
248
|
-
|
|
302
|
+
require "sidekiq/rails"
|
|
303
|
+
require File.expand_path("#{@config[:require]}/config/environment.rb")
|
|
304
|
+
@config[:tag] ||= default_tag
|
|
249
305
|
else
|
|
250
|
-
require
|
|
306
|
+
require @config[:require]
|
|
251
307
|
end
|
|
252
308
|
end
|
|
253
309
|
|
|
254
310
|
def default_tag
|
|
255
311
|
dir = ::Rails.root
|
|
256
312
|
name = File.basename(dir)
|
|
257
|
-
|
|
258
|
-
|
|
313
|
+
prevdir = File.dirname(dir) # Capistrano release directory?
|
|
314
|
+
if name.to_i != 0 && prevdir
|
|
315
|
+
if File.basename(prevdir) == "releases"
|
|
259
316
|
return File.basename(File.dirname(prevdir))
|
|
260
317
|
end
|
|
261
318
|
end
|
|
@@ -263,57 +320,52 @@ module Sidekiq
|
|
|
263
320
|
end
|
|
264
321
|
|
|
265
322
|
def validate!
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
if !File.exist?(options[:require]) ||
|
|
269
|
-
(File.directory?(options[:require]) && !File.exist?("#{options[:require]}/config/application.rb"))
|
|
323
|
+
if !File.exist?(@config[:require]) ||
|
|
324
|
+
(File.directory?(@config[:require]) && !File.exist?("#{@config[:require]}/config/application.rb"))
|
|
270
325
|
logger.info "=================================================================="
|
|
271
|
-
logger.info " Please point
|
|
272
|
-
logger.info " to load your
|
|
326
|
+
logger.info " Please point Sidekiq to a Rails application or a Ruby file "
|
|
327
|
+
logger.info " to load your job classes with -r [DIR|FILE]."
|
|
273
328
|
logger.info "=================================================================="
|
|
274
329
|
logger.info @parser
|
|
275
330
|
die(1)
|
|
276
331
|
end
|
|
277
332
|
|
|
278
333
|
[:concurrency, :timeout].each do |opt|
|
|
279
|
-
raise ArgumentError, "#{opt}: #{
|
|
334
|
+
raise ArgumentError, "#{opt}: #{@config[opt]} is not a valid value" if @config[opt].to_i <= 0
|
|
280
335
|
end
|
|
281
336
|
end
|
|
282
337
|
|
|
283
338
|
def parse_options(argv)
|
|
284
339
|
opts = {}
|
|
340
|
+
@parser = option_parser(opts)
|
|
341
|
+
@parser.parse!(argv)
|
|
342
|
+
opts
|
|
343
|
+
end
|
|
285
344
|
|
|
286
|
-
|
|
287
|
-
|
|
345
|
+
def option_parser(opts)
|
|
346
|
+
parser = OptionParser.new { |o|
|
|
347
|
+
o.on "-c", "--concurrency INT", "processor threads to use" do |arg|
|
|
288
348
|
opts[:concurrency] = Integer(arg)
|
|
289
349
|
end
|
|
290
350
|
|
|
291
|
-
o.on
|
|
292
|
-
opts[:daemon] = arg
|
|
293
|
-
end
|
|
294
|
-
|
|
295
|
-
o.on '-e', '--environment ENV', "Application environment" do |arg|
|
|
351
|
+
o.on "-e", "--environment ENV", "Application environment" do |arg|
|
|
296
352
|
opts[:environment] = arg
|
|
297
353
|
end
|
|
298
354
|
|
|
299
|
-
o.on
|
|
355
|
+
o.on "-g", "--tag TAG", "Process tag for procline" do |arg|
|
|
300
356
|
opts[:tag] = arg
|
|
301
357
|
end
|
|
302
358
|
|
|
303
|
-
o.on '-i', '--index INT', "unique process index on this machine" do |arg|
|
|
304
|
-
opts[:index] = Integer(arg.match(/\d+/)[0])
|
|
305
|
-
end
|
|
306
|
-
|
|
307
359
|
o.on "-q", "--queue QUEUE[,WEIGHT]", "Queues to process with optional weights" do |arg|
|
|
308
|
-
|
|
309
|
-
|
|
360
|
+
opts[:queues] ||= []
|
|
361
|
+
opts[:queues] << arg
|
|
310
362
|
end
|
|
311
363
|
|
|
312
|
-
o.on
|
|
364
|
+
o.on "-r", "--require [PATH|DIR]", "Location of Rails application with jobs or file to require" do |arg|
|
|
313
365
|
opts[:require] = arg
|
|
314
366
|
end
|
|
315
367
|
|
|
316
|
-
o.on
|
|
368
|
+
o.on "-t", "--timeout NUM", "Shutdown timeout" do |arg|
|
|
317
369
|
opts[:timeout] = Integer(arg)
|
|
318
370
|
end
|
|
319
371
|
|
|
@@ -321,81 +373,51 @@ module Sidekiq
|
|
|
321
373
|
opts[:verbose] = arg
|
|
322
374
|
end
|
|
323
375
|
|
|
324
|
-
o.on
|
|
376
|
+
o.on "-C", "--config PATH", "path to YAML config file" do |arg|
|
|
325
377
|
opts[:config_file] = arg
|
|
326
378
|
end
|
|
327
379
|
|
|
328
|
-
o.on
|
|
329
|
-
opts[:logfile] = arg
|
|
330
|
-
end
|
|
331
|
-
|
|
332
|
-
o.on '-P', '--pidfile PATH', "path to pidfile" do |arg|
|
|
333
|
-
opts[:pidfile] = arg
|
|
334
|
-
end
|
|
335
|
-
|
|
336
|
-
o.on '-V', '--version', "Print version and exit" do |arg|
|
|
380
|
+
o.on "-V", "--version", "Print version and exit" do
|
|
337
381
|
puts "Sidekiq #{Sidekiq::VERSION}"
|
|
338
382
|
die(0)
|
|
339
383
|
end
|
|
340
|
-
|
|
384
|
+
}
|
|
341
385
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
logger.info
|
|
386
|
+
parser.banner = "sidekiq [options]"
|
|
387
|
+
parser.on_tail "-h", "--help", "Show help" do
|
|
388
|
+
logger.info parser
|
|
345
389
|
die 1
|
|
346
390
|
end
|
|
347
|
-
@parser.parse!(argv)
|
|
348
|
-
|
|
349
|
-
%w[config/sidekiq.yml config/sidekiq.yml.erb].each do |filename|
|
|
350
|
-
opts[:config_file] ||= filename if File.exist?(filename)
|
|
351
|
-
end
|
|
352
391
|
|
|
353
|
-
|
|
392
|
+
parser
|
|
354
393
|
end
|
|
355
394
|
|
|
356
395
|
def initialize_logger
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
Sidekiq.logger.level = ::Logger::DEBUG if options[:verbose]
|
|
396
|
+
@config.logger.level = ::Logger::DEBUG if @config[:verbose]
|
|
360
397
|
end
|
|
361
398
|
|
|
362
|
-
def
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
f.puts ::Process.pid
|
|
367
|
-
end
|
|
368
|
-
end
|
|
369
|
-
end
|
|
399
|
+
def parse_config(path)
|
|
400
|
+
erb = ERB.new(File.read(path), trim_mode: "-")
|
|
401
|
+
erb.filename = File.expand_path(path)
|
|
402
|
+
opts = YAML.safe_load(erb.result, permitted_classes: [Symbol], aliases: true) || {}
|
|
370
403
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
if File.exist?(cfile)
|
|
374
|
-
opts = YAML.load(ERB.new(IO.read(cfile)).result) || opts
|
|
375
|
-
opts = opts.merge(opts.delete(environment) || {})
|
|
376
|
-
parse_queues(opts, opts.delete(:queues) || [])
|
|
404
|
+
if opts.respond_to? :deep_symbolize_keys!
|
|
405
|
+
opts.deep_symbolize_keys!
|
|
377
406
|
else
|
|
378
|
-
|
|
379
|
-
# can be deployed by cap with just the defaults.
|
|
380
|
-
end
|
|
381
|
-
ns = opts.delete(:namespace)
|
|
382
|
-
if ns
|
|
383
|
-
# logger hasn't been initialized yet, puts is all we have.
|
|
384
|
-
puts("namespace should be set in your ruby initializer, is ignored in config file")
|
|
385
|
-
puts("config.redis = { :url => ..., :namespace => '#{ns}' }")
|
|
407
|
+
symbolize_keys_deep!(opts)
|
|
386
408
|
end
|
|
387
|
-
opts
|
|
388
|
-
end
|
|
389
409
|
|
|
390
|
-
|
|
391
|
-
|
|
410
|
+
opts = opts.merge(opts.delete(environment.to_sym) || {})
|
|
411
|
+
opts.delete(:strict)
|
|
412
|
+
|
|
413
|
+
opts
|
|
392
414
|
end
|
|
393
415
|
|
|
394
|
-
def
|
|
395
|
-
|
|
396
|
-
(opts[:queues] ||= []) << q
|
|
397
|
-
end
|
|
398
|
-
opts[:strict] = false if weight.to_i > 0
|
|
416
|
+
def rails_app?
|
|
417
|
+
defined?(::Rails) && ::Rails.respond_to?(:application)
|
|
399
418
|
end
|
|
400
419
|
end
|
|
401
420
|
end
|
|
421
|
+
|
|
422
|
+
require "sidekiq/systemd"
|
|
423
|
+
require "sidekiq/metrics/tracking"
|