Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-05-19 18:44:42 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-05-19 18:44:42 +0300
commit4555e1b21c365ed8303ffb7a3325d773c9b8bf31 (patch)
tree5423a1c7516cffe36384133ade12572cf709398d /config/initializers
parente570267f2f6b326480d284e0164a6464ba4081bc (diff)
Add latest changes from gitlab-org/gitlab@13-12-stable-eev13.12.0-rc42
Diffstat (limited to 'config/initializers')
-rw-r--r--config/initializers/01_secret_token.rb2
-rw-r--r--config/initializers/0_inject_enterprise_edition_module.rb66
-rw-r--r--config/initializers/0_license.rb2
-rw-r--r--config/initializers/1_settings.rb18
-rw-r--r--config/initializers/active_record_preloader.rb2
-rw-r--r--config/initializers/active_record_renamed_table.rb5
-rw-r--r--config/initializers/database_config.rb14
-rw-r--r--config/initializers/declarative_policy.rb5
-rw-r--r--config/initializers/geo.rb2
-rw-r--r--config/initializers/gitlab_workhorse_secret.rb2
-rw-r--r--config/initializers/postgres_cte_as_materialized.rb2
-rw-r--r--config/initializers/postgres_partitioning.rb2
-rw-r--r--config/initializers/puma_client_tempfile_patch.rb146
-rw-r--r--config/initializers/request_profiler.rb1
-rw-r--r--config/initializers/rspec_profiling.rb2
-rw-r--r--config/initializers/session_store.rb2
-rw-r--r--config/initializers/stackprof.rb135
17 files changed, 152 insertions, 256 deletions
diff --git a/config/initializers/01_secret_token.rb b/config/initializers/01_secret_token.rb
index c4520b4b313..c1f03dfdb07 100644
--- a/config/initializers/01_secret_token.rb
+++ b/config/initializers/01_secret_token.rb
@@ -44,7 +44,7 @@ def create_tokens
begin
File.delete(secret_file) if file_secret_key
- rescue => e
+ rescue StandardError => e
warn "Error deleting useless .secret file: #{e}"
end
end
diff --git a/config/initializers/0_inject_enterprise_edition_module.rb b/config/initializers/0_inject_enterprise_edition_module.rb
index f9c82f45040..ea3fbda9186 100644
--- a/config/initializers/0_inject_enterprise_edition_module.rb
+++ b/config/initializers/0_inject_enterprise_edition_module.rb
@@ -3,38 +3,36 @@
require 'active_support/inflector'
module InjectEnterpriseEditionModule
- def prepend_if_ee(constant, with_descendants: false)
- return unless Gitlab.ee?
-
- prepend_module(constant.constantize, with_descendants)
- end
-
- def extend_if_ee(constant)
- extend(constant.constantize) if Gitlab.ee?
+ def prepend_mod_with(constant_name, namespace: Object, with_descendants: false)
+ each_extension_for(constant_name, namespace) do |constant|
+ prepend_module(constant, with_descendants)
+ end
end
- def include_if_ee(constant)
- include(constant.constantize) if Gitlab.ee?
+ def extend_mod_with(constant_name, namespace: Object)
+ each_extension_for(
+ constant_name,
+ namespace,
+ &method(:extend))
end
- def prepend_ee_mod(with_descendants: false)
- return unless Gitlab.ee?
-
- prepend_module(ee_module, with_descendants)
+ def include_mod_with(constant_name, namespace: Object)
+ each_extension_for(
+ constant_name,
+ namespace,
+ &method(:include))
end
- def extend_ee_mod
- extend(ee_module) if Gitlab.ee?
+ def prepend_mod(with_descendants: false)
+ prepend_mod_with(name, with_descendants: with_descendants) # rubocop: disable Cop/InjectEnterpriseEditionModule
end
- def include_ee_mod
- include(ee_module) if Gitlab.ee?
+ def extend_mod
+ extend_mod_with(name) # rubocop: disable Cop/InjectEnterpriseEditionModule
end
- def prepend_if_jh(constant, with_descendants: false)
- return unless Gitlab.jh?
-
- prepend_module(constant.constantize, with_descendants)
+ def include_mod
+ include_mod_with(name) # rubocop: disable Cop/InjectEnterpriseEditionModule
end
private
@@ -47,8 +45,28 @@ module InjectEnterpriseEditionModule
end
end
- def ee_module
- ::EE.const_get(name, false)
+ def each_extension_for(constant_name, namespace)
+ Gitlab.extensions.each do |extension_name|
+ extension_namespace =
+ const_get_maybe_false(namespace, extension_name.upcase)
+
+ extension_module =
+ const_get_maybe_false(extension_namespace, constant_name)
+
+ yield(extension_module) if extension_module
+ end
+ end
+
+ def const_get_maybe_false(mod, name)
+ # We're still heavily relying on Rails autoloading instead of zeitwerk,
+ # therefore this check: `mod.const_defined?(name, false)`
+ # Is not reliable, which may return false while it's defined.
+ # After we moved everything over to zeitwerk we can avoid rescuing
+ # NameError and just check if const_defined?
+ # mod && mod.const_defined?(name, false) && mod.const_get(name, false)
+ mod && mod.const_get(name, false)
+ rescue NameError
+ false
end
end
diff --git a/config/initializers/0_license.rb b/config/initializers/0_license.rb
index 3db5ec0a91a..c1a2048b28d 100644
--- a/config/initializers/0_license.rb
+++ b/config/initializers/0_license.rb
@@ -5,7 +5,7 @@ load_license = lambda do |dir:, license_name:|
public_key_file = File.read(Rails.root.join(dir, ".#{prefix}license_encryption_key.pub"))
public_key = OpenSSL::PKey::RSA.new(public_key_file)
Gitlab::License.encryption_key = public_key
-rescue
+rescue StandardError
warn "WARNING: No valid #{license_name} encryption key provided."
end
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index 99335321f28..8d5e19afc20 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -564,11 +564,17 @@ Settings.cron_jobs['ssh_keys_expired_notification_worker'] ||= Settingslogic.new
Settings.cron_jobs['ssh_keys_expired_notification_worker']['cron'] ||= '0 2 * * *'
Settings.cron_jobs['ssh_keys_expired_notification_worker']['job_class'] = 'SshKeys::ExpiredNotificationWorker'
Settings.cron_jobs['namespaces_in_product_marketing_emails_worker'] ||= Settingslogic.new({})
-Settings.cron_jobs['namespaces_in_product_marketing_emails_worker']['cron'] ||= '0 9 * * *'
+Settings.cron_jobs['namespaces_in_product_marketing_emails_worker']['cron'] ||= '0 16 * * *'
Settings.cron_jobs['namespaces_in_product_marketing_emails_worker']['job_class'] = 'Namespaces::InProductMarketingEmailsWorker'
Settings.cron_jobs['ssh_keys_expiring_soon_notification_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['ssh_keys_expiring_soon_notification_worker']['cron'] ||= '0 1 * * *'
Settings.cron_jobs['ssh_keys_expiring_soon_notification_worker']['job_class'] = 'SshKeys::ExpiringSoonNotificationWorker'
+Settings.cron_jobs['users_deactivate_dormant_users_worker'] ||= Settingslogic.new({})
+Settings.cron_jobs['users_deactivate_dormant_users_worker']['cron'] ||= '21,42 0-4 * * *'
+Settings.cron_jobs['users_deactivate_dormant_users_worker']['job_class'] = 'Users::DeactivateDormantUsersWorker'
+Settings.cron_jobs['ci_delete_unit_tests_worker'] ||= Settingslogic.new({})
+Settings.cron_jobs['ci_delete_unit_tests_worker']['cron'] ||= '0 0 * * *'
+Settings.cron_jobs['ci_delete_unit_tests_worker']['job_class'] = 'Ci::DeleteUnitTestsWorker'
Gitlab.com do
Settings.cron_jobs['batched_background_migrations_worker'] ||= Settingslogic.new({})
@@ -668,7 +674,7 @@ Gitlab.ee do
Settings.cron_jobs['elastic_migration_worker']['cron'] ||= '*/30 * * * *'
Settings.cron_jobs['elastic_migration_worker']['job_class'] ||= 'Elastic::MigrationWorker'
Settings.cron_jobs['sync_seat_link_worker'] ||= Settingslogic.new({})
- Settings.cron_jobs['sync_seat_link_worker']['cron'] ||= "#{rand(60)} 0 * * *"
+ Settings.cron_jobs['sync_seat_link_worker']['cron'] ||= "#{rand(60)} 3 * * * UTC"
Settings.cron_jobs['sync_seat_link_worker']['job_class'] = 'SyncSeatLinkWorker'
Settings.cron_jobs['web_application_firewall_metrics_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['web_application_firewall_metrics_worker']['cron'] ||= '0 1 * * 0'
@@ -688,6 +694,12 @@ Gitlab.ee do
Settings.cron_jobs['vulnerability_historical_statistics_deletion_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['vulnerability_historical_statistics_deletion_worker']['cron'] ||= '15 3 * * *'
Settings.cron_jobs['vulnerability_historical_statistics_deletion_worker']['job_class'] = 'Vulnerabilities::HistoricalStatistics::DeletionWorker'
+ Settings.cron_jobs['security_create_orchestration_policy_worker'] ||= Settingslogic.new({})
+ Settings.cron_jobs['security_create_orchestration_policy_worker']['cron'] ||= '*/10 * * * *'
+ Settings.cron_jobs['security_create_orchestration_policy_worker']['job_class'] = 'Security::CreateOrchestrationPolicyWorker'
+ Settings.cron_jobs['security_orchestration_policy_rule_schedule_worker'] ||= Settingslogic.new({})
+ Settings.cron_jobs['security_orchestration_policy_rule_schedule_worker']['cron'] ||= '*/15 * * * *'
+ Settings.cron_jobs['security_orchestration_policy_rule_schedule_worker']['job_class'] = 'Security::OrchestrationPolicyRuleScheduleWorker'
end
#
@@ -695,6 +707,7 @@ end
#
Settings['sidekiq'] ||= Settingslogic.new({})
Settings['sidekiq']['log_format'] ||= 'default'
+Settings['sidekiq']['routing_rules'] ||= []
#
# GitLab Shell
@@ -852,6 +865,7 @@ Settings['extra'] ||= Settingslogic.new({})
Settings.extra['matomo_site_id'] ||= Settings.extra['piwik_site_id'] if Settings.extra['piwik_site_id'].present?
Settings.extra['matomo_url'] ||= Settings.extra['piwik_url'] if Settings.extra['piwik_url'].present?
Settings.extra['matomo_disable_cookies'] = false if Settings.extra['matomo_disable_cookies'].nil?
+Settings.extra['maximum_text_highlight_size_kilobytes'] = Settings.extra.fetch('maximum_text_highlight_size_kilobytes', 512).kilobytes
#
# Rack::Attack settings
diff --git a/config/initializers/active_record_preloader.rb b/config/initializers/active_record_preloader.rb
index 257a8a9e955..198c97cb849 100644
--- a/config/initializers/active_record_preloader.rb
+++ b/config/initializers/active_record_preloader.rb
@@ -4,7 +4,7 @@ module ActiveRecord
module Associations
class Preloader
class NullPreloader
- def self.new(klass, owners, reflection, preload_scope)
+ def self.new(*args, **kwargs)
self
end
diff --git a/config/initializers/active_record_renamed_table.rb b/config/initializers/active_record_renamed_table.rb
new file mode 100644
index 00000000000..948ef8790c8
--- /dev/null
+++ b/config/initializers/active_record_renamed_table.rb
@@ -0,0 +1,5 @@
+# frozen_string_literal: true
+
+ActiveSupport.on_load(:active_record) do
+ ActiveRecord::ConnectionAdapters::SchemaCache.prepend(Gitlab::Database::SchemaCacheWithRenamedTable)
+end
diff --git a/config/initializers/database_config.rb b/config/initializers/database_config.rb
index a91f67224d7..6637080c038 100644
--- a/config/initializers/database_config.rb
+++ b/config/initializers/database_config.rb
@@ -20,25 +20,15 @@ Gitlab.ee do
end
end
-# We configure the database connection pool size automatically based on the
-# configured concurrency. We also add some headroom, to make sure we don't run
-# out of connections when more threads besides the 'user-facing' ones are
-# running.
-#
-# Read more about this in doc/development/database/client_side_connection_pool.md
-
-headroom = (ENV["DB_POOL_HEADROOM"].presence || 10).to_i
-calculated_pool_size = Gitlab::Runtime.max_threads + headroom
-
db_config = Gitlab::Database.config ||
Rails.application.config.database_configuration[Rails.env]
-db_config['pool'] = calculated_pool_size
+db_config['pool'] = Gitlab::Database.default_pool_size
ActiveRecord::Base.establish_connection(db_config)
Gitlab.ee do
if Gitlab::Runtime.sidekiq? && Gitlab::Geo.geo_database_configured?
- Rails.configuration.geo_database['pool'] = calculated_pool_size
+ Rails.configuration.geo_database['pool'] = Gitlab::Database.default_pool_size
Geo::TrackingBase.establish_connection(Rails.configuration.geo_database)
end
end
diff --git a/config/initializers/declarative_policy.rb b/config/initializers/declarative_policy.rb
new file mode 100644
index 00000000000..49267584809
--- /dev/null
+++ b/config/initializers/declarative_policy.rb
@@ -0,0 +1,5 @@
+# frozen_string_literal: true
+
+DeclarativePolicy.configure do
+ named_policy :global, ::GlobalPolicy
+end
diff --git a/config/initializers/geo.rb b/config/initializers/geo.rb
index 3278dc9e484..e0530f43899 100644
--- a/config/initializers/geo.rb
+++ b/config/initializers/geo.rb
@@ -4,6 +4,6 @@ Gitlab.ee do
if Gitlab::Geo.connected? && Gitlab::Geo.primary?
Gitlab::Geo.current_node&.update_clone_url!
end
-rescue => e
+rescue StandardError => e
warn "WARNING: Unable to check/update clone_url_prefix for Geo: #{e}"
end
diff --git a/config/initializers/gitlab_workhorse_secret.rb b/config/initializers/gitlab_workhorse_secret.rb
index 5c959a72bd1..88fabe50e83 100644
--- a/config/initializers/gitlab_workhorse_secret.rb
+++ b/config/initializers/gitlab_workhorse_secret.rb
@@ -2,7 +2,7 @@
begin
Gitlab::Workhorse.secret
-rescue
+rescue StandardError
Gitlab::Workhorse.write_secret
end
diff --git a/config/initializers/postgres_cte_as_materialized.rb b/config/initializers/postgres_cte_as_materialized.rb
index 85b3361e25e..fd6e7b48c25 100644
--- a/config/initializers/postgres_cte_as_materialized.rb
+++ b/config/initializers/postgres_cte_as_materialized.rb
@@ -6,7 +6,7 @@ module Arel
class Arel::Visitors::PostgreSQL
def visit_Gitlab_Database_AsWithMaterialized(obj, collector) # rubocop:disable Naming/MethodName
collector = visit obj.left, collector
- collector << " AS#{obj.expr} "
+ collector << " AS "
visit obj.right, collector
end
end
diff --git a/config/initializers/postgres_partitioning.rb b/config/initializers/postgres_partitioning.rb
index 6b64ea3f83d..787e46c2405 100644
--- a/config/initializers/postgres_partitioning.rb
+++ b/config/initializers/postgres_partitioning.rb
@@ -4,7 +4,7 @@
# (even with eager loading disabled).
Gitlab::Database::Partitioning::PartitionCreator.register(AuditEvent)
-Gitlab::Database::Partitioning::PartitionCreator.register(WebHookLogPartitioned)
+Gitlab::Database::Partitioning::PartitionCreator.register(WebHookLog)
begin
Gitlab::Database::Partitioning::PartitionCreator.new.create_partitions unless ENV['DISABLE_POSTGRES_PARTITION_CREATION_ON_STARTUP']
diff --git a/config/initializers/puma_client_tempfile_patch.rb b/config/initializers/puma_client_tempfile_patch.rb
index e1faa21804f..972eeaf0c83 100644
--- a/config/initializers/puma_client_tempfile_patch.rb
+++ b/config/initializers/puma_client_tempfile_patch.rb
@@ -1,101 +1,99 @@
# frozen_string_literal: true
if Gitlab::Runtime.puma?
+ # This patch represents https://github.com/puma/puma/pull/2613. If
+ # this PR is accepted in the next Puma release, we can remove this
+ # entire file.
+ #
+ # The patch itself is quite large because the tempfile creation in
+ # Puma is inside these fairly long methods. The actual changes are
+ # just two lines, commented with 'GitLab' to make them easier to find.
raise "Remove this monkey patch: #{__FILE__}" unless Puma::Const::VERSION == '5.1.1'
- if ENV['GITLAB_TEMPFILE_IMMEDIATE_UNLINK'] == '1'
- # This is copied from https://github.com/puma/puma/blob/v5.1.1/lib/puma/client.rb,
- # with two additions: both times we create a temporary file, we immediately
- # call `#unlink`. This means that if the process gets terminated without being
- # able to clean up itself, the temporary file will not linger on the file
- # system. We will try to get this patch accepted upstream if it works for us
- # (we just need to check if the temporary file responds to `#unlink` as that
- # won't work on Windows, for instance).
- module Puma
- class Client
- private
-
- def setup_body
- @body_read_start = Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond)
-
- if @env[HTTP_EXPECT] == CONTINUE
- # TODO allow a hook here to check the headers before
- # going forward
- @io << HTTP_11_100
- @io.flush
- end
+ module Puma
+ class Client
+ private
+
+ def setup_body
+ @body_read_start = Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond)
- @read_header = false
+ if @env[HTTP_EXPECT] == CONTINUE
+ # TODO allow a hook here to check the headers before
+ # going forward
+ @io << HTTP_11_100
+ @io.flush
+ end
- body = @parser.body
+ @read_header = false
- te = @env[TRANSFER_ENCODING2]
+ body = @parser.body
- if te
- if te.include?(",")
- te.split(",").each do |part|
- if CHUNKED.casecmp(part.strip) == 0 # rubocop:disable Metrics/BlockNesting
- return setup_chunked_body(body)
- end
+ te = @env[TRANSFER_ENCODING2]
+
+ if te
+ if te.include?(",")
+ te.split(",").each do |part|
+ if CHUNKED.casecmp(part.strip) == 0 # rubocop:disable Metrics/BlockNesting
+ return setup_chunked_body(body)
end
- elsif CHUNKED.casecmp(te) == 0
- return setup_chunked_body(body)
end
+ elsif CHUNKED.casecmp(te) == 0
+ return setup_chunked_body(body)
end
+ end
- @chunked_body = false
+ @chunked_body = false
- cl = @env[CONTENT_LENGTH]
+ cl = @env[CONTENT_LENGTH]
- unless cl
- @buffer = body.empty? ? nil : body
- @body = EmptyBody
- set_ready
- return true
- end
+ unless cl
+ @buffer = body.empty? ? nil : body
+ @body = EmptyBody
+ set_ready
+ return true
+ end
- remain = cl.to_i - body.bytesize
+ remain = cl.to_i - body.bytesize
- if remain <= 0
- @body = StringIO.new(body)
- @buffer = nil
- set_ready
- return true
- end
+ if remain <= 0
+ @body = StringIO.new(body)
+ @buffer = nil
+ set_ready
+ return true
+ end
- if remain > MAX_BODY
- @body = Tempfile.new(Const::PUMA_TMP_BASE)
- @body.binmode
- @body.unlink # This is the changed part
- @tempfile = @body
- else
- # The body[0,0] trick is to get an empty string in the same
- # encoding as body.
- @body = StringIO.new body[0,0] # rubocop:disable Layout/SpaceAfterComma
- end
+ if remain > MAX_BODY
+ @body = Tempfile.new(Const::PUMA_TMP_BASE)
+ @body.binmode
+ @body.unlink # GitLab: this is the changed part
+ @tempfile = @body
+ else
+ # The body[0,0] trick is to get an empty string in the same
+ # encoding as body.
+ @body = StringIO.new body[0,0] # rubocop:disable Layout/SpaceAfterComma
+ end
- @body.write body
+ @body.write body
- @body_remain = remain
+ @body_remain = remain
- return false # rubocop:disable Style/RedundantReturn
- end
+ return false # rubocop:disable Style/RedundantReturn
+ end
- def setup_chunked_body(body)
- @chunked_body = true
- @partial_part_left = 0
- @prev_chunk = ""
+ def setup_chunked_body(body)
+ @chunked_body = true
+ @partial_part_left = 0
+ @prev_chunk = ""
- @body = Tempfile.new(Const::PUMA_TMP_BASE)
- @body.binmode
- @body.unlink # This is the changed part
- @tempfile = @body
- @chunked_content_length = 0
+ @body = Tempfile.new(Const::PUMA_TMP_BASE)
+ @body.binmode
+ @body.unlink # GitLab: this is the changed part
+ @tempfile = @body
+ @chunked_content_length = 0
- if decode_chunk(body)
- @env[CONTENT_LENGTH] = @chunked_content_length
- return true # rubocop:disable Style/RedundantReturn
- end
+ if decode_chunk(body)
+ @env[CONTENT_LENGTH] = @chunked_content_length
+ return true # rubocop:disable Style/RedundantReturn
end
end
end
diff --git a/config/initializers/request_profiler.rb b/config/initializers/request_profiler.rb
index 8e426772b9a..2eb9f53d2a3 100644
--- a/config/initializers/request_profiler.rb
+++ b/config/initializers/request_profiler.rb
@@ -2,4 +2,5 @@
Rails.application.configure do |config|
config.middleware.use(Gitlab::RequestProfiler::Middleware)
+ config.middleware.use(Gitlab::Middleware::Speedscope)
end
diff --git a/config/initializers/rspec_profiling.rb b/config/initializers/rspec_profiling.rb
index 2473dc1ff6c..1288fad8a94 100644
--- a/config/initializers/rspec_profiling.rb
+++ b/config/initializers/rspec_profiling.rb
@@ -43,7 +43,7 @@ module RspecProfilingExt
module Run
def example_finished(*args)
super
- rescue => err
+ rescue StandardError => err
return if @already_logged_example_finished_error # rubocop:disable Gitlab/ModuleWithInstanceVariables
warn "rspec_profiling couldn't collect an example: #{err}. Further warnings suppressed."
diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb
index 6e0cd33aa96..530d7342d57 100644
--- a/config/initializers/session_store.rb
+++ b/config/initializers/session_store.rb
@@ -7,7 +7,7 @@ require 'gitlab/current_settings'
# allow it to fail: it may do so when create_from_defaults is executed before migrations are actually done
begin
Settings.gitlab['session_expire_delay'] = Gitlab::CurrentSettings.current_application_settings.session_expire_delay || 10080
-rescue
+rescue StandardError
Settings.gitlab['session_expire_delay'] ||= 10080
end
diff --git a/config/initializers/stackprof.rb b/config/initializers/stackprof.rb
index 4c4d241f065..4ff219cfda1 100644
--- a/config/initializers/stackprof.rb
+++ b/config/initializers/stackprof.rb
@@ -1,140 +1,5 @@
# frozen_string_literal: true
-# trigger stackprof by sending a SIGUSR2 signal
-#
-# Docs: https://docs.gitlab.com/ee/development/performance.html#production
-
-module Gitlab
- class StackProf
- DEFAULT_FILE_PREFIX = Dir.tmpdir
- DEFAULT_TIMEOUT_SEC = 30
- DEFAULT_MODE = :cpu
- # Sample interval as a frequency in microseconds (~100hz); appropriate for CPU profiles
- DEFAULT_INTERVAL_US = 10_000
- # Sample interval in event occurrences (n = every nth event); appropriate for allocation profiles
- DEFAULT_INTERVAL_EVENTS = 1_000
-
- # this is a workaround for sidekiq, which defines its own SIGUSR2 handler.
- # by defering to the sidekiq startup event, we get to set up our own
- # handler late enough.
- # see also: https://github.com/mperham/sidekiq/pull/4653
- def self.install
- require 'stackprof'
- require 'tmpdir'
-
- if Gitlab::Runtime.sidekiq?
- Sidekiq.configure_server do |config|
- config.on :startup do
- on_worker_start
- end
- end
- else
- Gitlab::Cluster::LifecycleEvents.on_worker_start do
- on_worker_start
- end
- end
- end
-
- def self.on_worker_start
- log_event('listening for SIGUSR2 signal')
-
- # create a pipe in order to propagate signal out of the signal handler
- # see also: https://cr.yp.to/docs/selfpipe.html
- read, write = IO.pipe
-
- # create a separate thread that polls for signals on the pipe.
- #
- # this way we do not execute in signal handler context, which
- # lifts restrictions and also serializes the calls in a thread-safe
- # manner.
- #
- # it's very similar to a goroutine and channel design.
- #
- # another nice benefit of this method is that we can timeout the
- # IO.select call, allowing the profile to automatically stop after
- # a given interval (by default 30 seconds), avoiding unbounded memory
- # growth from a profile that was started and never stopped.
- t = Thread.new do
- timeout_s = ENV['STACKPROF_TIMEOUT_S']&.to_i || DEFAULT_TIMEOUT_SEC
- current_timeout_s = nil
- loop do
- read.getbyte if IO.select([read], nil, nil, current_timeout_s)
-
- if ::StackProf.running?
- stackprof_file_prefix = ENV['STACKPROF_FILE_PREFIX'] || DEFAULT_FILE_PREFIX
- stackprof_out_file = "#{stackprof_file_prefix}/stackprof.#{Process.pid}.#{SecureRandom.hex(6)}.profile"
-
- log_event(
- 'stopping profile',
- profile_filename: stackprof_out_file,
- profile_timeout_s: timeout_s
- )
-
- ::StackProf.stop
- ::StackProf.results(stackprof_out_file)
- current_timeout_s = nil
- else
- mode = ENV['STACKPROF_MODE']&.to_sym || DEFAULT_MODE
- interval = ENV['STACKPROF_INTERVAL']&.to_i
- interval ||= (mode == :object ? DEFAULT_INTERVAL_EVENTS : DEFAULT_INTERVAL_US)
-
- log_event(
- 'starting profile',
- profile_mode: mode,
- profile_interval: interval,
- profile_timeout: timeout_s
- )
-
- ::StackProf.start(
- mode: mode,
- raw: Gitlab::Utils.to_boolean(ENV['STACKPROF_RAW'] || 'true'),
- interval: interval
- )
- current_timeout_s = timeout_s
- end
- end
- rescue => e
- log_event("stackprof failed: #{e}")
- end
- t.abort_on_exception = true
-
- # in the case of puma, this will override the existing SIGUSR2 signal handler
- # that can be used to trigger a restart.
- #
- # puma cluster has two types of restarts:
- # * SIGUSR1: phased restart
- # * SIGUSR2: restart
- #
- # phased restart is not supported in our configuration, because we use
- # preload_app. this means we will always perform a normal restart.
- # additionally, phased restart is not supported when sending a SIGUSR2
- # directly to a puma worker (as opposed to the master process).
- #
- # the result is that the behaviour of SIGUSR1 and SIGUSR2 is identical in
- # our configuration, and we can always use a SIGUSR1 to perform a restart.
- #
- # thus, it is acceptable for us to re-appropriate the SIGUSR2 signal, and
- # override the puma behaviour.
- #
- # see also:
- # * https://github.com/puma/puma/blob/master/docs/signals.md#puma-signals
- # * https://github.com/phusion/unicorn/blob/master/SIGNALS
- # * https://github.com/mperham/sidekiq/wiki/Signals
- Signal.trap('SIGUSR2') do
- write.write('.')
- end
- end
-
- def self.log_event(event, labels = {})
- Gitlab::AppJsonLogger.info({
- event: 'stackprof',
- message: event,
- pid: Process.pid
- }.merge(labels.compact))
- end
- end
-end
-
if Gitlab::Utils.to_boolean(ENV['STACKPROF_ENABLED'].to_s)
Gitlab::StackProf.install
end