BigW Consortium Gitlab

memory_killer.rb 1.77 KB
Newer Older
1 2 3
module Gitlab
  module SidekiqMiddleware
    class MemoryKiller
4 5
      # Default the RSS limit to 0, meaning the MemoryKiller is disabled
      MAX_RSS = (ENV['SIDEKIQ_MEMORY_KILLER_MAX_RSS'] || 0).to_s.to_i
6
      # Give Sidekiq 15 minutes of grace time after exceeding the RSS limit
7
      GRACE_TIME = (ENV['SIDEKIQ_MEMORY_KILLER_GRACE_TIME'] || 15 * 60).to_s.to_i
8
      # Wait 30 seconds for running jobs to finish during graceful shutdown
9 10 11 12
      SHUTDOWN_WAIT = (ENV['SIDEKIQ_MEMORY_KILLER_SHUTDOWN_WAIT'] || 30).to_s.to_i

      # Create a mutex used to ensure there will be only one thread waiting to
      # shut Sidekiq down
13
      MUTEX = Mutex.new
14 15 16 17

      def call(worker, job, queue)
        yield
        current_rss = get_rss
18

19
        return unless MAX_RSS > 0 && current_rss > MAX_RSS
20

Jacob Vosmaer committed
21
        Thread.new do
22 23 24 25
          # Return if another thread is already waiting to shut Sidekiq down
          return unless MUTEX.try_lock

          Sidekiq.logger.warn "current RSS #{current_rss} exceeds maximum RSS "\
26
            "#{MAX_RSS}"
27
          Sidekiq.logger.warn "spawned thread that will shut down PID "\
28 29
            "#{Process.pid} in #{GRACE_TIME} seconds"
          sleep(GRACE_TIME)
30 31 32 33

          Sidekiq.logger.warn "sending SIGUSR1 to PID #{Process.pid}"
          Process.kill('SIGUSR1', Process.pid)

34
          Sidekiq.logger.warn "waiting #{SHUTDOWN_WAIT} seconds before sending "\
35
            "SIGTERM to PID #{Process.pid}"
36
          sleep(SHUTDOWN_WAIT)
37 38

          Sidekiq.logger.warn "sending SIGTERM to PID #{Process.pid}"
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
          Process.kill('SIGTERM', Process.pid)
        end
      end

      private

      def get_rss
        output, status = Gitlab::Popen.popen(%W(ps -o rss= -p #{Process.pid}))
        return 0 unless status.zero?

        output.to_i
      end
    end
  end
end