aboutsummaryrefslogtreecommitdiffstats
path: root/railties/bin
diff options
context:
space:
mode:
Diffstat (limited to 'railties/bin')
-rw-r--r--railties/bin/listener147
-rw-r--r--railties/bin/tracker149
2 files changed, 119 insertions, 177 deletions
diff --git a/railties/bin/listener b/railties/bin/listener
index 493ac9dca4..421c453f23 100644
--- a/railties/bin/listener
+++ b/railties/bin/listener
@@ -1,103 +1,86 @@
-require "drb"
-ENV["RAILS_ENV"] = 'production'
-require "#{File.dirname(__FILE__)}/../config/environment.rb"
+#!/usr/local/bin/ruby
+
+require 'stringio'
+require 'fileutils'
require 'fcgi_handler'
-require 'rbconfig'
-VERBOSE = false
+def message(s)
+ $stderr.puts "listener: #{s}" if ENV && ENV["DEBUG_GATEWAY"]
+end
+
+class RemoteCGI < CGI
+ attr_accessor :stdinput, :stdoutput, :env_table
+ def initialize(env_table, input = nil, output = nil)
+ self.env_table = env_table
+ self.stdinput = input || StringIO.new
+ self.stdoutput = output || StringIO.new
+ super()
+ end
+
+ def out(stream) # Ignore the requested output stream
+ super(stdoutput)
+ end
+end
class Listener
include DRbUndumped
- attr_accessor :tracker
-
- def initialize(timeout = nil)
- @timeout = timeout
+
+ def initialize(timeout, socket_path)
+ @socket = File.expand_path(socket_path)
@mutex = Mutex.new
@active = false
-
+ @timeout = timeout
+
@handler = RailsFCGIHandler.new
@handler.extend DRbUndumped
- @output = FakeOut.new
- $stdout = @output
- end
-
- def inform_up(tracker_uri)
- return unless tracker_uri
- tracker = DRbObject.new_with_uri(tracker_uri)
- tracker.register_listener self
- @tracker = tracker
- end
- def inform_down
- @tracker.remove_listener(self) if @tracker
- end
- def run(on_uri, tracker_uri)
- on_uri ||= "drbunix:"
- DRb.start_service(on_uri, self) # Start a server for us
- inform_up tracker_uri
- @handler.process!(self)
- end
-
- def die!
- inform_down
- Kernel.exit 0
- end
-
- def process(input)
- $stderr.puts "listener: received request -- obtaining lock" if VERBOSE
- @mutex.synchronize do
- @active = true
-
- $stderr.puts "listener: obtained -- swaping stdin" if VERBOSE
- $stdin = input
- cgi = CGI.new
-
- $stderr.puts "listener: yielding to FCGI handler..." if VERBOSE
- @cgi_block.call cgi
- $stderr.puts "listener: handler finished, releasing control" if VERBOSE
-
- return @output.read!
- end
+ message 'opening socket'
+ DRb.start_service("drbunix:#{@socket}", self)
+
+ message 'entering process loop'
+ @handler.process! self
end
-
- def each_cgi(&block)
- @cgi_block = block
+
+ def each_cgi(&cgi_block)
+ @cgi_block = cgi_block
+ message 'entering idle loop'
loop do
- @timeout ? sleep(@timeout) : sleep
+ sleep @timeout rescue nil
die! unless @active
@active = false
end
end
-end
-class FakeOut < Struct.new(:contents)
- def initialize
- super("")
- end
- def write(str)
- contents << str
+ def process(env, input)
+ message 'received request'
+ @mutex.synchronize do
+ @active = true
+
+ message 'creating input stream'
+ input_stream = StringIO.new(input)
+ message 'building CGI instance'
+ cgi = RemoteCGI.new(eval(env), input_stream)
+
+ message 'yielding to fcgi handler'
+ @cgi_block.call cgi
+ message 'yield finished -- sending output'
+
+ cgi.stdoutput.seek(0)
+ output = cgi.stdoutput.read
+
+ return output
+ end
end
- def read!
- c = contents
- self.contents = ''
- return c
+
+ def die!
+ message 'shutting down'
+ DRb.stop_service
+ FileUtils.rm_f @socket
+ Kernel.exit 0
end
end
-if ARGV.shift == 'start-listeners'
- tracker = ARGV.shift
- number = (ARGV.shift || '1').to_i
- exit(0) if number.zero?
-
- if number > 1
- fork do
- exec(
- File.join(Config::CONFIG['bin_dir'], Config::CONFIG['RUBY_SO_NAME']),
- __FILE__, 'start-listeners', tracker, (number - 1).to_s
- )
- end
- end
-
- l = Listener.new(90)
- l.run(nil, tracker)
-end \ No newline at end of file
+socket_path = ARGV.shift
+timeout = (ARGV.shift || 90).to_i
+
+Listener.new(timeout, socket_path) \ No newline at end of file
diff --git a/railties/bin/tracker b/railties/bin/tracker
index 17fce67e54..859c9fa0e0 100644
--- a/railties/bin/tracker
+++ b/railties/bin/tracker
@@ -1,110 +1,69 @@
-require "drb"
-require "rbconfig"
+#!/usr/local/bin/ruby
-VERBOSE = false
+require 'drb'
+require 'thread'
+
+def message(s)
+ $stderr.puts "tracker: #{s}" if ENV && ENV["DEBUG_GATEWAY"]
+end
class Tracker
include DRbUndumped
-
- def initialize(timeout = 90, uri = nil)
- @timeout = timeout
- @waiting = []
- @working = []
-
- @waiting_mutex = Mutex.new
-
- DRb.start_service(uri, self)
- @uri = DRb.uri
- end
- def run
- start_listener 3
- sleep 3
-
- background
- end
-
- def register_listener(listener)
- @waiting.push listener
- nil
- end
- def remove_listener(listener)
- @waiting.delete listener
- @working.delete listener
- nil
+
+ def initialize(instances, socket_path)
+ @instances = instances
+ @socket = File.expand_path(socket_path)
+ @active = false
+
+ @listeners = []
+ @instances.times { @listeners << Mutex.new }
+
+ message "using #{@listeners.length} listeners"
+ message "opening socket at #{@socket}"
+
+ @service = DRb.start_service("drbunix://#{@socket}", self)
end
-
+
def with_listener
- listener = @waiting.shift
- unless listener
- start_listener(2) unless @waiting.length + @working.length > 6
- @waiting_mutex.synchronize do
- 10.times do
- sleep 0.5
- listener = @waiting.shift
- break if listener
- end
- unless listener
- ($stderr.puts "Dropping request due to lack of listeners!!!" unless listener) if VERBOSE
- return
- end
+ message "listener requested"
+
+ mutex = has_lock = index = nil
+ 3.times do
+ @listeners.each_with_index do |mutex, index|
+ has_lock = mutex.try_lock
+ break if has_lock
end
+ break if has_lock
+ sleep 0.05
end
-
- @working << listener
- yield listener
- ensure
- if listener
- @working.delete listener
- @waiting << listener
- end
- end
-
- def background
- loop do
- @timeout ? sleep(@timeout) : sleep
- unless @processed
- $stderr.puts "Idle for #{@timeout} -- shutting down tracker." if VERBOSE
- Kernel.exit 0
+
+ if has_lock
+ message "obtained listener #{index}"
+ @active = true
+ begin yield index
+ ensure
+ mutex.unlock
+ message "released listener #{index}"
end
- @processed = false
+ else
+ message "dropping request because no listeners are available!"
end
end
-
- def process(input)
- output = nil
- $stderr.puts "tracker: received request.. obtaining listener" if VERBOSE
- with_listener do |listener|
- $stderr.puts "tracker: obtained -- forwarding request to listener.." if VERBOSE
- @processed = true
- output = listener.process(input)
- $stderr.puts "tracker: listener released control." if VERBOSE
- end
- return output
- end
-
- def start_listener(n = 1)
- tracker_uri = @uri
- listener_path = File.join(File.dirname(__FILE__), 'listener')
- fork do
- exec(
- File.join(Config::CONFIG['bin_dir'], Config::CONFIG['RUBY_SO_NAME']),
- listener_path, 'start-listeners', tracker_uri, n.to_s
- )
+
+ def background(check_interval = nil)
+ if check_interval
+ loop do
+ sleep check_interval
+ message "Idle for #{check_interval}, shutting down" unless @active
+ @active = false
+ Kernel.exit 0
+ end
+ else DRb.thread.join
end
end
-
- def ping
- true
- end
end
-if ARGV.first == "start"
- tracker = Tracker.new(90, ARGV[1])
- socket = (/druby:([^?]*)\?/ =~ ARGV[1]) ? $1 : nil
- require 'fileutils' if socket
-
- begin tracker.run
- ensure
- FileUtils.rm_f(socket) if socket
- end
-end
+socket_path = ARGV.shift
+instances = ARGV.shift.to_i
+t = Tracker.new(instances, socket_path)
+t.background(ARGV.first ? ARGV.shift.to_i : 90) \ No newline at end of file