sidekiq 6.5.10 → 8.1.7
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 +568 -18
- data/README.md +66 -38
- data/bin/kiq +17 -0
- data/bin/lint-herb +13 -0
- data/bin/multi_queue_bench +271 -0
- data/bin/sidekiq +3 -8
- data/bin/sidekiqload +215 -118
- data/bin/sidekiqmon +3 -0
- data/bin/webload +69 -0
- data/lib/active_job/queue_adapters/sidekiq_adapter.rb +124 -0
- data/lib/generators/sidekiq/job_generator.rb +17 -3
- data/lib/generators/sidekiq/templates/job.rb.erb +1 -1
- data/lib/sidekiq/api.rb +526 -218
- data/lib/sidekiq/capsule.rb +135 -0
- data/lib/sidekiq/cli.rb +88 -96
- data/lib/sidekiq/client.rb +114 -47
- data/lib/sidekiq/component.rb +71 -4
- data/lib/sidekiq/config.rb +316 -0
- data/lib/sidekiq/deploy.rb +64 -0
- data/lib/sidekiq/embedded.rb +64 -0
- data/lib/sidekiq/fetch.rb +12 -14
- data/lib/sidekiq/iterable_job.rb +56 -0
- data/lib/sidekiq/job/interrupt_handler.rb +24 -0
- data/lib/sidekiq/job/iterable/active_record_enumerator.rb +53 -0
- data/lib/sidekiq/job/iterable/csv_enumerator.rb +47 -0
- data/lib/sidekiq/job/iterable/enumerators.rb +135 -0
- data/lib/sidekiq/job/iterable.rb +322 -0
- data/lib/sidekiq/job.rb +397 -10
- data/lib/sidekiq/job_logger.rb +14 -11
- data/lib/sidekiq/job_retry.rb +78 -28
- data/lib/sidekiq/job_util.rb +58 -16
- data/lib/sidekiq/launcher.rb +86 -70
- data/lib/sidekiq/loader.rb +57 -0
- data/lib/sidekiq/logger.rb +25 -94
- data/lib/sidekiq/manager.rb +11 -13
- data/lib/sidekiq/metrics/query.rb +84 -48
- data/lib/sidekiq/metrics/shared.rb +29 -14
- data/lib/sidekiq/metrics/tracking.rb +49 -30
- data/lib/sidekiq/middleware/chain.rb +19 -18
- data/lib/sidekiq/middleware/current_attributes.rb +78 -21
- data/lib/sidekiq/middleware/i18n.rb +2 -0
- data/lib/sidekiq/middleware/modules.rb +2 -0
- data/lib/sidekiq/monitor.rb +15 -5
- data/lib/sidekiq/paginator.rb +26 -4
- data/lib/sidekiq/processor.rb +78 -65
- data/lib/sidekiq/profiler.rb +73 -0
- data/lib/sidekiq/rails.rb +45 -60
- data/lib/sidekiq/redis_client_adapter.rb +35 -72
- data/lib/sidekiq/redis_connection.rb +54 -114
- data/lib/sidekiq/ring_buffer.rb +3 -0
- data/lib/sidekiq/scheduled.rb +28 -30
- data/lib/sidekiq/systemd.rb +2 -0
- data/lib/sidekiq/test_api.rb +331 -0
- data/lib/sidekiq/testing/inline.rb +2 -30
- data/lib/sidekiq/testing.rb +2 -342
- data/lib/sidekiq/transaction_aware_client.rb +23 -9
- data/lib/sidekiq/tui/controls.rb +53 -0
- data/lib/sidekiq/tui/filtering.rb +53 -0
- data/lib/sidekiq/tui/tabs/base_tab.rb +230 -0
- data/lib/sidekiq/tui/tabs/busy.rb +104 -0
- data/lib/sidekiq/tui/tabs/dead.rb +14 -0
- data/lib/sidekiq/tui/tabs/home.rb +115 -0
- data/lib/sidekiq/tui/tabs/metrics.rb +114 -0
- data/lib/sidekiq/tui/tabs/queues.rb +83 -0
- data/lib/sidekiq/tui/tabs/retries.rb +14 -0
- data/lib/sidekiq/tui/tabs/scheduled.rb +14 -0
- data/lib/sidekiq/tui/tabs/set_tab.rb +91 -0
- data/lib/sidekiq/tui/tabs.rb +15 -0
- data/lib/sidekiq/tui.rb +390 -0
- data/lib/sidekiq/version.rb +6 -1
- data/lib/sidekiq/web/action.rb +149 -64
- data/lib/sidekiq/web/application.rb +379 -281
- data/lib/sidekiq/web/config.rb +117 -0
- data/lib/sidekiq/web/helpers.rb +190 -71
- data/lib/sidekiq/web/router.rb +62 -75
- data/lib/sidekiq/web.rb +68 -101
- data/lib/sidekiq/worker_compatibility_alias.rb +13 -0
- data/lib/sidekiq.rb +85 -269
- data/sidekiq.gemspec +15 -11
- data/web/assets/images/logo.png +0 -0
- data/web/assets/images/status.png +0 -0
- data/web/assets/javascripts/application.js +84 -24
- data/web/assets/javascripts/base-charts.js +120 -0
- data/web/assets/javascripts/chartjs-adapter-date-fns.min.js +7 -0
- data/web/assets/javascripts/dashboard-charts.js +194 -0
- data/web/assets/javascripts/dashboard.js +18 -234
- data/web/assets/javascripts/metrics.js +138 -120
- data/web/assets/stylesheets/style.css +776 -0
- data/web/locales/ar.yml +72 -70
- data/web/locales/cs.yml +64 -62
- data/web/locales/da.yml +62 -53
- data/web/locales/de.yml +67 -65
- data/web/locales/el.yml +4 -7
- data/web/locales/en.yml +89 -71
- data/web/locales/es.yml +91 -68
- data/web/locales/fa.yml +67 -65
- data/web/locales/fr.yml +82 -67
- data/web/locales/gd.yml +110 -0
- data/web/locales/he.yml +67 -64
- data/web/locales/hi.yml +95 -59
- data/web/locales/it.yml +94 -54
- data/web/locales/ja.yml +69 -70
- data/web/locales/ko.yml +54 -52
- data/web/locales/lt.yml +68 -66
- data/web/locales/nb.yml +63 -61
- data/web/locales/nl.yml +54 -52
- data/web/locales/pl.yml +47 -45
- data/web/locales/{pt-br.yml → pt-BR.yml} +81 -70
- data/web/locales/pt.yml +53 -51
- data/web/locales/ru.yml +69 -66
- data/web/locales/sv.yml +55 -53
- data/web/locales/ta.yml +100 -64
- data/web/locales/tr.yml +102 -0
- data/web/locales/uk.yml +87 -61
- data/web/locales/ur.yml +66 -64
- data/web/locales/vi.yml +69 -67
- data/web/locales/zh-CN.yml +107 -0
- data/web/locales/{zh-tw.yml → zh-TW.yml} +13 -3
- data/web/views/_footer.html.erb +32 -0
- data/web/views/_job_info.html.erb +115 -0
- data/web/views/_metrics_period_select.html.erb +15 -0
- data/web/views/_nav.html.erb +45 -0
- data/web/views/_paging.html.erb +26 -0
- data/web/views/_poll_link.html.erb +4 -0
- data/web/views/_summary.html.erb +40 -0
- data/web/views/busy.html.erb +155 -0
- data/web/views/dashboard.html.erb +104 -0
- data/web/views/dead.html.erb +38 -0
- data/web/views/filtering.html.erb +6 -0
- data/web/views/layout.html.erb +26 -0
- data/web/views/metrics.html.erb +85 -0
- data/web/views/metrics_for_job.html.erb +58 -0
- data/web/views/morgue.html.erb +69 -0
- data/web/views/profiles.html.erb +43 -0
- data/web/views/queue.html.erb +57 -0
- data/web/views/queues.html.erb +46 -0
- data/web/views/retries.html.erb +77 -0
- data/web/views/retry.html.erb +39 -0
- data/web/views/scheduled.html.erb +64 -0
- data/web/views/{scheduled_job_info.erb → scheduled_job_info.html.erb} +3 -3
- metadata +113 -70
- data/lib/sidekiq/delay.rb +0 -43
- data/lib/sidekiq/extensions/action_mailer.rb +0 -48
- data/lib/sidekiq/extensions/active_record.rb +0 -43
- data/lib/sidekiq/extensions/class_methods.rb +0 -43
- data/lib/sidekiq/extensions/generic_proxy.rb +0 -33
- data/lib/sidekiq/metrics/deploy.rb +0 -47
- data/lib/sidekiq/web/csrf_protection.rb +0 -180
- data/lib/sidekiq/worker.rb +0 -370
- data/web/assets/javascripts/graph.js +0 -16
- data/web/assets/stylesheets/application-dark.css +0 -143
- data/web/assets/stylesheets/application-rtl.css +0 -242
- data/web/assets/stylesheets/application.css +0 -999
- data/web/assets/stylesheets/bootstrap-rtl.min.css +0 -9
- data/web/assets/stylesheets/bootstrap.css +0 -5
- data/web/locales/zh-cn.yml +0 -93
- data/web/views/_footer.erb +0 -20
- data/web/views/_job_info.erb +0 -89
- data/web/views/_nav.erb +0 -52
- data/web/views/_paging.erb +0 -23
- data/web/views/_poll_link.erb +0 -4
- data/web/views/_status.erb +0 -4
- data/web/views/_summary.erb +0 -40
- data/web/views/busy.erb +0 -137
- data/web/views/dashboard.erb +0 -84
- data/web/views/dead.erb +0 -34
- data/web/views/layout.erb +0 -42
- data/web/views/metrics.erb +0 -69
- data/web/views/metrics_for_job.erb +0 -87
- data/web/views/morgue.erb +0 -78
- data/web/views/queue.erb +0 -59
- data/web/views/queues.erb +0 -38
- data/web/views/retries.erb +0 -83
- data/web/views/retry.erb +0 -34
- data/web/views/scheduled.erb +0 -57
- /data/{LICENSE → LICENSE.txt} +0 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "sidekiq/component"
|
|
4
|
+
|
|
5
|
+
module Sidekiq
|
|
6
|
+
# A Sidekiq::Capsule is the set of resources necessary to
|
|
7
|
+
# process one or more queues with a given concurrency.
|
|
8
|
+
# One "default" Capsule is started but the user may declare additional
|
|
9
|
+
# Capsules in their initializer.
|
|
10
|
+
#
|
|
11
|
+
# This capsule will pull jobs from the "single" queue and process
|
|
12
|
+
# the jobs with one thread, meaning the jobs will be processed serially.
|
|
13
|
+
#
|
|
14
|
+
# Sidekiq.configure_server do |config|
|
|
15
|
+
# config.capsule("single-threaded") do |cap|
|
|
16
|
+
# cap.concurrency = 1
|
|
17
|
+
# cap.queues = %w(single)
|
|
18
|
+
# end
|
|
19
|
+
# end
|
|
20
|
+
class Capsule
|
|
21
|
+
include Sidekiq::Component
|
|
22
|
+
extend Forwardable
|
|
23
|
+
|
|
24
|
+
attr_reader :name
|
|
25
|
+
attr_reader :queues
|
|
26
|
+
attr_accessor :concurrency
|
|
27
|
+
attr_reader :mode
|
|
28
|
+
attr_reader :weights
|
|
29
|
+
|
|
30
|
+
def_delegators :@config, :[], :[]=, :fetch, :key?, :has_key?, :merge!, :dig, :thread_priority
|
|
31
|
+
|
|
32
|
+
def initialize(name, config)
|
|
33
|
+
@name = name
|
|
34
|
+
@config = config
|
|
35
|
+
@queues = ["default"]
|
|
36
|
+
@weights = {"default" => 0}
|
|
37
|
+
@concurrency = config[:concurrency]
|
|
38
|
+
@mode = :strict
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def to_h
|
|
42
|
+
{concurrency: concurrency, mode: mode, weights: weights}
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def fetcher
|
|
46
|
+
@fetcher ||= begin
|
|
47
|
+
instance = (config[:fetch_class] || Sidekiq::BasicFetch).new(self)
|
|
48
|
+
instance.setup(config[:fetch_setup]) if instance.respond_to?(:setup)
|
|
49
|
+
instance
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def stop
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Sidekiq checks queues in three modes:
|
|
57
|
+
# - :strict - all queues have 0 weight and are checked strictly in order
|
|
58
|
+
# - :weighted - queues have arbitrary weight between 1 and N
|
|
59
|
+
# - :random - all queues have weight of 1
|
|
60
|
+
def queues=(val)
|
|
61
|
+
@weights = {}
|
|
62
|
+
@queues = Array(val).each_with_object([]) do |qstr, memo|
|
|
63
|
+
arr = qstr
|
|
64
|
+
arr = qstr.split(",") if qstr.is_a?(String)
|
|
65
|
+
name, weight = arr
|
|
66
|
+
@weights[name] = weight.to_i
|
|
67
|
+
[weight.to_i, 1].max.times do
|
|
68
|
+
memo << name
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
@mode = if @weights.values.all?(&:zero?)
|
|
72
|
+
:strict
|
|
73
|
+
elsif @weights.values.all? { |x| x == 1 }
|
|
74
|
+
:random
|
|
75
|
+
else
|
|
76
|
+
:weighted
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Allow the middleware to be different per-capsule.
|
|
81
|
+
# Avoid if possible and add middleware globally so all
|
|
82
|
+
# capsules share the same chains. Easier to debug that way.
|
|
83
|
+
def client_middleware
|
|
84
|
+
@client_chain ||= config.client_middleware.copy_for(self)
|
|
85
|
+
yield @client_chain if block_given?
|
|
86
|
+
@client_chain
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def server_middleware
|
|
90
|
+
@server_chain ||= config.server_middleware.copy_for(self)
|
|
91
|
+
yield @server_chain if block_given?
|
|
92
|
+
@server_chain
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def redis_pool
|
|
96
|
+
Thread.current[:sidekiq_redis_pool] || local_redis_pool
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def local_redis_pool
|
|
100
|
+
# connection pool is lazy, it will not create connections unless you actually need them
|
|
101
|
+
# so don't be skimpy!
|
|
102
|
+
@redis ||= config.new_redis_pool(@concurrency, name)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def redis
|
|
106
|
+
raise ArgumentError, "requires a block" unless block_given?
|
|
107
|
+
redis_pool.with do |conn|
|
|
108
|
+
retryable = true
|
|
109
|
+
begin
|
|
110
|
+
yield conn
|
|
111
|
+
rescue RedisClientAdapter::BaseError => ex
|
|
112
|
+
# 2550 Failover can cause the server to become a replica, need
|
|
113
|
+
# to disconnect and reopen the socket to get back to the primary.
|
|
114
|
+
# 4495 Use the same logic if we have a "Not enough replicas" error from the primary
|
|
115
|
+
# 4985 Use the same logic when a blocking command is force-unblocked
|
|
116
|
+
# The same retry logic is also used in client.rb
|
|
117
|
+
if retryable && ex.message =~ /READONLY|NOREPLICAS|UNBLOCKED/
|
|
118
|
+
conn.close
|
|
119
|
+
retryable = false
|
|
120
|
+
retry
|
|
121
|
+
end
|
|
122
|
+
raise
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def lookup(name)
|
|
128
|
+
config.lookup(name)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def logger
|
|
132
|
+
config.logger
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
data/lib/sidekiq/cli.rb
CHANGED
|
@@ -2,46 +2,36 @@
|
|
|
2
2
|
|
|
3
3
|
$stdout.sync = true
|
|
4
4
|
|
|
5
|
-
require "yaml"
|
|
6
|
-
require "singleton"
|
|
7
5
|
require "optparse"
|
|
8
6
|
require "erb"
|
|
9
7
|
require "fileutils"
|
|
10
8
|
|
|
11
9
|
require "sidekiq"
|
|
10
|
+
require "sidekiq/config"
|
|
12
11
|
require "sidekiq/component"
|
|
12
|
+
require "sidekiq/capsule"
|
|
13
13
|
require "sidekiq/launcher"
|
|
14
14
|
|
|
15
|
-
# module ScoutApm
|
|
16
|
-
# VERSION = "5.3.1"
|
|
17
|
-
# end
|
|
18
|
-
fail <<~EOM if defined?(ScoutApm::VERSION) && ScoutApm::VERSION < "5.2.0"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
scout_apm v#{ScoutApm::VERSION} is unsafe with Sidekiq 6.5. Please run `bundle up scout_apm` to upgrade to 5.2.0 or greater.
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
EOM
|
|
25
|
-
|
|
26
15
|
module Sidekiq # :nodoc:
|
|
27
16
|
class CLI
|
|
28
17
|
include Sidekiq::Component
|
|
29
|
-
include Singleton unless $TESTING
|
|
30
18
|
|
|
31
19
|
attr_accessor :launcher
|
|
32
20
|
attr_accessor :environment
|
|
33
21
|
attr_accessor :config
|
|
34
22
|
|
|
35
23
|
def parse(args = ARGV.dup)
|
|
36
|
-
@config
|
|
37
|
-
@config[:error_handlers].clear
|
|
38
|
-
@config[:error_handlers] << @config.method(:default_error_handler)
|
|
24
|
+
@config ||= Sidekiq.default_configuration
|
|
39
25
|
|
|
40
26
|
setup_options(args)
|
|
41
27
|
initialize_logger
|
|
42
28
|
validate!
|
|
43
29
|
end
|
|
44
30
|
|
|
31
|
+
def self.instance
|
|
32
|
+
@instance ||= new
|
|
33
|
+
end
|
|
34
|
+
|
|
45
35
|
def jruby?
|
|
46
36
|
defined?(::JRUBY_VERSION)
|
|
47
37
|
end
|
|
@@ -49,16 +39,16 @@ module Sidekiq # :nodoc:
|
|
|
49
39
|
# Code within this method is not tested because it alters
|
|
50
40
|
# global process state irreversibly. PRs which improve the
|
|
51
41
|
# test coverage of Sidekiq::CLI are welcomed.
|
|
52
|
-
def run(boot_app: true)
|
|
42
|
+
def run(boot_app: true, warmup: true)
|
|
53
43
|
boot_application if boot_app
|
|
54
44
|
|
|
55
|
-
if environment == "development" && $stdout.tty? && @config.
|
|
45
|
+
if environment == "development" && $stdout.tty? && @config.logger.formatter.is_a?(Sidekiq::Logger::Formatters::Pretty)
|
|
56
46
|
print_banner
|
|
57
47
|
end
|
|
58
48
|
logger.info "Booted Rails #{::Rails.version} application in #{environment} environment" if rails_app?
|
|
59
49
|
|
|
60
50
|
self_read, self_write = IO.pipe
|
|
61
|
-
sigs = %w[INT TERM TTIN TSTP]
|
|
51
|
+
sigs = %w[INT TERM INFO TTIN TSTP]
|
|
62
52
|
# USR1 and USR2 don't work on the JVM
|
|
63
53
|
sigs << "USR2" if Sidekiq.pro? && !jruby?
|
|
64
54
|
sigs.each do |sig|
|
|
@@ -84,26 +74,27 @@ module Sidekiq # :nodoc:
|
|
|
84
74
|
# touch the connection pool so it is created before we
|
|
85
75
|
# fire startup and start multithreading.
|
|
86
76
|
info = @config.redis_info
|
|
87
|
-
ver = info["redis_version"]
|
|
88
|
-
raise "You are
|
|
77
|
+
ver = Gem::Version.new(info["redis_version"])
|
|
78
|
+
raise "You are connected to Redis #{ver}, Sidekiq requires Redis 7.0.0 or greater" if ver < Gem::Version.new("7.0.0")
|
|
89
79
|
|
|
90
80
|
maxmemory_policy = info["maxmemory_policy"]
|
|
91
|
-
if maxmemory_policy != "noeviction"
|
|
81
|
+
if maxmemory_policy != "noeviction" && maxmemory_policy != ""
|
|
82
|
+
# Redis Enterprise Cloud returns "" for their policy 😳
|
|
92
83
|
logger.warn <<~EOM
|
|
93
84
|
|
|
94
85
|
|
|
95
86
|
WARNING: Your Redis instance will evict Sidekiq data under heavy load.
|
|
96
87
|
The 'noeviction' maxmemory policy is recommended (current policy: '#{maxmemory_policy}').
|
|
97
|
-
See: https://github.com/
|
|
88
|
+
See: https://github.com/sidekiq/sidekiq/wiki/Using-Redis#memory
|
|
98
89
|
|
|
99
90
|
EOM
|
|
100
91
|
end
|
|
101
92
|
|
|
102
93
|
# Since the user can pass us a connection pool explicitly in the initializer, we
|
|
103
94
|
# need to verify the size is large enough or else Sidekiq's performance is dramatically slowed.
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
95
|
+
@config.capsules.each_pair do |name, cap|
|
|
96
|
+
raise ArgumentError, "Pool size too small for #{name}" if cap.redis_pool.size < cap.concurrency
|
|
97
|
+
end
|
|
107
98
|
|
|
108
99
|
# cache process identity
|
|
109
100
|
@config[:identity] = identity
|
|
@@ -111,12 +102,14 @@ module Sidekiq # :nodoc:
|
|
|
111
102
|
# Touch middleware so it isn't lazy loaded by multiple threads, #3043
|
|
112
103
|
@config.server_middleware
|
|
113
104
|
|
|
105
|
+
::Process.warmup if warmup && ::Process.respond_to?(:warmup) && ENV["RUBY_DISABLE_WARMUP"] != "1"
|
|
106
|
+
|
|
114
107
|
# Before this point, the process is initializing with just the main thread.
|
|
115
108
|
# Starting here the process will now have multiple threads running.
|
|
116
109
|
fire_event(:startup, reverse: false, reraise: true)
|
|
117
110
|
|
|
118
|
-
logger.debug { "Client Middleware: #{@config.client_middleware.map(&:klass).join(", ")}" }
|
|
119
|
-
logger.debug { "Server Middleware: #{@config.server_middleware.map(&:klass).join(", ")}" }
|
|
111
|
+
logger.debug { "Client Middleware: #{@config.default_capsule.client_middleware.map(&:klass).join(", ")}" }
|
|
112
|
+
logger.debug { "Server Middleware: #{@config.default_capsule.server_middleware.map(&:klass).join(", ")}" }
|
|
120
113
|
|
|
121
114
|
launch(self_read)
|
|
122
115
|
end
|
|
@@ -149,19 +142,34 @@ module Sidekiq # :nodoc:
|
|
|
149
142
|
end
|
|
150
143
|
end
|
|
151
144
|
|
|
152
|
-
|
|
153
|
-
|
|
145
|
+
HOLIDAY_COLORS = {
|
|
146
|
+
# got other color-specific holidays from around the world?
|
|
147
|
+
# https://developer-book.com/post/definitive-guide-for-colored-text-in-terminal/#256-color-escape-codes
|
|
148
|
+
"3-17" => "\e[1;32m", # St. Patrick's Day green
|
|
149
|
+
"10-31" => "\e[38;5;208m" # Halloween orange
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
def self.day
|
|
153
|
+
@@day ||= begin
|
|
154
|
+
t = Date.today
|
|
155
|
+
"#{t.month}-#{t.day}"
|
|
156
|
+
end
|
|
154
157
|
end
|
|
155
158
|
|
|
156
159
|
def self.r
|
|
157
|
-
"\e[31m"
|
|
160
|
+
@@r ||= HOLIDAY_COLORS[day] || "\e[1;31m"
|
|
158
161
|
end
|
|
159
162
|
|
|
160
163
|
def self.b
|
|
161
|
-
"\e[30m"
|
|
164
|
+
@@b ||= HOLIDAY_COLORS[day] || "\e[30m"
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def self.w
|
|
168
|
+
"\e[1;37m"
|
|
162
169
|
end
|
|
163
170
|
|
|
164
171
|
def self.reset
|
|
172
|
+
@@b = @@r = @@day = nil
|
|
165
173
|
"\e[0m"
|
|
166
174
|
end
|
|
167
175
|
|
|
@@ -174,7 +182,7 @@ module Sidekiq # :nodoc:
|
|
|
174
182
|
#{w} ,$$$$$b#{b}/#{w}md$$$P^'
|
|
175
183
|
#{w} .d$$$$$$#{b}/#{w}$$$P'
|
|
176
184
|
#{w} $$^' `"#{b}/#{w}$$$' #{r}____ _ _ _ _
|
|
177
|
-
#{w} $:
|
|
185
|
+
#{w} $: #{b}'#{w},$$: #{r} / ___|(_) __| | ___| | _(_) __ _
|
|
178
186
|
#{w} `b :$$ #{r} \\___ \\| |/ _` |/ _ \\ |/ / |/ _` |
|
|
179
187
|
#{w} $$: #{r} ___) | | (_| | __/ <| | (_| |
|
|
180
188
|
#{w} $$ #{r}|____/|_|\\__,_|\\___|_|\\_\\_|\\__, |
|
|
@@ -201,14 +209,25 @@ module Sidekiq # :nodoc:
|
|
|
201
209
|
cli.logger.warn "<no backtrace available>"
|
|
202
210
|
end
|
|
203
211
|
end
|
|
212
|
+
},
|
|
213
|
+
"INFO" => ->(cli) {
|
|
214
|
+
cli.logger.error { "DEPRECATED: the INFO signal does not work on Linux, use TTIN instead." }
|
|
215
|
+
Thread.list.each do |thread|
|
|
216
|
+
cli.logger.warn "Thread TID-#{(thread.object_id ^ ::Process.pid).to_s(36)} #{thread.name}"
|
|
217
|
+
if thread.backtrace
|
|
218
|
+
cli.logger.warn thread.backtrace.join("\n")
|
|
219
|
+
else
|
|
220
|
+
cli.logger.warn "<no backtrace available>"
|
|
221
|
+
end
|
|
222
|
+
end
|
|
204
223
|
}
|
|
205
224
|
}
|
|
206
|
-
UNHANDLED_SIGNAL_HANDLER = ->(cli) { cli.logger.info "No signal handler registered, ignoring" }
|
|
207
|
-
SIGNAL_HANDLERS.default = UNHANDLED_SIGNAL_HANDLER
|
|
208
225
|
|
|
209
226
|
def handle_signal(sig)
|
|
210
227
|
logger.debug "Got #{sig} signal"
|
|
211
|
-
SIGNAL_HANDLERS[sig]
|
|
228
|
+
hndlr = SIGNAL_HANDLERS[sig]
|
|
229
|
+
hndlr ? hndlr.call(self) :
|
|
230
|
+
logger.warn("No #{sig} signal handler registered, ignoring")
|
|
212
231
|
end
|
|
213
232
|
|
|
214
233
|
private
|
|
@@ -272,6 +291,18 @@ module Sidekiq # :nodoc:
|
|
|
272
291
|
|
|
273
292
|
# merge with defaults
|
|
274
293
|
@config.merge!(opts)
|
|
294
|
+
|
|
295
|
+
@config.default_capsule.tap do |cap|
|
|
296
|
+
cap.queues = opts[:queues]
|
|
297
|
+
cap.concurrency = opts[:concurrency] || @config[:concurrency]
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
opts[:capsules]&.each do |name, cap_config|
|
|
301
|
+
@config.capsule(name.to_s) do |cap|
|
|
302
|
+
cap.queues = cap_config[:queues]
|
|
303
|
+
cap.concurrency = cap_config[:concurrency]
|
|
304
|
+
end
|
|
305
|
+
end
|
|
275
306
|
end
|
|
276
307
|
|
|
277
308
|
def boot_application
|
|
@@ -279,30 +310,18 @@ module Sidekiq # :nodoc:
|
|
|
279
310
|
|
|
280
311
|
if File.directory?(@config[:require])
|
|
281
312
|
require "rails"
|
|
282
|
-
if ::Rails::VERSION::MAJOR <
|
|
283
|
-
|
|
284
|
-
else
|
|
285
|
-
require "sidekiq/rails"
|
|
286
|
-
require File.expand_path("#{@config[:require]}/config/environment.rb")
|
|
313
|
+
if ::Rails::VERSION::MAJOR < 7
|
|
314
|
+
warn "Sidekiq #{Sidekiq::VERSION} only supports Rails 7+"
|
|
287
315
|
end
|
|
288
|
-
|
|
316
|
+
require "sidekiq/rails"
|
|
317
|
+
require File.expand_path("#{@config[:require]}/config/environment.rb")
|
|
318
|
+
@config[:tag] ||= default_tag(::Rails.root)
|
|
289
319
|
else
|
|
290
320
|
require @config[:require]
|
|
321
|
+
@config[:tag] ||= default_tag
|
|
291
322
|
end
|
|
292
323
|
end
|
|
293
324
|
|
|
294
|
-
def default_tag
|
|
295
|
-
dir = ::Rails.root
|
|
296
|
-
name = File.basename(dir)
|
|
297
|
-
prevdir = File.dirname(dir) # Capistrano release directory?
|
|
298
|
-
if name.to_i != 0 && prevdir
|
|
299
|
-
if File.basename(prevdir) == "releases"
|
|
300
|
-
return File.basename(File.dirname(prevdir))
|
|
301
|
-
end
|
|
302
|
-
end
|
|
303
|
-
name
|
|
304
|
-
end
|
|
305
|
-
|
|
306
325
|
def validate!
|
|
307
326
|
if !File.exist?(@config[:require]) ||
|
|
308
327
|
(File.directory?(@config[:require]) && !File.exist?("#{@config[:require]}/config/application.rb"))
|
|
@@ -332,10 +351,6 @@ module Sidekiq # :nodoc:
|
|
|
332
351
|
opts[:concurrency] = Integer(arg)
|
|
333
352
|
end
|
|
334
353
|
|
|
335
|
-
o.on "-d", "--daemon", "Daemonize process" do |arg|
|
|
336
|
-
puts "ERROR: Daemonization mode was removed in Sidekiq 6.0, please use a proper process supervisor to start and manage your services"
|
|
337
|
-
end
|
|
338
|
-
|
|
339
354
|
o.on "-e", "--environment ENV", "Application environment" do |arg|
|
|
340
355
|
opts[:environment] = arg
|
|
341
356
|
end
|
|
@@ -345,8 +360,8 @@ module Sidekiq # :nodoc:
|
|
|
345
360
|
end
|
|
346
361
|
|
|
347
362
|
o.on "-q", "--queue QUEUE[,WEIGHT]", "Queues to process with optional weights" do |arg|
|
|
348
|
-
|
|
349
|
-
|
|
363
|
+
opts[:queues] ||= []
|
|
364
|
+
opts[:queues] << arg
|
|
350
365
|
end
|
|
351
366
|
|
|
352
367
|
o.on "-r", "--require [PATH|DIR]", "Location of Rails application with jobs or file to require" do |arg|
|
|
@@ -365,15 +380,7 @@ module Sidekiq # :nodoc:
|
|
|
365
380
|
opts[:config_file] = arg
|
|
366
381
|
end
|
|
367
382
|
|
|
368
|
-
o.on "-
|
|
369
|
-
puts "ERROR: Logfile redirection was removed in Sidekiq 6.0, Sidekiq will only log to STDOUT"
|
|
370
|
-
end
|
|
371
|
-
|
|
372
|
-
o.on "-P", "--pidfile PATH", "path to pidfile" do |arg|
|
|
373
|
-
puts "ERROR: PID file creation was removed in Sidekiq 6.0, please use a proper process supervisor to start and manage your services"
|
|
374
|
-
end
|
|
375
|
-
|
|
376
|
-
o.on "-V", "--version", "Print version and exit" do |arg|
|
|
383
|
+
o.on "-V", "--version", "Print version and exit" do
|
|
377
384
|
puts "Sidekiq #{Sidekiq::VERSION}"
|
|
378
385
|
die(0)
|
|
379
386
|
end
|
|
@@ -389,13 +396,19 @@ module Sidekiq # :nodoc:
|
|
|
389
396
|
end
|
|
390
397
|
|
|
391
398
|
def initialize_logger
|
|
392
|
-
|
|
399
|
+
if @config[:verbose] || ENV["DEBUG_INVOCATION"] == "1"
|
|
400
|
+
# DEBUG_INVOCATION is a systemd-ism triggered by
|
|
401
|
+
# RestartMode=debug. We turn on debugging when the
|
|
402
|
+
# sidekiq process crashes and is restarted with this flag.
|
|
403
|
+
@config.logger.level = ::Logger::DEBUG
|
|
404
|
+
end
|
|
393
405
|
end
|
|
394
406
|
|
|
395
407
|
def parse_config(path)
|
|
396
|
-
erb = ERB.new(File.read(path))
|
|
408
|
+
erb = ERB.new(File.read(path), trim_mode: "-")
|
|
397
409
|
erb.filename = File.expand_path(path)
|
|
398
|
-
|
|
410
|
+
require "yaml"
|
|
411
|
+
opts = YAML.safe_load(erb.result, permitted_classes: [Symbol], aliases: true) || {}
|
|
399
412
|
|
|
400
413
|
if opts.respond_to? :deep_symbolize_keys!
|
|
401
414
|
opts.deep_symbolize_keys!
|
|
@@ -406,31 +419,9 @@ module Sidekiq # :nodoc:
|
|
|
406
419
|
opts = opts.merge(opts.delete(environment.to_sym) || {})
|
|
407
420
|
opts.delete(:strict)
|
|
408
421
|
|
|
409
|
-
parse_queues(opts, opts.delete(:queues) || [])
|
|
410
|
-
|
|
411
422
|
opts
|
|
412
423
|
end
|
|
413
424
|
|
|
414
|
-
def load_yaml(src)
|
|
415
|
-
if Psych::VERSION > "4.0"
|
|
416
|
-
YAML.safe_load(src, permitted_classes: [Symbol], aliases: true)
|
|
417
|
-
else
|
|
418
|
-
YAML.load(src)
|
|
419
|
-
end
|
|
420
|
-
end
|
|
421
|
-
|
|
422
|
-
def parse_queues(opts, queues_and_weights)
|
|
423
|
-
queues_and_weights.each { |queue_and_weight| parse_queue(opts, *queue_and_weight) }
|
|
424
|
-
end
|
|
425
|
-
|
|
426
|
-
def parse_queue(opts, queue, weight = nil)
|
|
427
|
-
opts[:queues] ||= []
|
|
428
|
-
opts[:strict] = true if opts[:strict].nil?
|
|
429
|
-
raise ArgumentError, "queues: #{queue} cannot be defined twice" if opts[:queues].include?(queue)
|
|
430
|
-
[weight.to_i, 1].max.times { opts[:queues] << queue.to_s }
|
|
431
|
-
opts[:strict] = false if weight.to_i > 0
|
|
432
|
-
end
|
|
433
|
-
|
|
434
425
|
def rails_app?
|
|
435
426
|
defined?(::Rails) && ::Rails.respond_to?(:application)
|
|
436
427
|
end
|
|
@@ -438,4 +429,5 @@ module Sidekiq # :nodoc:
|
|
|
438
429
|
end
|
|
439
430
|
|
|
440
431
|
require "sidekiq/systemd"
|
|
441
|
-
require "sidekiq/metrics/tracking"
|
|
432
|
+
require "sidekiq/metrics/tracking"
|
|
433
|
+
require "sidekiq/job/interrupt_handler"
|