Module: Gitlab::SidekiqSignals

Defined in:
lib/gitlab/sidekiq_signals.rb

Overview

As a process group leader, we can ensure that children of sidekiq are killed at the same time as sidekiq itself, to stop long-lived children from being reparented to init and “escaping”. To do this, we override the default handlers used by sidekiq for INT and TERM signals

Constant Summary collapse

REPLACE_SIGNALS =
%w[INT TERM].freeze
SIDEKIQ_CHANGED_MESSAGE =
"Intercepting signal handlers: #{REPLACE_SIGNALS.join(", ")} failed. " \
"Sidekiq should have registered them, but appears not to have done so."

Class Method Summary collapse

Class Method Details

.blindly_signal_pgroup!(signal) ⇒ Object

The process group leader can forward INT and TERM signals to the whole group. However, the forwarded signal is also received by the leader, which could lead to an infinite loop. We can avoid this by temporarily ignoring the forwarded signal. This may cause us to miss some repeated signals from outside the process group, but that isn't fatal.


36
37
38
39
40
41
42
43
# File 'lib/gitlab/sidekiq_signals.rb', line 36

def self.blindly_signal_pgroup!(signal)
  old_trap = trap(signal, 'IGNORE')
  begin
    Process.kill(signal, 0)
  ensure
    trap(signal, old_trap)
  end
end

.install!(sidekiq_handlers) ⇒ Object


15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/gitlab/sidekiq_signals.rb', line 15

def self.install!(sidekiq_handlers)
  # This only works if we're process group leader
  return unless Process.getpgrp == Process.pid

  raise SIDEKIQ_CHANGED_MESSAGE unless
    REPLACE_SIGNALS == sidekiq_handlers.keys & REPLACE_SIGNALS

  REPLACE_SIGNALS.each do |signal|
    old_handler = sidekiq_handlers[signal]
    sidekiq_handlers[signal] = ->(cli) do
      blindly_signal_pgroup!(signal)
      old_handler.call(cli)
    end
  end
end