class Spring::Server

Attributes

env[R]

Public Class Methods

boot(options = {}) click to toggle source
# File lib/spring/server.rb, line 13
def self.boot(options = {})
  new(options).boot
end
new(options = {}) click to toggle source
# File lib/spring/server.rb, line 19
def initialize(options = {})
  @foreground   = options.fetch(:foreground, false)
  @env          = options[:env] || default_env
  @applications = Hash.new { |h, k| h[k] = ApplicationManager.new(k, env) }
  @pidfile      = env.pidfile_path.open('a')
  @mutex        = Mutex.new
end

Public Instance Methods

boot() click to toggle source
# File lib/spring/server.rb, line 35
def boot
  Spring.verify_environment

  write_pidfile
  set_pgid unless foreground?
  ignore_signals unless foreground?
  set_exit_hook
  set_process_title
  start_server
end
foreground?() click to toggle source
# File lib/spring/server.rb, line 27
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/spring/server.rb, line 89
def ignore_signals
  IGNORE_SIGNALS.each { |sig| trap(sig, "IGNORE") }
end
log(message) click to toggle source
# File lib/spring/server.rb, line 31
def log(message)
  env.log "[server] #{message}"
end
rails_env_for(args, default_rails_env) click to toggle source
# File lib/spring/server.rb, line 76
def rails_env_for(args, default_rails_env)
  Spring.command(args.first).env(args.drop(1)) || default_rails_env
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/spring/server.rb, line 126
def redirect_output
  [STDOUT, STDERR].each { |stream| stream.reopen(env.log_file) }
end
serve(client) click to toggle source
# File lib/spring/server.rb, line 53
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, default_rails_env = command.values_at('args', 'default_rails_env')

  if Spring.command?(args.first)
    log "running command #{args.first}"
    client.puts
    client.puts @applications[rails_env_for(args, default_rails_env)].run(app_client)
  else
    log "command not found #{args.first}"
    client.close
  end
rescue SocketError => e
  raise e unless client.eof?
ensure
  redirect_output
end
set_exit_hook() click to toggle source
# File lib/spring/server.rb, line 93
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/spring/server.rb, line 83
def set_pgid
  Process.setpgid(0, SID.pgid)
end
set_process_title() click to toggle source
# File lib/spring/server.rb, line 130
def set_process_title
  ProcessTitleUpdater.run { |distance|
    "spring server | #{env.app_name} | started #{distance} ago"
  }
end
shutdown() click to toggle source
# File lib/spring/server.rb, line 100
def shutdown
  log "shutting down"

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

  @applications.values.map { |a| Spring.failsafe_thread { a.stop } }.map(&:join)
end
start_server() click to toggle source
# File lib/spring/server.rb, line 46
def start_server
  server = UNIXServer.open(env.socket_name)
  log "started on #{env.socket_name}"
  loop { serve server.accept }
rescue Interrupt
end
write_pidfile() click to toggle source
# File lib/spring/server.rb, line 112
def write_pidfile
  if @pidfile.flock(File::LOCK_EX | File::LOCK_NB)
    @pidfile.truncate(0)
    @pidfile.write("#{Process.pid}\n")
    @pidfile.fsync
  else
    exit 1
  end
end

Private Instance Methods

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