class Expedite::Server

Attributes

env[R]

Public Class Methods

boot(options = {}) click to toggle source
# File lib/expedite/server.rb, line 12
def self.boot(options = {})
  new(options).boot
end
new(foreground: true, env: nil) click to toggle source
# File lib/expedite/server.rb, line 18
def initialize(foreground: true, env: nil)
  @foreground   = foreground
  @env          = env || default_env
  @pidfile      = @env.pidfile_path.open('a')
  @mutex        = Mutex.new
end

Public Instance Methods

boot() click to toggle source
# File lib/expedite/server.rb, line 33
def boot
  env.load_helper

  write_pidfile
  set_pgid unless foreground?
  ignore_signals unless foreground?
  set_exit_hook
  set_process_title
  start_server
  exit 0
end
foreground?() click to toggle source
# File lib/expedite/server.rb, line 25
def foreground?
  @foreground
end
ignore_signals() click to toggle source

Ignore SIGINT and SIGQUIT otherwise the user typing ^C or ^\ on the command line will kill the server/application.

# File lib/expedite/server.rb, line 129
def ignore_signals
  IGNORE_SIGNALS.each { |sig| trap(sig, "IGNORE") }
end
kill(sig) click to toggle source
# File lib/expedite/server.rb, line 81
def kill(sig)
  pid = self.pid
  Process.kill(sig, pid) if pid
rescue Errno::ESRCH
  # already dead
end
log(message) click to toggle source
# File lib/expedite/server.rb, line 29
def log(message)
  env.log "[server] #{message}"
end
pid() click to toggle source
# File lib/expedite/server.rb, line 45
def pid
  @env.pidfile_path.read.to_i
rescue Errno::ENOENT
  nil
end
redirect_output() click to toggle source

We need to redirect STDOUT and STDERR, otherwise the server will keep the original FDs open which would break piping. (e.g. `spring rake -T | grep db` would hang forever because the server would keep the stdout FD open.)

# File lib/expedite/server.rb, line 166
def redirect_output
  [STDOUT, STDERR].each { |stream| stream.reopen(env.log_file) }
end
running?() click to toggle source
# File lib/expedite/server.rb, line 51
def running?
  pidfile = @env.pidfile_path.open('r+')
  !pidfile.flock(File::LOCK_EX | File::LOCK_NB)
rescue Errno::ENOENT
  false
ensure
  if pidfile
    pidfile.flock(File::LOCK_UN)
    pidfile.close
  end
end
serve(client) click to toggle source
# File lib/expedite/server.rb, line 95
def serve(client)
  log "accepted client"
  client.puts env.version

  app_client = client.recv_io
  command    = JSON.load(client.read(client.gets.to_i))

  args, variant = command.values_at('args', 'variant')
  cmd = args.first
  if true #Expedite.command(cmd)
    log "running command #{cmd}"
    client.puts

    target = env.applications[variant]
    client.puts target.run(app_client)
  else
    log "command not found #{cmd}"
    client.close
  end
rescue SocketError => e
  raise e unless client.eof?
ensure
  redirect_output
end
set_exit_hook() click to toggle source
# File lib/expedite/server.rb, line 133
def set_exit_hook
  server_pid = Process.pid

  # We don't want this hook to run in any forks of the current process
  at_exit { shutdown if Process.pid == server_pid }
end
set_pgid() click to toggle source

Boot the server into the process group of the current session. This will cause it to be automatically killed once the session ends (i.e. when the user closes their terminal).

# File lib/expedite/server.rb, line 123
def set_pgid
  # Process.setpgid(0, SID.pgid)
end
set_process_title() click to toggle source
# File lib/expedite/server.rb, line 170
def set_process_title
  $0 = "expedite server | #{env.app_name}"
end
shutdown() click to toggle source
# File lib/expedite/server.rb, line 140
def shutdown
  log "shutting down"

  [env.socket_path, env.pidfile_path].each do |path|
    if path.exist?
      path.unlink rescue nil
    end
  end

  env.applications.values.map { |a| Expedite.failsafe_thread { a.stop } }.map(&:join)
end
start_server() click to toggle source
# File lib/expedite/server.rb, line 88
def start_server
  server = UNIXServer.open(env.socket_path)
  log "started on #{env.socket_path}"
  loop { serve server.accept }
rescue Interrupt
end
stop() click to toggle source

timeout: Defaults to 2 seconds

# File lib/expedite/server.rb, line 64
def stop
  if running?
    timeout = Time.now + @env.graceful_termination_timeout
    kill 'TERM'
    sleep 0.1 until !running? || Time.now >= timeout

    if running?
      kill 'KILL'
      :killed
    else
      :stopped
    end
  else
    :not_running
  end
end
write_pidfile() click to toggle source
# File lib/expedite/server.rb, line 152
def write_pidfile
  if @pidfile.flock(File::LOCK_EX | File::LOCK_NB)
    @pidfile.truncate(0)
    @pidfile.write("#{Process.pid}\n")
    @pidfile.fsync
  else
    raise "Failed to lock #{@env.pidfile_path}"
  end
end

Private Instance Methods

default_env() click to toggle source
# File lib/expedite/server.rb, line 176
def default_env
  Env.new(log_file: default_log_file)
end
default_log_file() click to toggle source
# File lib/expedite/server.rb, line 180
def default_log_file
  if foreground? && !ENV["SPRING_LOG"]
    $stdout
  else
    nil
  end
end