summaryrefslogtreecommitdiff
path: root/config/initializers/sidekiq.rb
blob: b5d983990150a95b5f8ba9710368a8ae319a4e23 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
51
52
53
54
55
56
57
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
require 'sidekiq/web'

def enable_reliable_fetch?
  return true unless Feature::FlipperFeature.table_exists?

  Feature.enabled?(:gitlab_sidekiq_reliable_fetcher, default_enabled: true)
end

def enable_semi_reliable_fetch_mode?
  return true unless Feature::FlipperFeature.table_exists?

  Feature.enabled?(:gitlab_sidekiq_enable_semi_reliable_fetcher, default_enabled: true)
end

# Disable the Sidekiq Rack session since GitLab already has its own session store.
# CSRF protection still works (https://github.com/mperham/sidekiq/commit/315504e766c4fd88a29b7772169060afc4c40329).
Sidekiq::Web.set :sessions, false

# Custom Queues configuration
queues_config_hash = Gitlab::Redis::Queues.params
queues_config_hash[:namespace] = Gitlab::Redis::Queues::SIDEKIQ_NAMESPACE

# Default is to retry 25 times with exponential backoff. That's too much.
Sidekiq.default_worker_options = { retry: 3 }

if Rails.env.development?
  Sidekiq.default_worker_options[:backtrace] = true
end

enable_json_logs = Gitlab.config.sidekiq.log_format == 'json'
enable_sidekiq_memory_killer = ENV['SIDEKIQ_MEMORY_KILLER_MAX_RSS'].to_i.nonzero?
use_sidekiq_daemon_memory_killer = ENV["SIDEKIQ_DAEMON_MEMORY_KILLER"].to_i.nonzero?
use_sidekiq_legacy_memory_killer = !use_sidekiq_daemon_memory_killer

Sidekiq.configure_server do |config|
  config.redis = queues_config_hash

  config.server_middleware do |chain|
    chain.add Gitlab::SidekiqMiddleware::Monitor
    chain.add Gitlab::SidekiqMiddleware::Metrics if Settings.monitoring.sidekiq_exporter
    chain.add Gitlab::SidekiqMiddleware::ArgumentsLogger if ENV['SIDEKIQ_LOG_ARGUMENTS'] && !enable_json_logs
    chain.add Gitlab::SidekiqMiddleware::MemoryKiller if enable_sidekiq_memory_killer && use_sidekiq_legacy_memory_killer
    chain.add Gitlab::SidekiqMiddleware::RequestStoreMiddleware unless ENV['SIDEKIQ_REQUEST_STORE'] == '0'
    chain.add Gitlab::SidekiqMiddleware::BatchLoader
    chain.add Gitlab::SidekiqMiddleware::CorrelationLogger
    chain.add Gitlab::SidekiqMiddleware::InstrumentationLogger
    chain.add Gitlab::SidekiqStatus::ServerMiddleware
  end

  if enable_json_logs
    Sidekiq.logger.formatter = Gitlab::SidekiqLogging::JSONFormatter.new
    config.options[:job_logger] = Gitlab::SidekiqLogging::StructuredLogger

    # Remove the default-provided handler
    config.error_handlers.reject! { |handler| handler.is_a?(Sidekiq::ExceptionHandler::Logger) }
    config.error_handlers << Gitlab::SidekiqLogging::ExceptionHandler.new
  end

  config.client_middleware do |chain|
    chain.add Gitlab::SidekiqStatus::ClientMiddleware
    chain.add Gitlab::SidekiqMiddleware::CorrelationInjector
  end

  config.on :startup do
    # Clear any connections that might have been obtained before starting
    # Sidekiq (e.g. in an initializer).
    ActiveRecord::Base.clear_all_connections!

    # Start monitor to track running jobs. By default, cancel job is not enabled
    # To cancel job, it requires `SIDEKIQ_MONITOR_WORKER=1` to enable notification channel
    Gitlab::SidekiqDaemon::Monitor.instance.start

    Gitlab::SidekiqDaemon::MemoryKiller.instance.start if enable_sidekiq_memory_killer && use_sidekiq_daemon_memory_killer
  end

  if enable_reliable_fetch?
    config.options[:semi_reliable_fetch] = enable_semi_reliable_fetch_mode?
    Sidekiq::ReliableFetch.setup_reliable_fetch!(config)
  end

  # Sidekiq-cron: load recurring jobs from gitlab.yml
  # UGLY Hack to get nested hash from settingslogic
  cron_jobs = JSON.parse(Gitlab.config.cron_jobs.to_json)
  # UGLY hack: Settingslogic doesn't allow 'class' key
  cron_jobs_required_keys = %w(job_class cron)
  cron_jobs.each do |k, v|
    if cron_jobs[k] && cron_jobs_required_keys.all? { |s| cron_jobs[k].key?(s) }
      cron_jobs[k]['class'] = cron_jobs[k].delete('job_class')
    else
      cron_jobs.delete(k)
      Rails.logger.error("Invalid cron_jobs config key: '#{k}'. Check your gitlab config file.") # rubocop:disable Gitlab/RailsLogger
    end
  end
  Sidekiq::Cron::Job.load_from_hash! cron_jobs

  Gitlab::SidekiqVersioning.install!

  db_config = Gitlab::Database.config ||
    Rails.application.config.database_configuration[Rails.env]
  db_config['pool'] = Sidekiq.options[:concurrency]
  ActiveRecord::Base.establish_connection(db_config)
  Rails.logger.debug("Connection Pool size for Sidekiq Server is now: #{ActiveRecord::Base.connection.pool.instance_variable_get('@size')}") # rubocop:disable Gitlab/RailsLogger

  Gitlab.ee do
    Gitlab::Mirror.configure_cron_job!

    Gitlab::Geo.configure_cron_jobs!

    if Gitlab::Geo.geo_database_configured?
      Rails.configuration.geo_database['pool'] = Sidekiq.options[:concurrency]
      Geo::TrackingBase.establish_connection(Rails.configuration.geo_database)

      Rails.logger.debug("Connection Pool size for Sidekiq Server is now: #{Geo::TrackingBase.connection_pool.size} (Geo tracking database)") # rubocop:disable Gitlab/RailsLogger
    end
  end

  # Avoid autoload issue such as 'Mail::Parsers::AddressStruct'
  # https://github.com/mikel/mail/issues/912#issuecomment-214850355
  Mail.eager_autoload!

  # Ensure the whole process group is terminated if possible
  Gitlab::SidekiqSignals.install!(Sidekiq::CLI::SIGNAL_HANDLERS)
end

Sidekiq.configure_client do |config|
  config.redis = queues_config_hash

  config.client_middleware do |chain|
    chain.add Gitlab::SidekiqMiddleware::CorrelationInjector
    chain.add Gitlab::SidekiqStatus::ClientMiddleware
  end
end