1# frozen_string_literal: true
2
3module Gitlab
4  module HealthChecks
5    # This check is registered on master,
6    # and validated by worker
7    class MasterCheck
8      extend SimpleAbstractCheck
9
10      class << self
11        extend ::Gitlab::Utils::Override
12
13        override :available?
14        def available?
15          Gitlab::Runtime.puma_in_clustered_mode?
16        end
17
18        def register_master
19          return unless available?
20
21          # when we fork, we pass the read pipe to child
22          # child can then react on whether the other end
23          # of pipe is still available
24          @pipe_read, @pipe_write = IO.pipe
25        end
26
27        def finish_master
28          return unless available?
29
30          close_read
31          close_write
32        end
33
34        def register_worker
35          return unless available?
36
37          # fork needs to close the pipe
38          close_write
39        end
40
41        private
42
43        def close_read
44          @pipe_read&.close
45          @pipe_read = nil
46        end
47
48        def close_write
49          @pipe_write&.close
50          @pipe_write = nil
51        end
52
53        def metric_prefix
54          'master_check'
55        end
56
57        def successful?(result)
58          result
59        end
60
61        def check
62          # the lack of pipe is a legitimate failure of check
63          return false unless @pipe_read
64
65          @pipe_read.read_nonblock(1)
66
67          true
68        rescue IO::EAGAINWaitReadable
69          # if it is blocked, it means that the pipe is still open
70          # and there's no data waiting on it
71          true
72        rescue EOFError
73          # the pipe is closed
74          false
75        end
76      end
77    end
78  end
79end
80