Class: Forklift::Master

Inherits:
Object
  • Object
show all
Defined in:
lib/forklift/master.rb,
lib/forklift/master_old.rb

Constant Summary collapse

WORKERS =

This hash maps PIDs to Workers

{}
SELF_PIPE =
[]
SIG_QUEUE =

signal queue used for self-piping

[]
QUEUE_SIGS =

list of signals we care about and trap in master.

[ :WINCH, :QUIT, :INT, :TERM, :USR1, :USR2, :HUP, :TTIN, :TTOU ]
START_CTX =
{
  :argv => ARGV.map { |arg| arg.dup },
  0 => $0.dup,
}

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeMaster

Returns a new instance of Master.



35
36
37
38
39
40
# File 'lib/forklift/master.rb', line 35

def initialize
  self.reexec_pid = 0
  self.worker_processes = 2
  @logger = Logger.new($stdout)
  @timeout = 100
end

Instance Attribute Details

#after_forkObject

Returns the value of attribute after_fork.



5
6
7
# File 'lib/forklift/master_old.rb', line 5

def after_fork
  @after_fork
end

#appObject

Returns the value of attribute app.



5
6
7
# File 'lib/forklift/master_old.rb', line 5

def app
  @app
end

#before_execObject

Returns the value of attribute before_exec.



5
6
7
# File 'lib/forklift/master_old.rb', line 5

def before_exec
  @before_exec
end

#before_forkObject

Returns the value of attribute before_fork.



5
6
7
# File 'lib/forklift/master_old.rb', line 5

def before_fork
  @before_fork
end

#configObject

Returns the value of attribute config.



5
6
7
# File 'lib/forklift/master_old.rb', line 5

def config
  @config
end

#init_listenersObject

Returns the value of attribute init_listeners.



5
6
7
# File 'lib/forklift/master_old.rb', line 5

def init_listeners
  @init_listeners
end

#listener_optsObject

Returns the value of attribute listener_opts.



5
6
7
# File 'lib/forklift/master_old.rb', line 5

def listener_opts
  @listener_opts
end

#loggerObject (readonly)

Returns the value of attribute logger.



10
11
12
# File 'lib/forklift/master.rb', line 10

def logger
  @logger
end

#master_pidObject

Returns the value of attribute master_pid.



11
12
13
# File 'lib/forklift/master.rb', line 11

def master_pid
  @master_pid
end

#orig_appObject

Returns the value of attribute orig_app.



5
6
7
# File 'lib/forklift/master_old.rb', line 5

def orig_app
  @orig_app
end

#pidObject (readonly)

Returns the value of attribute pid.



10
11
12
# File 'lib/forklift/master.rb', line 10

def pid
  @pid
end

#preload_appObject

Returns the value of attribute preload_app.



5
6
7
# File 'lib/forklift/master_old.rb', line 5

def preload_app
  @preload_app
end

#ready_pipeObject

Returns the value of attribute ready_pipe.



5
6
7
# File 'lib/forklift/master_old.rb', line 5

def ready_pipe
  @ready_pipe
end

#reexec_pidObject

Returns the value of attribute reexec_pid.



11
12
13
# File 'lib/forklift/master.rb', line 11

def reexec_pid
  @reexec_pid
end

#timeoutObject

Returns the value of attribute timeout.



11
12
13
# File 'lib/forklift/master.rb', line 11

def timeout
  @timeout
end

#userObject

Returns the value of attribute user.



5
6
7
# File 'lib/forklift/master_old.rb', line 5

def user
  @user
end

#worker_processesObject

Returns the value of attribute worker_processes.



11
12
13
# File 'lib/forklift/master.rb', line 11

def worker_processes
  @worker_processes
end

Instance Method Details

#joinObject

monitors children and receives signals forever (or until a termination signal is sent). This handles signals one-at-a-time time and we’ll happily drop signals in case somebody is signalling us too often.



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/forklift/master_old.rb', line 71

def join
  respawn = true
  last_check = Time.now

  proc_name 'master'
  logger.info "master process ready" # test_exec.rb relies on this message
  if @ready_pipe
    @ready_pipe.syswrite($$.to_s)
    @ready_pipe = @ready_pipe.close rescue nil
  end

  begin
    reap_all_workers

    case SIG_QUEUE.shift
    when nil
      # avoid murdering workers after our master process (or the
      # machine) comes out of suspend/hibernation
      if (last_check + @timeout) >= (last_check = Time.now)
        sleep_time = murder_lazy_workers
      else
        sleep_time = @timeout/2.0 + 1
        @logger.debug("waiting #{sleep_time}s after suspend/hibernation")
      end
      maintain_worker_count if respawn
      master_sleep(sleep_time)

    when :QUIT # graceful shutdown
      break
    when :TERM, :INT # immediate shutdown
      stop(false)
      break
    when :USR1 # rotate logs
      logger.info "master done reopening logs"
      kill_each_worker(:USR1)
    when :USR2 # exec binary, stay alive in case something went wrong
      # reexec
    end

  rescue => e
    Forklift.log_error(@logger, "master loop error", e)
  end while true

  stop # gracefully shutdown all workers on our way out
  logger.info "master complete"
  unlink_pid_safe(pid) if pid
end

#startObject



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/forklift/master.rb', line 42

def start
  init_self_pipe!
  # setup signal handlers before writing pid file in case people get
  # trigger happy and send signals as soon as the pid file exists.
  # Note that signals don't actually get handled until the #join method
  QUEUE_SIGS.each { |sig| trap(sig) { SIG_QUEUE << sig; awaken_master } }
  trap(:CHLD) { awaken_master }

  self.master_pid = $$

  logger.info "Starting master"

  spawn_missing_workers

  self
end