Class: Sidekiq::ProcessManager::Manager

Inherits:
Object
  • Object
show all
Defined in:
lib/sidekiq/process_manager/manager.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(process_count: 1, prefork: false, preboot: nil, mode: nil, silent: false) ⇒ Manager

Returns a new instance of Manager.

Raises:

  • (ArgumentError)


10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/sidekiq/process_manager/manager.rb', line 10

def initialize(process_count: 1, prefork: false, preboot: nil, mode: nil, silent: false)
  require "sidekiq/cli"

  # Get the number of processes to fork
  @process_count = process_count
  raise ArgumentError.new("Process count must be greater than 1") if @process_count < 1

  @prefork = (prefork && process_count > 1)
  @preboot = preboot if process_count > 1 && !prefork

  if mode == :testing
    require_relative "../../../spec/support/mocks"
    @cli = MockSidekiqCLI.new(silent)
  else
    @cli = Sidekiq::CLI.instance
  end

  @silent = silent
  @pids = []
  @terminated_pids = []
  @started = false
  @monitor = Monitor.new
end

Instance Attribute Details

#cliObject (readonly)

Returns the value of attribute cli.



8
9
10
# File 'lib/sidekiq/process_manager/manager.rb', line 8

def cli
  @cli
end

Instance Method Details

#pidsObject



94
95
96
# File 'lib/sidekiq/process_manager/manager.rb', line 94

def pids
  @pids.dup
end

#startObject

Start the process manager. This method will start the specified number of sidekiq processes and monitor them. It will only exit once all child processes have exited. If a child process dies unexpectedly, it will be restarted.

Child processes are manged by sending the signals you would normally send to a sidekiq process to the process manager instead.



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/sidekiq/process_manager/manager.rb', line 41

def start
  raise "Process manager already started" if started?
  @started = true

  load_sidekiq

  master_pid = ::Process.pid

  # Trap signals that will be forwarded to child processes
  [:INT, :TERM, :USR1, :USR2, :TSTP, :TTIN].each do |signal|
    ::Signal.trap(signal) do
      if ::Process.pid == master_pid
        send_signal_to_children(signal)
      end
    end
  end

  # Ensure that child processes receive the term signal when the master process exits.
  at_exit do
    if ::Process.pid == master_pid && @process_count > 0
      @pids.each do |pid|
        send_signal_to_children(:TERM)
      end
    end
  end

  @process_count.times do
    start_child_process!
  end

  log_info("Process manager started with pid #{::Process.pid}")
  monitor_child_processes
  log_info("Process manager #{::Process.pid} exiting")
end

#started?Boolean

Returns:

  • (Boolean)


98
99
100
# File 'lib/sidekiq/process_manager/manager.rb', line 98

def started?
  @started
end

#stopObject

Helper to gracefully stop all child processes.



88
89
90
91
92
# File 'lib/sidekiq/process_manager/manager.rb', line 88

def stop
  @process_count = 0
  send_signal_to_children(:TSTP)
  send_signal_to_children(:TERM)
end

#wait(timeout = 5) ⇒ Object

Helper to wait on the manager to wait on child processes to start up.

Raises:

  • (Timeout::Error)


77
78
79
80
81
82
83
84
85
# File 'lib/sidekiq/process_manager/manager.rb', line 77

def wait(timeout = 5)
  start_time = Time.now
  while Time.now < start_time + timeout
    return if @pids.size == @process_count
    sleep(0.01)
  end

  raise Timeout::Error.new("child processes failed to start in #{timeout} seconds")
end