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