1
0
Fork 0
mirror of https://github.com/puma/puma.git synced 2022-11-09 13:48:40 -05:00

Adding mongrel_rails_service (and svc) drafts. Still fail to stop due Rails CGI Handler (my guess). Also fixed the "graceful stop" in mongrel_simple_service because cause also errors (how gracefully it is?)

git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/trunk@55 19e92222-5c0b-0410-8929-a290d50e31e9
This commit is contained in:
luislavena 2006-02-21 23:31:05 +00:00
parent cae898c5a5
commit 985bb4dd71
3 changed files with 432 additions and 1 deletions

View file

@ -0,0 +1,237 @@
###############################################
# mongrel_rails_service.rb
#
# Control script for Rails powered by Mongrel
#
# WARNING: stop command still doesn't work with rails!
###############################################
require 'rubygems'
require 'mongrel'
require 'mongrel/command'
require 'win32/service'
include Win32
module GenericCommand
def configure
options [
['-n', '--name SVC_NAME', "Required name for the service to be registered/installed.", :@svc_name, nil],
]
end
def validate
valid? @svc_name != nil, "You must specify the service name to be uninstalled."
# We should validate service existance here, right Zed?
begin
valid? Service.exists?(@svc_name), "There is no service with that name, cannot proceed."
rescue
end
return @valid
end
end
class InstallCommand < Mongrel::Command::Command
# Default every option to nil so only the defined ones get passed to service
# (which will override ServiceCommand defaults).
def configure
options [
['-n', '--name SVC_NAME', "Required name for the service to be registered/installed.", :@svc_name, nil],
['-d', '--display SVC_DISPLAY', "Adjust the display name of the service.", :@svc_display, nil],
['-r', '--root PATH', "Set the root path where your rails app resides.", :@rails_root, Dir.pwd],
['-e', '--environment ENV', "Rails environment to run as", :@environment, 'production'],
['-b', '--binding ADDR', "Address to bind to", :@ip, nil],
['-p', '--port PORT', "Which port to bind to", :@port, 3000],
['-m', '--mime PATH', "A YAML file that lists additional MIME types", :@mime_map, nil],
['-P', '--num-procs INT', "Number of processor threads to use", :@num_procs, nil],
['-t', '--timeout SECONDS', "Timeout all requests after SECONDS time", :@timeout, nil],
]
end
# When we validate the options, we need to make sure the --root is actually RAILS_ROOT
# of the rails application we wanted to serve, because later "as service" no error
# show to trace this.
def validate
@rails_root = File.expand_path(@rails_root)
# start with the premise of app really exist.
app_exist = true
paths = %w{app config db log public}
paths.each do |path|
if !File.directory?(@rails_root + '/' + path)
app_exist = false
break
end
end
valid? @svc_name != nil, "You must specify a valid service name to install."
valid? app_exist == true, "The root of rails app isn't valid, please verify."
valid_exists? @mime_map, "MIME mapping file does not exist: #@mime_map" if @mime_map
# We should validate service existance here, right Zed?
begin
valid? !Service.exists?(@svc_name), "The service already exist, please uninstall it first."
rescue
end
# Expand to get full path for mime-types file
@mime_map = File.Expand_path(@mime_map) if @mime_map
# default service display to service name
@svc_display = @svc_name if !@svc_display
return @valid
end
def build_params
# build the parameters that will be used when register/install the service
@params = ""
# add "service" command
@params << "service "
# rails_root, must be quoted to support long_names
@params << "-r \"#{@rails_root}\" "
# environment
@params << "-e #{@environment} " if @environment
# binding
@params << "-b #{@ip} " if @ip
# port
@params << "-p #{@port.to_i} " if @port
# mime
@params << "-m #{@mime_map} " if @mime_map
# num_procs
@params << "-P #{@num_procs.to_i} " if @num_procs
# timeout
@params << "-t #{@timeout.to_i} " if @timeout
end
def install_service
# use rbconfig to get the path to bin ruby.exe
require 'rbconfig'
# ruby.exe instead of rubyw.exe due a exception raised when stoping the service!
binary_path = ""
binary_path << '"' << Config::CONFIG['bindir'] << '/ruby.exe' << '" '
# add service_script
service_script = File.expand_path(File.dirname(__FILE__) + '/mongrel_rails_svc.rb')
binary_path << '"' << service_script << '" '
# now add the parameters to it.
binary_path << @params
puts "Installing service with these options:"
puts "service name: " << @svc_name
puts "service display: " << @svc_display
puts "RAILS_ROOT: " << @rails_root
puts "RAILS_ENV: " << @environment if @environment
puts "binding: " << @ip if @ip
puts "port: " << @port.to_s if @port
puts "mime_map: " << @mime_map if @mime_map
puts "num_procs: " << @num_procs.to_s if @num_procs
puts "timeout: " << @timeout.to_s if @timeout
puts "ruby.exe: " << Config::CONFIG['bindir'] << '/ruby.exe'
puts "service script: " << service_script
puts
svc = Service.new
begin
svc.create_service{ |s|
s.service_name = @svc_name
s.display_name = @svc_display
s.binary_path_name = binary_path
s.dependencies = []
}
puts "#{@svc_display} service installed."
rescue ServiceError => err
puts "There was a problem installing the service:"
puts err
end
svc.close
end
def run
build_params
install_service
end
end
class DeleteCommand < Mongrel::Command::Command
include GenericCommand
def run
display_name = Service.getdisplayname(@svc_name)
begin
Service.stop(@svc_name)
rescue
end
begin
Service.delete(@svc_name)
rescue
end
puts "#{display_name} service deleted."
end
end
class StartCommand < Mongrel::Command::Command
include GenericCommand
def run
display_name = Service.getdisplayname(@svc_name)
begin
Service.start(@svc_name)
started = false
while started == false
s = Service.status(@svc_name)
started = true if s.current_state == "running"
break if started == true
puts "One moment, " + s.current_state
sleep 1
end
puts "#{display_name} service started"
rescue ServiceError => err
puts "There was a problem starting the service:"
puts err
end
end
end
class StopCommand < Mongrel::Command::Command
include GenericCommand
def run
display_name = Service.getdisplayname(@svc_name)
begin
Service.stop(@svc_name)
stopped = false
while stopped == false
s = Service.status(@svc_name)
stopped = true if s.current_state == "stopped"
break if stopped == true
puts "One moment, " + s.current_state
sleep 1
end
puts "#{display_name} service stopped"
rescue ServiceError => err
puts "There was a problem stopping the service:"
puts err
end
end
end
Mongrel::Command::Registry.instance.run ARGV

View file

@ -0,0 +1,194 @@
###############################################
# mongrel_rails_svc.rb
#
# This is where Win32::Daemon resides.
###############################################
require 'rubygems'
require 'mongrel'
require 'optparse'
require 'win32/service'
DEBUG_LOG_FILE = File.expand_path(File.dirname(__FILE__) + '/debug.log')
#STDERR.reopen(DEBUG_LOG_FILE)
# There are need for SimpleHandler
require 'yaml'
require 'zlib'
class RailsHandler < Mongrel::HttpHandler
def initialize(dir, mime_map = {})
@files = Mongrel::DirHandler.new(dir,false)
@guard = Mutex.new
# register the requested mime types
mime_map.each {|k,v| Mongrel::DirHandler::add_mime_type(k,v) }
end
def process(request, response)
# not static, need to talk to rails
return if response.socket.closed?
if @files.can_serve(request.params["PATH_INFO"])
@files.process(request,response)
else
cgi = Mongrel::CGIWrapper.new(request, response)
begin
@guard.synchronize do
# Rails is not thread safe so must be run entirely within synchronize
Dispatcher.dispatch(cgi, ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS, response.body)
end
# This finalizes the output using the proper HttpResponse way
cgi.out {""}
rescue Object => rails_error
STDERR.puts "calling Dispatcher.dispatch #{rails_error}"
STDERR.puts rails_error.backtrace.join("\n")
end
end
end
end
class SimpleHandler < Mongrel::HttpHandler
def process(request, response)
response.start do |head,out|
head["Content-Type"] = "text/html"
results = "<html><body>Your request:<br /><pre>#{request.params.to_yaml}</pre><a href=\"/files\">View the files.</a></body></html>"
if request.params["HTTP_ACCEPT_ENCODING"] == "gzip,deflate"
head["Content-Encoding"] = "deflate"
# send it back deflated
out << Zlib::Deflate.deflate(results)
else
# no gzip supported, send it back normal
out << results
end
end
end
end
class RailsDaemon < Win32::Daemon
def initialize(ip, port, rails_root, docroot, environment, mime_map, num_procs, timeout)
File.open(DEBUG_LOG_FILE,"a+") { |f| f.puts("#{Time.now} - daemon_initialize entered") }
@ip = ip
@port = port
@rails_root = rails_root
@docroot = docroot
@environment = environment
@mime_map = mime_map
@num_procs = num_procs
@timeout = timeout
File.open(DEBUG_LOG_FILE,"a+") { |f| f.puts("#{Time.now} - daemon_initialize left") }
end
def load_mime_map
File.open(DEBUG_LOG_FILE,"a+") { |f| f.puts("#{Time.now} - load_mime_map entered") }
mime = {}
# configure any requested mime map
if @mime_map
puts "Loading additional MIME types from #@mime_map"
mime.merge!(YAML.load_file(@mime_map))
# check all the mime types to make sure they are the right format
mime.each {|k,v| puts "WARNING: MIME type #{k} must start with '.'" if k.index(".") != 0 }
end
File.open(DEBUG_LOG_FILE,"a+") { |f| f.puts("#{Time.now} - load_mime_map left") }
return mime
end
def configure_rails
File.open(DEBUG_LOG_FILE,"a+") { |f| f.puts("#{Time.now} - configure_rails entered") }
Dir.chdir(@rails_root)
ENV['RAILS_ENV'] = @environment
require File.join(@rails_root, 'config/environment')
# configure the rails handler
rails = RailsHandler.new(@docroot, load_mime_map)
File.open(DEBUG_LOG_FILE,"a+") { |f| f.puts("#{Time.now} - configure_rails left") }
return rails
end
def service_init
File.open(DEBUG_LOG_FILE,"a+") { |f| f.puts("#{Time.now} - service_init entered") }
@rails = configure_rails
#@rails = SimpleHandler.new
# start up mongrel with the right configurations
@server = Mongrel::HttpServer.new(@ip, @port, @num_procs.to_i, @timeout.to_i)
@server.register("/", @rails)
File.open(DEBUG_LOG_FILE,"a+") { |f| f.puts("#{Time.now} - service_init left") }
end
def service_main
File.open(DEBUG_LOG_FILE,"a+") { |f| f.puts("#{Time.now} - service_main entered") }
File.open(DEBUG_LOG_FILE,"a+") { |f| f.puts("#{Time.now} - server.run") }
@server.run
File.open(DEBUG_LOG_FILE,"a+") { |f| f.puts("#{Time.now} - while RUNNING") }
while state == RUNNING
sleep 1
end
File.open(DEBUG_LOG_FILE,"a+") { |f| f.puts("#{Time.now} - service_main left") }
end
def service_stop
File.open(DEBUG_LOG_FILE,"a+") { |f| f.puts("#{Time.now} - service_stop entered") }
#File.open(DEBUG_LOG_FILE,"a+") { |f| f.puts("#{Time.now} - server.stop") }
#@server.stop
File.open(DEBUG_LOG_FILE,"a+") { |f| f.puts("#{Time.now} - service_stop left") }
end
end
if ARGV[0] == 'service'
ARGV.shift
# default options
OPTIONS = {
:rails_root => Dir.pwd,
:environment => 'production',
:ip => '0.0.0.0',
:port => 3000,
:mime_map => nil,
:num_procs => 20,
:timeout => 120
}
ARGV.options do |opts|
opts.on('-r', '--root PATH', "Set the root path where your rails app resides.") { |OPTIONS[:rails_root]| }
opts.on('-e', '--environment ENV', "Rails environment to run as.") { |OPTIONS[:environment]| }
opts.on('-b', '--binding ADDR', "Address to bind to") { |OPTIONS[:ip]| }
opts.on('-p', '--port PORT', "Which port to bind to") { |OPTIONS[:port]| }
opts.on('-m', '--mime PATH', "A YAML file that lists additional MIME types") { |OPTIONS[:mime_map]| }
opts.on('-P', '--num-procs INT', "Number of processor threads to use") { |OPTIONS[:num_procs]| }
opts.on('-t', '--timeout SECONDS', "Timeout all requests after SECONDS time") { |OPTIONS[:timeout]| }
opts.parse!
end
OPTIONS[:docroot] = File.expand_path(OPTIONS[:rails_root] + '/public')
rails_svc = RailsDaemon.new(OPTIONS[:ip], OPTIONS[:port], OPTIONS[:rails_root], OPTIONS[:docroot], OPTIONS[:environment], OPTIONS[:mime_map], OPTIONS[:num_procs].to_i, OPTIONS[:timeout].to_i)
rails_svc.mainloop
end

View file

@ -51,7 +51,7 @@ class MongrelDaemon < Win32::Daemon
f.puts "stop signal received: " + Time.now.to_s
f.puts "sending stop to mongrel threads: " + Time.now.to_s
}
@http_server.stop
#@http_server.stop
end
def service_pause