2018-10-20 14:00:19 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
module Gitlab
|
|
|
|
module Cluster
|
|
|
|
#
|
|
|
|
# LifecycleEvents lets Rails initializers register application startup hooks
|
|
|
|
# that are sensitive to forking. For example, to defer the creation of
|
|
|
|
# watchdog threads. This lets us abstract away the Unix process
|
|
|
|
# lifecycles of Unicorn, Sidekiq, Puma, Puma Cluster, etc.
|
|
|
|
#
|
2019-10-16 11:06:17 -04:00
|
|
|
# We have the following lifecycle events.
|
2018-10-20 14:00:19 -04:00
|
|
|
#
|
2019-11-07 10:06:33 -05:00
|
|
|
# - on_before_fork (on master process):
|
2019-10-16 11:06:17 -04:00
|
|
|
#
|
|
|
|
# Unicorn/Puma Cluster: This will be called exactly once,
|
|
|
|
# on startup, before the workers are forked. This is
|
|
|
|
# called in the PARENT/MASTER process.
|
|
|
|
#
|
2019-11-07 10:06:33 -05:00
|
|
|
# Sidekiq/Puma Single: This is not called.
|
2019-10-16 11:06:17 -04:00
|
|
|
#
|
2019-11-07 10:06:33 -05:00
|
|
|
# - on_master_start (on master process):
|
2019-10-16 11:06:17 -04:00
|
|
|
#
|
|
|
|
# Unicorn/Puma Cluster: This will be called exactly once,
|
|
|
|
# on startup, before the workers are forked. This is
|
|
|
|
# called in the PARENT/MASTER process.
|
|
|
|
#
|
2019-11-07 10:06:33 -05:00
|
|
|
# Sidekiq/Puma Single: This is called immediately.
|
2019-10-16 11:06:17 -04:00
|
|
|
#
|
2019-11-07 10:06:33 -05:00
|
|
|
# - on_before_blackout_period (on master process):
|
2019-10-16 11:06:17 -04:00
|
|
|
#
|
2019-11-07 10:06:33 -05:00
|
|
|
# Unicorn/Puma Cluster: This will be called before a blackout
|
|
|
|
# period when performing graceful shutdown of master.
|
|
|
|
# This is called on `master` process.
|
2019-10-16 11:06:17 -04:00
|
|
|
#
|
2019-11-07 10:06:33 -05:00
|
|
|
# Sidekiq/Puma Single: This is not called.
|
2019-10-16 11:06:17 -04:00
|
|
|
#
|
2019-11-07 10:06:33 -05:00
|
|
|
# - on_before_graceful_shutdown (on master process):
|
2019-10-16 11:06:17 -04:00
|
|
|
#
|
|
|
|
# Unicorn/Puma Cluster: This will be called before a graceful
|
2019-11-07 10:06:33 -05:00
|
|
|
# shutdown of workers starts happening, but after blackout period.
|
2019-10-16 11:06:17 -04:00
|
|
|
# This is called on `master` process.
|
|
|
|
#
|
|
|
|
# Sidekiq/Puma Single: This is not called.
|
|
|
|
#
|
2019-11-07 10:06:33 -05:00
|
|
|
# - on_before_master_restart (on master process):
|
2019-10-16 11:06:17 -04:00
|
|
|
#
|
|
|
|
# Unicorn: This will be called before a new master is spun up.
|
|
|
|
# This is called on forked master before `execve` to become
|
|
|
|
# a new masterfor Unicorn. This means that this does not really
|
|
|
|
# affect old master process.
|
|
|
|
#
|
|
|
|
# Puma Cluster: This will be called before a new master is spun up.
|
|
|
|
# This is called on `master` process.
|
|
|
|
#
|
|
|
|
# Sidekiq/Puma Single: This is not called.
|
2018-10-20 14:00:19 -04:00
|
|
|
#
|
2019-11-07 10:06:33 -05:00
|
|
|
# - on_worker_start (on worker process):
|
|
|
|
#
|
|
|
|
# Unicorn/Puma Cluster: This is called in the worker process
|
|
|
|
# exactly once before processing requests.
|
|
|
|
#
|
|
|
|
# Sidekiq/Puma Single: This is called immediately.
|
|
|
|
#
|
2018-10-20 14:00:19 -04:00
|
|
|
# Blocks will be executed in the order in which they are registered.
|
|
|
|
#
|
|
|
|
class LifecycleEvents
|
|
|
|
class << self
|
|
|
|
#
|
|
|
|
# Hook registration methods (called from initializers)
|
|
|
|
#
|
|
|
|
def on_worker_start(&block)
|
|
|
|
if in_clustered_environment?
|
|
|
|
# Defer block execution
|
|
|
|
(@worker_start_hooks ||= []) << block
|
|
|
|
else
|
|
|
|
yield
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def on_before_fork(&block)
|
|
|
|
# Defer block execution
|
|
|
|
(@before_fork_hooks ||= []) << block
|
|
|
|
end
|
|
|
|
|
2019-11-07 10:06:33 -05:00
|
|
|
# Read the config/initializers/cluster_events_before_phased_restart.rb
|
|
|
|
def on_before_blackout_period(&block)
|
|
|
|
# Defer block execution
|
|
|
|
(@master_blackout_period ||= []) << block
|
|
|
|
end
|
|
|
|
|
2019-10-16 11:06:17 -04:00
|
|
|
# Read the config/initializers/cluster_events_before_phased_restart.rb
|
2019-10-30 05:27:58 -04:00
|
|
|
def on_before_graceful_shutdown(&block)
|
2019-10-16 11:06:17 -04:00
|
|
|
# Defer block execution
|
2019-10-30 05:27:58 -04:00
|
|
|
(@master_graceful_shutdown ||= []) << block
|
2019-10-16 11:06:17 -04:00
|
|
|
end
|
2018-10-20 14:00:19 -04:00
|
|
|
|
2019-10-16 11:06:17 -04:00
|
|
|
def on_before_master_restart(&block)
|
2018-10-20 14:00:19 -04:00
|
|
|
# Defer block execution
|
|
|
|
(@master_restart_hooks ||= []) << block
|
|
|
|
end
|
|
|
|
|
2019-05-29 08:27:44 -04:00
|
|
|
def on_master_start(&block)
|
|
|
|
if in_clustered_environment?
|
|
|
|
on_before_fork(&block)
|
|
|
|
else
|
|
|
|
on_worker_start(&block)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-10-20 14:00:19 -04:00
|
|
|
#
|
|
|
|
# Lifecycle integration methods (called from unicorn.rb, puma.rb, etc.)
|
|
|
|
#
|
|
|
|
def do_worker_start
|
2019-11-07 10:06:33 -05:00
|
|
|
call(@worker_start_hooks)
|
2018-10-20 14:00:19 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def do_before_fork
|
2019-11-07 10:06:33 -05:00
|
|
|
call(@before_fork_hooks)
|
2018-10-20 14:00:19 -04:00
|
|
|
end
|
|
|
|
|
2019-10-30 05:27:58 -04:00
|
|
|
def do_before_graceful_shutdown
|
2019-11-07 10:06:33 -05:00
|
|
|
call(@master_blackout_period)
|
|
|
|
|
|
|
|
blackout_seconds = ::Settings.shutdown.blackout_seconds.to_i
|
|
|
|
sleep(blackout_seconds) if blackout_seconds > 0
|
|
|
|
|
|
|
|
call(@master_graceful_shutdown)
|
2019-10-16 11:06:17 -04:00
|
|
|
end
|
|
|
|
|
2019-10-04 02:06:05 -04:00
|
|
|
def do_before_master_restart
|
2019-11-07 10:06:33 -05:00
|
|
|
call(@master_restart_hooks)
|
2018-10-20 14:00:19 -04:00
|
|
|
end
|
|
|
|
|
2019-10-04 02:06:05 -04:00
|
|
|
# DEPRECATED
|
|
|
|
alias_method :do_master_restart, :do_before_master_restart
|
|
|
|
|
2018-10-20 14:00:19 -04:00
|
|
|
# Puma doesn't use singletons (which is good) but
|
|
|
|
# this means we need to pass through whether the
|
|
|
|
# puma server is running in single mode or cluster mode
|
|
|
|
def set_puma_options(options)
|
|
|
|
@puma_options = options
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
2019-11-07 10:06:33 -05:00
|
|
|
def call(hooks)
|
|
|
|
hooks&.each(&:call)
|
|
|
|
end
|
|
|
|
|
2018-10-20 14:00:19 -04:00
|
|
|
def in_clustered_environment?
|
|
|
|
# Sidekiq doesn't fork
|
2019-12-22 04:07:51 -05:00
|
|
|
return false if Gitlab::Runtime.sidekiq?
|
2018-10-20 14:00:19 -04:00
|
|
|
|
|
|
|
# Unicorn always forks
|
2019-12-22 04:07:51 -05:00
|
|
|
return true if Gitlab::Runtime.unicorn?
|
2018-10-20 14:00:19 -04:00
|
|
|
|
|
|
|
# Puma sometimes forks
|
|
|
|
return true if in_clustered_puma?
|
|
|
|
|
|
|
|
# Default assumption is that we don't fork
|
|
|
|
false
|
|
|
|
end
|
|
|
|
|
|
|
|
def in_clustered_puma?
|
2019-12-22 04:07:51 -05:00
|
|
|
return false unless Gitlab::Runtime.puma?
|
2018-10-20 14:00:19 -04:00
|
|
|
|
|
|
|
@puma_options && @puma_options[:workers] && @puma_options[:workers] > 0
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|