From: Brian Candler Date: 2009-05-14T20:40:40+09:00 Subject: Re: JRuby 1.3.0 will include Nailgun Brian Candler wrote: > I don't see in principle why it couldn't be done - I guess you just fork > the process when a request comes in. The messy bit is passing the > stdin/stdout/stderr file descriptors over a socket. And it could be > called "railgun" :-) It turns out all the messy passing of IO objects is already included in the Ruby standard socket library, so without further ado, here's a working proof-of-concept :-) Tested under ruby 1.8.6p111 $ cat hello.rb # Silly program which requires active_support to work puts ''.blank? $ time ruby -rubygems -e'require "active_support"' -e 'load "hello.rb"' true real 0m1.522s user 0m1.280s sys 0m0.216s $ ruby -rubygems -railgun -e'require "active_support"' Railgun PID 10272 started [in another console] $ time ./rg 10272 hello.rb true real 0m0.076s user 0m0.036s sys 0m0.012s ---- 8< ---- ailgun.rb ---- # Sample usage: # ruby -rubygems -railgun -e'require "active_support"' # Note that at least one '-e' option is required, e.g. -e0 at_exit do require 'socket' sockname = "/tmp/railgun#{$$}" File.delete(sockname) rescue nil trap('INT') { File.delete(sockname) rescue nil; exit! } server = UNIXServer.open(sockname) puts "Railgun PID #{$$} started" while client = server.accept fork do begin STDIN.reopen(client.recv_io) STDOUT.reopen(client.recv_io) STDERR.reopen(client.recv_io) # [script, args] # TODO: interpret flags like -I and -r nbytes = client.read(4).unpack("N").first args = Marshal.load(client.read(nbytes)) client.close cmd = args.shift ARGV.replace(args) load cmd rescue Exception => e STDERR.puts e client.close rescue nil end end client.close end end ---- 8< ---- ---- 8< ---- rg.rb ---- #!/usr/bin/env ruby # Usage: ruby rg.rb require 'socket' pid = ARGV.shift server = UNIXSocket.open("/tmp/railgun#{pid}") args = Marshal.dump(ARGV) server.send_io(STDIN) server.send_io(STDOUT) server.send_io(STDERR) server.write [args.size].pack("N") server.write args ---- 8< ---- The awkward thing from a user point of view is that you have to remember the pid of where the railgun server is. You could use a fixed name, but that would only let you have a single railgun process preloaded with a single set of libraries. Perhaps it would be better for the railgun server to drop you into a new shell which has something in the ENV with this information. -- Posted via http://www.ruby-forum.com/.