Sha256: ec27e3051fed822b300d0acb335ebad7df3ba8fc245b2d895fc900990a7b5c14

Contents?: true

Size: 1.68 KB

Versions: 2

Compression:

Stored size: 1.68 KB

Contents

require "socket"
require "spring/application"
require "mutex_m"

class Spring
  class ApplicationManager
    include Mutex_m

    attr_reader :pid, :child, :env

    def initialize(env)
      super()
      @env = env
    end

    def start
      start_child
      start_wait_thread
    end

    def restart
      # Restarting is a background operation. If it fails, we don't want
      # any terminal output. The user will see the output when they next
      # try to run a command.
      start_child(true)
    end

    def alive?
      @pid
    end

    def run(client)
      @client = client

      synchronize do
        start unless alive?

        begin
          child.send_io @client
        rescue Errno::EPIPE
          # EPIPE indicates child has died but has not been collected by the wait thread yet
          start
          child.send_io @client
        end
      end
    ensure
      @client.close
      @client = nil
    end

    private

    def start_child(silence = false)
      @child, child_socket = UNIXSocket.pair
      @pid = fork {
        [STDOUT, STDERR].each { |s| s.reopen('/dev/null', 'w') } if silence
        @client.close if @client
        ENV['RAILS_ENV'] = ENV['RACK_ENV'] = env
        Application.new(child_socket).start
      }
      child_socket.close
    end

    def start_wait_thread
      @wait_thread = Thread.new {
        Thread.current.abort_on_exception = true

        while alive?
          _, status = Process.wait2(pid)
          @pid = nil

          # In the forked child, this will block forever, so we won't
          # return to the next iteration of the loop.
          synchronize { restart if !alive? && status.success? }
        end
      }
    end
  end
end

Version data entries

2 entries across 2 versions & 1 rubygems

Version Path
spring-0.0.2 lib/spring/application_manager.rb
spring-0.0.1 lib/spring/application_manager.rb