diff options
Diffstat (limited to 'railties/bin')
-rw-r--r-- | railties/bin/listener | 99 | ||||
-rw-r--r-- | railties/bin/tracker | 106 |
2 files changed, 205 insertions, 0 deletions
diff --git a/railties/bin/listener b/railties/bin/listener new file mode 100644 index 0000000000..2310282204 --- /dev/null +++ b/railties/bin/listener @@ -0,0 +1,99 @@ +require "drb" +ENV["RAILS_ENV"] = 'production' +require "#{File.dirname(__FILE__)}/../config/environment.rb" +require 'fcgi_handler' + +VERBOSE = false + +class Listener + include DRbUndumped + attr_accessor :tracker + + def initialize(timeout = nil) + @timeout = timeout + @mutex = Mutex.new + @active = false + + @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 + end + + def each_cgi(&block) + @cgi_block = block + loop do + @timeout ? sleep(@timeout) : sleep + die! unless @active + @active = false + end + end +end + +class FakeOut < Struct.new(:contents) + def initialize + super("") + end + def write(str) + contents << str + end + def read! + c = contents + self.contents = '' + return c + 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 'ruby', __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 diff --git a/railties/bin/tracker b/railties/bin/tracker new file mode 100644 index 0000000000..3a0c3aafc9 --- /dev/null +++ b/railties/bin/tracker @@ -0,0 +1,106 @@ +require "drb" + +VERBOSE = false + +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 + 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 + end + 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 + end + @processed = false + 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 'ruby', listener_path, 'start-listeners', tracker_uri, n.to_s + 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 |