Created
November 18, 2009 08:14
-
-
Save xaviershay/237652 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Support | |
class ApplicationServer | |
attr_accessor :options | |
attr_accessor :started | |
def initialize(options = {}) | |
self.options = options | |
end | |
def option(key, default = nil) | |
options.has_key?(key) ? options[key] : default | |
end | |
def port | |
option(:port, 9293) | |
end | |
def daemonize? | |
option(:daemonize, true) | |
end | |
def start | |
if File.exists?(pid_file) | |
# Server has already been started, so we don't have to do it | |
self.started = false | |
else | |
$stderr.puts "==> Starting rack application server on port #{port}... " | |
fork do | |
args = options[:config], '-p', port.to_s | |
if daemonize? | |
args += ['-D', '--pid', pid_file] | |
else | |
File.open(pid_file, 'w') { |fp| fp.write Process.pid } | |
end | |
ENV["RACK_ENV"] = "test" | |
exec 'rackup', *args | |
end | |
self.started = true | |
end | |
end | |
def stop | |
silence_stream(STDOUT) do | |
if File.exists?(pid_file) | |
pid = File.read(pid_file) | |
system("kill -9 #{pid}") | |
FileUtils.rm_f pid_file | |
end | |
end | |
end | |
def fail | |
$stderr.puts | |
$stderr.puts | |
$stderr.puts "==> Failed to boot the Rack application server... exiting!" | |
exit | |
end | |
def pid_file | |
prepare_pid_file(Dir.pwd + "/tmp", "rack.#{port}.pid") | |
end | |
def silence_stream(stream) | |
old_stream = stream.dup | |
stream.reopen(RUBY_PLATFORM =~ /mswin/ ? 'NUL:' : '/dev/null') | |
stream.sync = true | |
yield | |
ensure | |
stream.reopen(old_stream) | |
end | |
def boot | |
if start | |
wait | |
stop_at_exit | |
end | |
end | |
def stop_at_exit | |
at_exit do | |
stop | |
end | |
end | |
def wait | |
wait_for_socket | |
$stderr.puts "==> Server ready on port #{port}\n" | |
end | |
def wait_for_socket | |
silence_stream(STDOUT) do | |
TCPSocket.wait_for_service_with_timeout \ | |
:host => 'localhost', | |
:port => port, | |
:timeout => 5 # seconds | |
end | |
rescue SocketError | |
fail | |
end | |
def prepare_pid_file(file_path, pid_file_name) | |
FileUtils.mkdir_p File.expand_path(file_path) | |
File.expand_path("#{file_path}/#{pid_file_name}") | |
end | |
# Load more than one server in parallel | |
def self.multi_boot(*servers) | |
servers.collect {|config| | |
ApplicationServer.new(config) | |
}.each {|server| | |
server.start | |
}.each {|server| | |
server.wait | |
server.stop_at_exit if server.started | |
} | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class TCPSocket | |
def self.wait_for_service_with_timeout(options) | |
start_time = Time.now | |
until listening_service?(options) | |
verbose_wait | |
if options[:timeout] && (Time.now > start_time + options[:timeout]) | |
raise SocketError.new("Socket did not open within #{options[:timeout]} seconds") | |
end | |
end | |
end | |
def self.wait_for_service_termination_with_timeout(options) | |
start_time = Time.now | |
while listening_service?(options) | |
verbose_wait | |
if options[:timeout] && (Time.now > start_time + options[:timeout]) | |
raise SocketError.new("Socket did not terminate within #{options[:timeout]} seconds") | |
end | |
end | |
end | |
def self.wait_for_service(options) | |
verbose_wait until listening_service?(options) | |
end | |
def self.wait_for_service_termination(options) | |
verbose_wait while listening_service?(options) | |
end | |
def self.listening_service?(options) | |
Timeout::timeout(options[:timeout] || 20) do | |
begin | |
socket = TCPSocket.new(options[:host], options[:port]) | |
socket.close unless socket.nil? | |
true | |
rescue Errno::ECONNREFUSED, | |
Errno::EBADF # Windows | |
false | |
end | |
end | |
end | |
def self.verbose_wait | |
puts ".\n" | |
sleep 2 | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment