aboutsummaryrefslogtreecommitdiffstats
path: root/railties/lib/commands/process
diff options
context:
space:
mode:
Diffstat (limited to 'railties/lib/commands/process')
-rw-r--r--railties/lib/commands/process/inspector.rb68
-rw-r--r--railties/lib/commands/process/reaper.rb149
-rw-r--r--railties/lib/commands/process/spawner.rb219
-rw-r--r--railties/lib/commands/process/spinner.rb57
4 files changed, 0 insertions, 493 deletions
diff --git a/railties/lib/commands/process/inspector.rb b/railties/lib/commands/process/inspector.rb
deleted file mode 100644
index 8a6437e715..0000000000
--- a/railties/lib/commands/process/inspector.rb
+++ /dev/null
@@ -1,68 +0,0 @@
-require 'optparse'
-
-if RUBY_PLATFORM =~ /(:?mswin|mingw)/ then abort("Inspector is only for Unix") end
-
-OPTIONS = {
- :pid_path => File.expand_path(RAILS_ROOT + '/tmp/pids'),
- :pattern => "dispatch.*.pid",
- :ps => "ps -o pid,state,user,start,time,pcpu,vsz,majflt,command -p %s"
-}
-
-class Inspector
- def self.inspect(pid_path, pattern)
- new(pid_path, pattern).inspect
- end
-
- def initialize(pid_path, pattern)
- @pid_path, @pattern = pid_path, pattern
- end
-
- def inspect
- header = `#{OPTIONS[:ps] % 1}`.split("\n")[0] + "\n"
- lines = pids.collect { |pid| `#{OPTIONS[:ps] % pid}`.split("\n")[1] }
-
- puts(header + lines.join("\n"))
- end
-
- private
- def pids
- pid_files.collect do |pid_file|
- File.read(pid_file).to_i
- end
- end
-
- def pid_files
- Dir.glob(@pid_path + "/" + @pattern)
- end
-end
-
-
-ARGV.options do |opts|
- opts.banner = "Usage: inspector [options]"
-
- opts.separator ""
-
- opts.on <<-EOF
- Description:
- Displays system information about Rails dispatchers (or other processes that use pid files) through
- the ps command.
-
- Examples:
- inspector # default ps on all tmp/pids/dispatch.*.pid files
- inspector -s 'ps -o user,start,majflt,pcpu,vsz -p %s' # custom ps, %s is where the pid is interleaved
- EOF
-
- opts.on(" Options:")
-
- opts.on("-s", "--ps=command", "default: #{OPTIONS[:ps]}", String) { |v| OPTIONS[:ps] = v }
- opts.on("-p", "--pidpath=path", "default: #{OPTIONS[:pid_path]}", String) { |v| OPTIONS[:pid_path] = v }
- opts.on("-r", "--pattern=pattern", "default: #{OPTIONS[:pattern]}", String) { |v| OPTIONS[:pattern] = v }
-
- opts.separator ""
-
- opts.on("-h", "--help", "Show this help message.") { puts opts; exit }
-
- opts.parse!
-end
-
-Inspector.inspect(OPTIONS[:pid_path], OPTIONS[:pattern])
diff --git a/railties/lib/commands/process/reaper.rb b/railties/lib/commands/process/reaper.rb
deleted file mode 100644
index 95175d41e0..0000000000
--- a/railties/lib/commands/process/reaper.rb
+++ /dev/null
@@ -1,149 +0,0 @@
-require 'optparse'
-require 'net/http'
-require 'uri'
-
-if RUBY_PLATFORM =~ /(:?mswin|mingw)/ then abort("Reaper is only for Unix") end
-
-class Killer
- class << self
- # Searches for all processes matching the given keywords, and then invokes
- # a specific action on each of them. This is useful for (e.g.) reloading a
- # set of processes:
- #
- # Killer.process(:reload, "/tmp/pids", "dispatcher.*.pid")
- def process(action, pid_path, pattern, keyword)
- new(pid_path, pattern, keyword).process(action)
- end
-
- # Forces the (rails) application to reload by sending a +HUP+ signal to the
- # process.
- def reload(pid)
- `kill -s HUP #{pid}`
- end
-
- # Force the (rails) application to restart by sending a +USR2+ signal to the
- # process.
- def restart(pid)
- `kill -s USR2 #{pid}`
- end
-
- # Forces the (rails) application to gracefully terminate by sending a
- # +TERM+ signal to the process.
- def graceful(pid)
- `kill -s TERM #{pid}`
- end
-
- # Forces the (rails) application to terminate immediately by sending a -9
- # signal to the process.
- def kill(pid)
- `kill -9 #{pid}`
- end
-
- # Send a +USR1+ signal to the process.
- def usr1(pid)
- `kill -s USR1 #{pid}`
- end
- end
-
- def initialize(pid_path, pattern, keyword=nil)
- @pid_path, @pattern, @keyword = pid_path, pattern, keyword
- end
-
- def process(action)
- pids = find_processes
-
- if pids.empty?
- warn "Couldn't find any pid file in '#{@pid_path}' matching '#{@pattern}'"
- warn "(also looked for processes matching #{@keyword.inspect})" if @keyword
- else
- pids.each do |pid|
- puts "#{action.capitalize}ing #{pid}"
- self.class.send(action, pid)
- end
-
- delete_pid_files if terminating?(action)
- end
- end
-
- private
- def terminating?(action)
- [ "kill", "graceful" ].include?(action)
- end
-
- def find_processes
- files = pid_files
- if files.empty?
- find_processes_via_grep
- else
- files.collect { |pid_file| File.read(pid_file).to_i }
- end
- end
-
- def find_processes_via_grep
- lines = `ps axww -o 'pid command' | grep #{@keyword}`.split(/\n/).
- reject { |line| line =~ /inq|ps axww|grep|spawn-fcgi|spawner|reaper/ }
- lines.map { |line| line[/^\s*(\d+)/, 1].to_i }
- end
-
- def delete_pid_files
- pid_files.each { |pid_file| File.delete(pid_file) }
- end
-
- def pid_files
- Dir.glob(@pid_path + "/" + @pattern)
- end
-end
-
-
-OPTIONS = {
- :action => "restart",
- :pid_path => File.expand_path(RAILS_ROOT + '/tmp/pids'),
- :pattern => "dispatch.[0-9]*.pid",
- :dispatcher => File.expand_path("#{RAILS_ROOT}/public/dispatch.fcgi")
-}
-
-ARGV.options do |opts|
- opts.banner = "Usage: reaper [options]"
-
- opts.separator ""
-
- opts.on <<-EOF
- Description:
- The reaper is used to restart, reload, gracefully exit, and forcefully exit processes
- running a Rails Dispatcher (or any other process responding to the same signals). This
- is commonly done when a new version of the application is available, so the existing
- processes can be updated to use the latest code.
-
- It uses pid files to work on the processes and by default assume them to be located
- in RAILS_ROOT/tmp/pids.
-
- The reaper actions are:
-
- * restart : Restarts the application by reloading both application and framework code
- * reload : Only reloads the application, but not the framework (like the development environment)
- * graceful: Marks all of the processes for exit after the next request
- * kill : Forcefully exists all processes regardless of whether they're currently serving a request
-
- Restart is the most common and default action.
-
- Examples:
- reaper # restarts the default dispatchers
- reaper -a reload # reload the default dispatchers
- reaper -a kill -r *.pid # kill all processes that keep pids in tmp/pids
- EOF
-
- opts.on(" Options:")
-
- opts.on("-a", "--action=name", "reload|graceful|kill (default: #{OPTIONS[:action]})", String) { |v| OPTIONS[:action] = v }
- opts.on("-p", "--pidpath=path", "default: #{OPTIONS[:pid_path]}", String) { |v| OPTIONS[:pid_path] = v }
- opts.on("-r", "--pattern=pattern", "default: #{OPTIONS[:pattern]}", String) { |v| OPTIONS[:pattern] = v }
- opts.on("-d", "--dispatcher=path", "DEPRECATED. default: #{OPTIONS[:dispatcher]}", String) { |v| OPTIONS[:dispatcher] = v }
-
- opts.separator ""
-
- opts.on("-h", "--help", "Show this help message.") { puts opts; exit }
-
- opts.parse!
-end
-
-Killer.process(OPTIONS[:action], OPTIONS[:pid_path], OPTIONS[:pattern], OPTIONS[:dispatcher])
diff --git a/railties/lib/commands/process/spawner.rb b/railties/lib/commands/process/spawner.rb
deleted file mode 100644
index 8bf47abb75..0000000000
--- a/railties/lib/commands/process/spawner.rb
+++ /dev/null
@@ -1,219 +0,0 @@
-require 'active_support'
-require 'optparse'
-require 'socket'
-require 'fileutils'
-
-def daemonize #:nodoc:
- exit if fork # Parent exits, child continues.
- Process.setsid # Become session leader.
- exit if fork # Zap session leader. See [1].
- Dir.chdir "/" # Release old working directory.
- File.umask 0000 # Ensure sensible umask. Adjust as needed.
- STDIN.reopen "/dev/null" # Free file descriptors and
- STDOUT.reopen "/dev/null", "a" # point them somewhere sensible.
- STDERR.reopen STDOUT # STDOUT/ERR should better go to a logfile.
-end
-
-class Spawner
- def self.record_pid(name = "#{OPTIONS[:process]}.spawner", id = Process.pid)
- FileUtils.mkdir_p(OPTIONS[:pids])
- File.open(File.expand_path(OPTIONS[:pids] + "/#{name}.pid"), "w+") { |f| f.write(id) }
- end
-
- def self.spawn_all
- OPTIONS[:instances].times do |i|
- port = OPTIONS[:port] + i
- print "Checking if something is already running on #{OPTIONS[:address]}:#{port}..."
-
- begin
- srv = TCPServer.new(OPTIONS[:address], port)
- srv.close
- srv = nil
-
- puts "NO"
- puts "Starting dispatcher on port: #{OPTIONS[:address]}:#{port}"
-
- FileUtils.mkdir_p(OPTIONS[:pids])
- spawn(port)
- rescue
- puts "YES"
- end
- end
- end
-end
-
-class FcgiSpawner < Spawner
- def self.spawn(port)
- cmd = "#{OPTIONS[:spawner]} -f #{OPTIONS[:dispatcher]} -p #{port} -P #{OPTIONS[:pids]}/#{OPTIONS[:process]}.#{port}.pid"
- cmd << " -a #{OPTIONS[:address]}" if can_bind_to_custom_address?
- system(cmd)
- end
-
- def self.can_bind_to_custom_address?
- @@can_bind_to_custom_address ||= /^\s-a\s/.match `#{OPTIONS[:spawner]} -h`
- end
-end
-
-class MongrelSpawner < Spawner
- def self.spawn(port)
- cmd =
- "mongrel_rails start -d " +
- "-a #{OPTIONS[:address]} " +
- "-p #{port} " +
- "-P #{OPTIONS[:pids]}/#{OPTIONS[:process]}.#{port}.pid " +
- "-e #{OPTIONS[:environment]} " +
- "-c #{OPTIONS[:rails_root]} " +
- "-l #{OPTIONS[:rails_root]}/log/mongrel.log"
-
- # Add prefix functionality to spawner's call to mongrel_rails
- # Digging through mongrel's project subversion server, the earliest
- # Tag that has prefix implemented in the bin/mongrel_rails file
- # is 0.3.15 which also happens to be the earliest tag listed.
- # References: http://mongrel.rubyforge.org/svn/tags
- if Mongrel::Const::MONGREL_VERSION.to_f >=0.3 && !OPTIONS[:prefix].nil?
- cmd = cmd + " --prefix #{OPTIONS[:prefix]}"
- end
- system(cmd)
- end
-
- def self.can_bind_to_custom_address?
- true
- end
-end
-
-
-begin
- require_library_or_gem 'fcgi'
-rescue Exception
- # FCGI not available
-end
-
-begin
- require_library_or_gem 'mongrel'
-rescue Exception
- # Mongrel not available
-end
-
-server = case ARGV.first
- when "fcgi", "mongrel"
- ARGV.shift
- else
- if defined?(Mongrel)
- "mongrel"
- elsif RUBY_PLATFORM !~ /(:?mswin|mingw)/ && !silence_stderr { `spawn-fcgi -version` }.blank? && defined?(FCGI)
- "fcgi"
- end
-end
-
-case server
- when "fcgi"
- puts "=> Starting FCGI dispatchers"
- spawner_class = FcgiSpawner
- when "mongrel"
- puts "=> Starting mongrel dispatchers"
- spawner_class = MongrelSpawner
- else
- puts "Neither FCGI (spawn-fcgi) nor Mongrel was installed and available!"
- exit(0)
-end
-
-
-
-OPTIONS = {
- :environment => "production",
- :spawner => '/usr/bin/env spawn-fcgi',
- :dispatcher => File.expand_path(RELATIVE_RAILS_ROOT + '/public/dispatch.fcgi'),
- :pids => File.expand_path(RELATIVE_RAILS_ROOT + "/tmp/pids"),
- :rails_root => File.expand_path(RELATIVE_RAILS_ROOT),
- :process => "dispatch",
- :port => 8000,
- :address => '0.0.0.0',
- :instances => 3,
- :repeat => nil,
- :prefix => nil
-}
-
-ARGV.options do |opts|
- opts.banner = "Usage: spawner [platform] [options]"
-
- opts.separator ""
-
- opts.on <<-EOF
- Description:
- The spawner is a wrapper for spawn-fcgi and mongrel that makes it
- easier to start multiple processes running the Rails dispatcher. The
- spawn-fcgi command is included with the lighttpd web server, but can
- be used with both Apache and lighttpd (and any other web server
- supporting externally managed FCGI processes). Mongrel automatically
- ships with with mongrel_rails for starting dispatchers.
-
- The first choice you need to make is whether to spawn the Rails
- dispatchers as FCGI or Mongrel. By default, this spawner will prefer
- Mongrel, so if that's installed, and no platform choice is made,
- Mongrel is used.
-
- Then decide a starting port (default is 8000) and the number of FCGI
- process instances you'd like to run. So if you pick 9100 and 3
- instances, you'll start processes on 9100, 9101, and 9102.
-
- By setting the repeat option, you get a protection loop, which will
- attempt to restart any FCGI processes that might have been exited or
- outright crashed.
-
- You can select bind address for started processes. By default these
- listen on every interface. For single machine installations you would
- probably want to use 127.0.0.1, hiding them form the outside world.
-
- Examples:
- spawner # starts instances on 8000, 8001, and 8002
- # using Mongrel if available.
- spawner fcgi # starts instances on 8000, 8001, and 8002
- # using FCGI.
- spawner mongrel -i 5 # starts instances on 8000, 8001, 8002,
- # 8003, and 8004 using Mongrel.
- spawner -p 9100 -i 10 # starts 10 instances counting from 9100 to
- # 9109 using Mongrel if available.
- spawner -p 9100 -r 5 # starts 3 instances counting from 9100 to
- # 9102 and attempts start them every 5
- # seconds.
- spawner -a 127.0.0.1 # starts 3 instances binding to localhost
- EOF
-
- opts.on(" Options:")
-
- opts.on("-p", "--port=number", Integer, "Starting port number (default: #{OPTIONS[:port]})") { |v| OPTIONS[:port] = v }
-
- if spawner_class.can_bind_to_custom_address?
- opts.on("-a", "--address=ip", String, "Bind to IP address (default: #{OPTIONS[:address]})") { |v| OPTIONS[:address] = v }
- end
-
- opts.on("-p", "--port=number", Integer, "Starting port number (default: #{OPTIONS[:port]})") { |v| OPTIONS[:port] = v }
- opts.on("-i", "--instances=number", Integer, "Number of instances (default: #{OPTIONS[:instances]})") { |v| OPTIONS[:instances] = v }
- opts.on("-r", "--repeat=seconds", Integer, "Repeat spawn attempts every n seconds (default: off)") { |v| OPTIONS[:repeat] = v }
- opts.on("-e", "--environment=name", String, "test|development|production (default: #{OPTIONS[:environment]})") { |v| OPTIONS[:environment] = v }
- opts.on("-P", "--prefix=path", String, "URL prefix for Rails app. [Used only with Mongrel > v0.3.15]: (default: #{OPTIONS[:prefix]})") { |v| OPTIONS[:prefix] = v }
- opts.on("-n", "--process=name", String, "default: #{OPTIONS[:process]}") { |v| OPTIONS[:process] = v }
- opts.on("-s", "--spawner=path", String, "default: #{OPTIONS[:spawner]}") { |v| OPTIONS[:spawner] = v }
- opts.on("-d", "--dispatcher=path", String, "default: #{OPTIONS[:dispatcher]}") { |dispatcher| OPTIONS[:dispatcher] = File.expand_path(dispatcher) }
-
- opts.separator ""
-
- opts.on("-h", "--help", "Show this help message.") { puts opts; exit }
-
- opts.parse!
-end
-
-ENV["RAILS_ENV"] = OPTIONS[:environment]
-
-if OPTIONS[:repeat]
- daemonize
- trap("TERM") { exit }
- spawner_class.record_pid
-
- loop do
- spawner_class.spawn_all
- sleep(OPTIONS[:repeat])
- end
-else
- spawner_class.spawn_all
-end
diff --git a/railties/lib/commands/process/spinner.rb b/railties/lib/commands/process/spinner.rb
deleted file mode 100644
index c0b2f09a94..0000000000
--- a/railties/lib/commands/process/spinner.rb
+++ /dev/null
@@ -1,57 +0,0 @@
-require 'optparse'
-
-def daemonize #:nodoc:
- exit if fork # Parent exits, child continues.
- Process.setsid # Become session leader.
- exit if fork # Zap session leader. See [1].
- Dir.chdir "/" # Release old working directory.
- File.umask 0000 # Ensure sensible umask. Adjust as needed.
- STDIN.reopen "/dev/null" # Free file descriptors and
- STDOUT.reopen "/dev/null", "a" # point them somewhere sensible.
- STDERR.reopen STDOUT # STDOUT/ERR should better go to a logfile.
-end
-
-OPTIONS = {
- :interval => 5.0,
- :command => File.expand_path(RAILS_ROOT + '/script/process/spawner'),
- :daemon => false
-}
-
-ARGV.options do |opts|
- opts.banner = "Usage: spinner [options]"
-
- opts.separator ""
-
- opts.on <<-EOF
- Description:
- The spinner is a protection loop for the spawner, which will attempt to restart any FCGI processes
- that might have been exited or outright crashed. It's a brute-force attempt that'll just try
- to run the spawner every X number of seconds, so it does pose a light load on the server.
-
- Examples:
- spinner # attempts to run the spawner with default settings every second with output on the terminal
- spinner -i 3 -d # only run the spawner every 3 seconds and detach from the terminal to become a daemon
- spinner -c '/path/to/app/script/process/spawner -p 9000 -i 10' -d # using custom spawner
- EOF
-
- opts.on(" Options:")
-
- opts.on("-c", "--command=path", String) { |v| OPTIONS[:command] = v }
- opts.on("-i", "--interval=seconds", Float) { |v| OPTIONS[:interval] = v }
- opts.on("-d", "--daemon") { |v| OPTIONS[:daemon] = v }
-
- opts.separator ""
-
- opts.on("-h", "--help", "Show this help message.") { puts opts; exit }
-
- opts.parse!
-end
-
-daemonize if OPTIONS[:daemon]
-
-trap(OPTIONS[:daemon] ? "TERM" : "INT") { exit }
-
-loop do
- system(OPTIONS[:command])
- sleep(OPTIONS[:interval])
-end \ No newline at end of file