Skip to content

Commit

Permalink
Rewrote server to support manager process.
Browse files Browse the repository at this point in the history
  • Loading branch information
Dan Yoder authored and automatthew committed Oct 14, 2008
1 parent 30116e8 commit 4d4f6b2
Show file tree
Hide file tree
Showing 12 changed files with 117 additions and 132 deletions.
7 changes: 4 additions & 3 deletions lib/dispatchers/base.rb
Expand Up @@ -33,18 +33,19 @@ class Base
# As with any Rack application, a Waves dispatcher must provide a call method
# that takes an +env+ hash.
def call( env )
if Waves.synchronize?
Waves.synchronize { _call( env ) }
if Waves.synchronize? or Waves.debug?
Waves.synchronize { _call( env ) }
else
_call( env )
end
# Thread.new { Waves.reload }
end

# Called by event driven servers like thin and ebb. Returns true if
# the server should run the request in a separate thread, as determined by
# Configurations::Mapping#threaded?
def deferred?( env )
Waves::Runtime.instance.mapping.threaded?( env )
# TODO: impl.
end

private
Expand Down
1 change: 0 additions & 1 deletion lib/dispatchers/default.rb
Expand Up @@ -29,7 +29,6 @@ class Default < Base

# Takes a Waves::Request and returns a Waves::Response
def safe( request )
Waves.reload
# set a default content type -- this can be overridden by the resource
request.response.content_type = request.accept.default
# grab the appropriate resource from those declared in the configuration, based on the request
Expand Down
3 changes: 1 addition & 2 deletions lib/ext/kernel.rb
Expand Up @@ -2,8 +2,7 @@ module Kernel
unless respond_to?(:debugger)
# Starts a debugging session if ruby-debug has been loaded (call waves-server --debugger to do load it).
def debugger
puts "debugger called"
Waves::Logger.info "\n***** Debugger requested, but was not available: Start server with --debugger to enable *****\n"
Waves::Logger.info "Debugger invoked but not loaded. Start server with --debugger to enable."
end
end

Expand Down
6 changes: 1 addition & 5 deletions lib/foundations/compact.rb
Expand Up @@ -17,11 +17,7 @@ def self.included( app )
log :level => :debug
host '127.0.0.1'
port 3000
handler ::Rack::Handler::Mongrel
application {
use ::Rack::ShowExceptions
run ::Waves::Dispatchers::Default.new
}
server Waves::Servers::Mongrel.new
resource app::Resources::Map
})
const_set( :Production, Class.new( self::Development ) {
Expand Down
7 changes: 0 additions & 7 deletions lib/layers/mvc.rb
Expand Up @@ -93,13 +93,6 @@ def attributes
auto_load true, :directories => [ :helpers ]
end

app.auto_eval :Resources do
auto_create_class :Default, Waves::Resources::Base
auto_load :Default, :directories => [ :resources ]
auto_create_class( true, app::Resources::Default )
auto_load( true, :directories => [ :resources ] )
end

end
end
end
Expand Down
15 changes: 12 additions & 3 deletions lib/runtime/configuration.rb
Expand Up @@ -150,9 +150,12 @@ class Default < Base
#
# When accessing the value
# (calling with no arguments), returns an array of the handler and options.
def self.handler( *args )
return self['handler'] if args.empty?
self['handler'] = args.first
def self.server( server = nil )
if server
self['server'] = server
else
self['server']
end
end

# Provides access to the Waves::MimeTypes class via the configuration. You
Expand All @@ -178,6 +181,12 @@ def self.application( &block )
dependencies []
cache :dir => 'cache'
pid "#{$$}.pid"
server Waves::Servers::WEBrick.new
application {
use ::Rack::ShowExceptions
run ::Waves::Dispatchers::Default.new
}

end
end
end
Expand Down
146 changes: 61 additions & 85 deletions lib/runtime/server.rb
@@ -1,102 +1,78 @@
module Waves
# You can run the Waves::Server via the +waves-server+ command or via <tt>rake cluster:start</tt>. Run <tt>waves-server --help</tt> for options on the <tt>waves-server</tt> command. The <tt>cluster:start</tt> task uses the +mode+ environment variable to determine the active configuration. You can define +port+ to run on a single port, or +ports+ (taking an array) to run on multiple ports.
#
# *Example*
#
# Assume that +ports+ is set in the development configuration like this:
#
# ports [ 2020, 2021, 2022 ]
#
# Then you could start up instances on all three ports using:
#
# rake cluster:start mode=development
#
# This is the equivalent of running:
#
# waves-server -c development -p 2020 -d
# waves-server -c development -p 2021 -d
# waves-server -c development -p 2022 -d
#
# The +cluster:stop+ task stops all of the instances.
#

class Server < Runtime

# Access the server thread.
attr_reader :thread

# Access the host we're binding to (set via the configuration).

def host ; options[:host] || config.host ; end

# Access the port we're listening on (set via the configuration).
def port ; options[:port] || config.port ; end

# Run the server as a daemon. Corresponds to the -d switch on +waves-server+.
def ports ; config.ports || [ port ] ; end
def application ; config.application.to_app ; end

def Server.run( options )
@manager = new( options )
Server.trap( 'INT' ) { }
Server.trap( 'HUP' ) { @manager.restart }
@manager.start
end

def Server.trap(signal)
Kernel::trap(signal) { yield }
Thread.new { loop { sleep 1 } } if RUBY_PLATFORM =~ /mswin32/
end

def start
daemonize if options[ :daemon ]
Waves::Logger.start
Waves::Logger.info "Waves version #{Waves.version} starting"
start_debugger if options[ :debugger ]
unless RUBY_PLATFORM =~ /mswin32/
start_servers
else
config.servers.call( application, host, port )
end
Process.waitall
end

def daemonize
pwd = Dir.pwd
Daemonize.daemonize( Waves::Logger.output )
Dir.chdir(pwd)
File.write( Waves.config.pid, $$ )
end

def trap(signal)
Kernel::trap(signal) { yield }
Thread.new { loop {sleep 1} } if RUBY_PLATFORM =~ /mswin32/

def start_debugger
require 'ruby-debug'
Debugger.start
Debugger.settings[:autoeval] = true if Debugger.respond_to?(:settings)
Waves::Logger.info "ruby-debug enabled"
end

# Start the server.
def start
daemonize if options[:daemon]
start_debugger if options[:debugger]
log.info "Waves Runtime #{Waves.version}"
log.info "Waves starting on #{host}:#{port}"
# TODO: technically is this not really Rack-compatible, since the options / block
# stuff is custom to the underlying server implementation, an area where Rack surprisingly
# exposes server internals ... :(
config.handler.run( config.application.to_app, { :Host => host, :Port => port } ) do |server|
@server = server
self.trap('INT') { puts; stop } if @server.respond_to? :stop
def start_servers
@pids = [] ; ports.each do | port |
@pids << fork do
Server.trap( 'INT' ) { exit }
config.server.call( application, host, port ) do | server |
Waves::Logger.info "Waves server started on #{host}:#{port}."
Server.trap('INT') do
server.stop if server.respond_to? :stop
Waves::Logger.info "Waves server on #{host}:#{port} stopped."
end
end
end
end
end

# Stop the server.

def stop
log.info "Waves Server Stopping ..."
if options[:daemon]
pid_file = Waves.config.pid ; FileUtils.rm( pid_file ) if File.exist?( pid_file )
end
@server.stop
log.info "Waves Server Stopped"
@pids.each { | pid | Process.kill( 'INT', pid ) }
end

class << self
private :new, :dup, :clone
# Start or restart the server.
def run( options={} )
@server.stop if @server; @server = new( options ); @server.start
end

# Allows us to access the Waves::Server instance.
def method_missing(*args)
@server.send(*args)
end

#-- Probably wouldn't need this if I added a block parameter to method_missing.
def synchronize(&block) ; @server.synchronize(&block) ; end

def restart
stop ; start_servers
end

private

def start_debugger
begin
require 'ruby-debug'
Debugger.start
Debugger.settings[:autoeval] = true if Debugger.respond_to?(:settings)
log.info "Debugger enabled"
rescue Exception
log.info "You need to install ruby-debug to run the server in debugging mode. With gems, use 'gem install ruby-debug'"
exit
end

unless RUBY_PLATFORM =~ /mswin32/
def reload ; restart ; end
end


end

end
end
9 changes: 9 additions & 0 deletions lib/servers/mongrel.rb
@@ -0,0 +1,9 @@
module Waves
module Servers
class Mongrel
def call( app, host, port )
Rack::Handler::Mongrel.run( app, :Host => host, :Port => port ) { |server| yield server if block_given? }
end
end
end
end
9 changes: 9 additions & 0 deletions lib/servers/webrick.rb
@@ -0,0 +1,9 @@
module Waves
module Servers
class WEBrick
def call( app, host, port )
Rack::Handler::WEBrick.run( app, :Host => host, :Port => port ) { yield self if block_given? }
end
end
end
end
26 changes: 0 additions & 26 deletions lib/tasks/cluster.rb

This file was deleted.

18 changes: 18 additions & 0 deletions lib/tasks/manager.rb
@@ -0,0 +1,18 @@
namespace :manager do

desc 'Start a cluster of waves applications.'
task :start do |task|
File.write('pid', Manager.run( :daemonize => true ) )
end

desc 'Stop a cluster of waves applications.'
task :stop do |task|
Process.kill( 'INT', File.read( 'pid' ) ) rescue nil
end

desc 'Restart a cluster of waves applications.'
task :restart do |task|
Process.kill( 'HUP', File.read( 'pid' ) ) rescue nil
end

end
2 changes: 2 additions & 0 deletions lib/waves.rb
Expand Up @@ -33,6 +33,8 @@
# waves Runtime
require 'dispatchers/base'
require 'dispatchers/default'
require 'servers/webrick'
require 'servers/mongrel'
require 'runtime/logger'
require 'runtime/mime_types'
require 'runtime/runtime'
Expand Down

0 comments on commit 4d4f6b2

Please sign in to comment.