Commit 3683ce9f authored by Aleksei Lipniagov's avatar Aleksei Lipniagov

Fix /-/readiness probe for Puma Single

Introduces `puma_in_clustered_mode?` check.
Introduces `.available?` for health checks.
Sets MasterCheck as not available for Puma in a Single mode.
parent 211062fa
---
title: Fix /-/readiness probe for Puma Single
merge_request: 53708
author:
type: other
......@@ -4,7 +4,7 @@ def max_puma_workers
Puma.cli_config.options[:workers].to_i
end
if Gitlab::Runtime.puma? && max_puma_workers == 0
if Gitlab::Runtime.puma? && !Gitlab::Runtime.puma_in_clustered_mode?
raise 'Puma is only supported in Clustered mode (workers > 0)' if Gitlab.com?
warn 'WARNING: Puma is running in Single mode (workers = 0). Some features may not work. Please refer to https://gitlab.com/groups/gitlab-org/-/epics/5303 for info.'
......
......@@ -11,6 +11,10 @@ module Gitlab
name.sub(/_check$/, '').capitalize
end
def available?
true
end
def readiness
raise NotImplementedError
end
......
......@@ -8,7 +8,16 @@ module Gitlab
extend SimpleAbstractCheck
class << self
extend ::Gitlab::Utils::Override
override :available?
def available?
Gitlab::Runtime.puma_in_clustered_mode?
end
def register_master
return unless available?
# when we fork, we pass the read pipe to child
# child can then react on whether the other end
# of pipe is still available
......@@ -16,11 +25,15 @@ module Gitlab
end
def finish_master
return unless available?
close_read
close_write
end
def register_worker
return unless available?
# fork needs to close the pipe
close_write
end
......
......@@ -48,6 +48,7 @@ module Gitlab
def probe_readiness
checks
.select(&:available?)
.flat_map(&:readiness)
.compact
.group_by(&:name)
......
......@@ -12,6 +12,10 @@ module Gitlab
Gitlab::HealthChecks::Result.new(
'web_exporter', exporter.running)
end
def available?
true
end
end
attr_reader :running
......
......@@ -81,6 +81,10 @@ module Gitlab
puma? || sidekiq? || action_cable?
end
def puma_in_clustered_mode?
puma? && Puma.cli_config.options[:workers].to_i > 0
end
def max_threads
threads = 1 # main thread
......
......@@ -4,11 +4,15 @@ require 'spec_helper'
require_relative './simple_check_shared'
RSpec.describe Gitlab::HealthChecks::MasterCheck do
let(:result_class) { Gitlab::HealthChecks::Result }
before do
stub_const('SUCCESS_CODE', 100)
stub_const('FAILURE_CODE', 101)
end
context 'when Puma runs in Clustered mode' do
before do
allow(Gitlab::Runtime).to receive(:puma_in_clustered_mode?).and_return(true)
described_class.register_master
end
......@@ -16,7 +20,11 @@ RSpec.describe Gitlab::HealthChecks::MasterCheck do
described_class.finish_master
end
describe '#readiness' do
describe '.available?' do
specify { expect(described_class.available?).to be true }
end
describe '.readiness' do
context 'when master is running' do
it 'worker does return success' do
_, child_status = run_worker
......@@ -47,4 +55,16 @@ RSpec.describe Gitlab::HealthChecks::MasterCheck do
Process.wait2(pid)
end
end
end
# '.readiness' check is not invoked if '.available?' returns false
context 'when Puma runs in Single mode' do
before do
allow(Gitlab::Runtime).to receive(:puma_in_clustered_mode?).and_return(false)
end
describe '.available?' do
specify { expect(described_class.available?).to be false }
end
end
end
......@@ -61,6 +61,35 @@ RSpec.describe Gitlab::HealthChecks::Probes::Collection do
expect(subject.json[:message]).to eq('Redis::CannotConnectError : Redis down')
end
end
context 'when some checks are not available' do
before do
allow(Gitlab::Runtime).to receive(:puma_in_clustered_mode?).and_return(false)
end
let(:checks) do
[
Gitlab::HealthChecks::MasterCheck
]
end
it 'asks for check availability' do
expect(Gitlab::HealthChecks::MasterCheck).to receive(:available?)
subject
end
it 'does not call `readiness` on checks that are not available' do
expect(Gitlab::HealthChecks::MasterCheck).not_to receive(:readiness)
subject
end
it 'does not fail collection check' do
expect(subject.http_status).to eq(200)
expect(subject.json[:status]).to eq('ok')
end
end
end
context 'without checks' do
......
......@@ -44,10 +44,11 @@ RSpec.describe Gitlab::Runtime do
context "puma" do
let(:puma_type) { double('::Puma') }
let(:max_workers) { 2 }
before do
stub_const('::Puma', puma_type)
allow(puma_type).to receive_message_chain(:cli_config, :options).and_return(max_threads: 2)
allow(puma_type).to receive_message_chain(:cli_config, :options).and_return(max_threads: 2, workers: max_workers)
stub_env('ACTION_CABLE_IN_APP', 'false')
end
......@@ -70,6 +71,20 @@ RSpec.describe Gitlab::Runtime do
it_behaves_like "valid runtime", :puma, 11
end
describe ".puma_in_clustered_mode?" do
context 'when Puma is set up with workers > 0' do
let(:max_workers) { 4 }
specify { expect(described_class.puma_in_clustered_mode?).to be true }
end
context 'when Puma is set up with workers = 0' do
let(:max_workers) { 0 }
specify { expect(described_class.puma_in_clustered_mode?).to be false }
end
end
end
context "unicorn" do
......
......@@ -77,6 +77,11 @@ RSpec.describe HealthController do
shared_context 'endpoint responding with readiness data' do
context 'when requesting instance-checks' do
context 'when Puma runs in Clustered mode' do
before do
allow(Gitlab::Runtime).to receive(:puma_in_clustered_mode?).and_return(true)
end
it 'responds with readiness checks data' do
expect(Gitlab::HealthChecks::MasterCheck).to receive(:check) { true }
......@@ -100,7 +105,23 @@ RSpec.describe HealthController do
end
end
context 'when Puma runs in Single mode' do
before do
allow(Gitlab::Runtime).to receive(:puma_in_clustered_mode?).and_return(false)
end
it 'does not invoke MasterCheck, succeedes' do
expect(Gitlab::HealthChecks::MasterCheck).not_to receive(:check) { true }
subject
expect(json_response).to eq('status' => 'ok')
end
end
end
context 'when requesting all checks' do
shared_context 'endpoint responding with readiness data for all checks' do
before do
params.merge!(all: true)
end
......@@ -164,6 +185,23 @@ RSpec.describe HealthController do
end
end
end
context 'when Puma runs in Clustered mode' do
before do
allow(Gitlab::Runtime).to receive(:puma_in_clustered_mode?).and_return(true)
end
it_behaves_like 'endpoint responding with readiness data for all checks'
end
context 'when Puma runs in Single mode' do
before do
allow(Gitlab::Runtime).to receive(:puma_in_clustered_mode?).and_return(false)
end
it_behaves_like 'endpoint responding with readiness data for all checks'
end
end
end
context 'accessed from whitelisted ip' do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment