117 lines
2.8 KiB
Ruby
117 lines
2.8 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'spec_helper'
|
|
|
|
# For easier debugging set `UNICORN_DEBUG=1`
|
|
|
|
RSpec.describe Gitlab::Cluster::Mixins::UnicornHttpServer do
|
|
before do
|
|
stub_const('UNICORN_STARTUP_TIMEOUT', 30)
|
|
end
|
|
|
|
context 'when running Unicorn' do
|
|
using RSpec::Parameterized::TableSyntax
|
|
|
|
where(:signal, :exitstatus, :termsig) do
|
|
# executes phased restart block
|
|
:USR2 | 140 | nil
|
|
:QUIT | 140 | nil
|
|
|
|
# does not execute phased restart block
|
|
:INT | 0 | nil
|
|
:TERM | 0 | nil
|
|
end
|
|
|
|
with_them do
|
|
it 'properly handles process lifecycle' do
|
|
with_unicorn(workers: 1) do |pid|
|
|
Process.kill(signal, pid)
|
|
|
|
child_pid, child_status = Process.wait2(pid)
|
|
expect(child_pid).to eq(pid)
|
|
expect(child_status.exitstatus).to eq(exitstatus)
|
|
expect(child_status.termsig).to eq(termsig)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def with_unicorn(workers:, timeout: UNICORN_STARTUP_TIMEOUT)
|
|
with_unicorn_configs(workers: workers) do |unicorn_rb, config_ru|
|
|
cmdline = [
|
|
"bundle", "exec", "unicorn",
|
|
"-I", Rails.root.to_s,
|
|
"-c", unicorn_rb,
|
|
config_ru
|
|
]
|
|
|
|
IO.popen(cmdline) do |process|
|
|
# wait for process to start:
|
|
# I, [2019-10-15T13:21:27.565225 #3089] INFO -- : master process ready
|
|
wait_for_output(process, /master process ready/, timeout: timeout)
|
|
consume_output(process)
|
|
|
|
yield(process.pid)
|
|
ensure
|
|
begin
|
|
Process.kill(:KILL, process.pid)
|
|
rescue Errno::ESRCH
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
def with_unicorn_configs(workers:)
|
|
Dir.mktmpdir do |dir|
|
|
File.write "#{dir}/unicorn.rb", <<-EOF
|
|
require './lib/gitlab/cluster/lifecycle_events'
|
|
require './lib/gitlab/cluster/mixins/unicorn_http_server'
|
|
|
|
worker_processes #{workers}
|
|
listen "127.0.0.1:0"
|
|
preload_app true
|
|
|
|
Unicorn::HttpServer.prepend(#{described_class})
|
|
|
|
mutex = Mutex.new
|
|
|
|
Gitlab::Cluster::LifecycleEvents.on_before_blackout_period do
|
|
mutex.synchronize do
|
|
exit(140)
|
|
end
|
|
end
|
|
|
|
# redirect stderr to stdout
|
|
$stderr.reopen($stdout)
|
|
EOF
|
|
|
|
File.write "#{dir}/config.ru", <<-EOF
|
|
run -> (env) { [404, {}, ['']] }
|
|
EOF
|
|
|
|
yield("#{dir}/unicorn.rb", "#{dir}/config.ru")
|
|
end
|
|
end
|
|
|
|
def wait_for_output(process, output, timeout:)
|
|
Timeout.timeout(timeout) do
|
|
loop do
|
|
line = process.readline
|
|
puts "UNICORN_DEBUG: #{line}" if ENV['UNICORN_DEBUG']
|
|
break if line =~ output
|
|
end
|
|
end
|
|
end
|
|
|
|
def consume_output(process)
|
|
Thread.new do
|
|
loop do
|
|
line = process.readline
|
|
puts "UNICORN_DEBUG: #{line}" if ENV['UNICORN_DEBUG']
|
|
end
|
|
rescue
|
|
end
|
|
end
|
|
end
|