diff options
-rw-r--r-- | examples/mongrel_rails_service.rb | 237 | ||||
-rw-r--r-- | examples/mongrel_rails_svc.rb | 194 | ||||
-rw-r--r-- | examples/mongrel_simple_service.rb | 2 |
3 files changed, 432 insertions, 1 deletions
diff --git a/examples/mongrel_rails_service.rb b/examples/mongrel_rails_service.rb new file mode 100644 index 0000000..a0c4454 --- /dev/null +++ b/examples/mongrel_rails_service.rb @@ -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
diff --git a/examples/mongrel_rails_svc.rb b/examples/mongrel_rails_svc.rb new file mode 100644 index 0000000..1ce8781 --- /dev/null +++ b/examples/mongrel_rails_svc.rb @@ -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
+
diff --git a/examples/mongrel_simple_service.rb b/examples/mongrel_simple_service.rb index 8e82c7b..3f9bc2c 100644 --- a/examples/mongrel_simple_service.rb +++ b/examples/mongrel_simple_service.rb @@ -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
|