Eric Wong
2009-Aug-14 01:18 UTC
[Mongrel-development] teaching Mongrel to inherit sockets (and replace mongrel_cluster)
This change to Mongrel should be completely harmless for non-UNIX systems, too (it won''t break (or do) anything). This minimal change let Mongrels inherit listen sockets from a parent process, so that parent could be a cluster manager. This means no more port juggling with mongrel_cluster! The entire Mongrel pack will all share one port. Only the manager script (see below) itself relies on UNIX-isms (but I think mongrel_cluster did, too). diff --git a/lib/mongrel.rb b/lib/mongrel.rb index 0619abe..90e99e7 100644 --- a/lib/mongrel.rb +++ b/lib/mongrel.rb @@ -91,7 +91,11 @@ module Mongrel def initialize(host, port, num_processors=950, throttle=0, timeout=60) tries = 0 - @socket = TCPServer.new(host, port) + @socket = if ENV[''LISTEN_FD''] + TCPServer.for_fd(ENV[''LISTEN_FD''].to_i) + else + TCPServer.new(host, port) + end if defined?(Fcntl::FD_CLOEXEC) @socket.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) end --- Here''s my initial cut of a mongrel_cluster replacement, it can definitely be cleaned up and improved upon with real option parsing and such... ---------------------------------- 8< ---------------------------------- #!/usr/bin/env ruby require ''socket'' nr_workers = 4 pids = {} cmd = %w(mongrel_rails start) server = TCPServer.new(''0.0.0.0'', 3000) server.listen 1024 ENV[''LISTEN_FD''] = server.fileno.to_s # pass any signals we receive onto each child process: %w(TERM INT USR1 USR2).each do |sig| trap(sig) do pids.keys.each { |pid| Process.kill(sig, pid) rescue nil } exit 0 if sig == ''TERM'' || sig == ''INT'' # TERM and INT mean death end end nr_workers.times { |i| pids[fork { exec *cmd }] = i } loop do pid, status = Process.waitpid2(-1) i = pids.delete(pid) or next STDERR.puts "reaped worker #{i}: #{status}, respawning..." pids[fork { exec *cmd }] = i end ---------------------------------- 8< ---------------------------------- -- Eric Wong