[ANN] JRuby 1.3.0 will include Nailgun

  • Thread starter Charles Oliver Nutter
  • Start date
C

Charles Oliver Nutter

Nailgun is a tool that speeds up Java command startup by punting
commands to an always-running "server" JVM. The improvement for JRuby is
substantial, with bare-bones startup times improving tenfold.

There's work to be done, like to get signals to forward from the client
to the server and to more easily manage server instances, but it's a
good start. We're looking for people to try it out (to be released in
RC2 soon) and give us feedback.

http://blog.headius.com/2009/05/jruby-nailgun-support-in-130.html

Here's a short sample session using JRuby with Nailgun:

~/projects/jruby âž” cd tool/nailgun/ ; make ; cd -
Building ng client. To build a Windows binary, type 'make ng.exe'
gcc -Wall -pedantic -s -O3 -o ng src/c/ng.c
ld warning: option -s is obsolete and being ignored
/Users/headius/projects/jruby

~/projects/jruby âž” jruby --ng-server
NGServer started on all interfaces, port 2113.
^Z
[1]+ Stopped jruby --ng-server

~/projects/jruby âž” bg
[1]+ jruby --ng-server &

~/projects/jruby âž” jruby --ng -e "puts 1"
1

~/projects/jruby âž” time jruby -e "puts 1"
1

real 0m0.609s
user 0m0.482s
sys 0m0.119s

~/projects/jruby âž” time jruby --ng -e "puts 1"
1

real 0m0.073s
user 0m0.010s
sys 0m0.018s

- Charlie
 
D

David Palm

Nailgun is a tool that speeds up Java command startup by punting
commands to an always-running "server" JVM. The improvement for JRuby
is substantial, with bare-bones startup times improving tenfold.

This is so cool. I've been wanting something like it forever.

Is the nailgun implementation similar in concept to perperl (or PersistentPerl, http://daemoninc.com/PersistentPerl/)? Is there anything like it for MRI as well? In your opinion, would it be feasible?

Kudos!

David
 
B

Brian Candler

David said:
This is so cool. I've been wanting something like it forever.

Is the nailgun implementation similar in concept to perperl (or
PersistentPerl, http://daemoninc.com/PersistentPerl/)? Is there anything
like it for MRI as well? In your opinion, would it be feasible?

It would be wonderful if it could have all the Rails Active* libraries
preloaded; that would drastically shorten the startup time for unit
tests etc.

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" :)
 
B

Brian Candler

Brian said:
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 <pid> <cmd> <args...>

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.
 
C

Charles Oliver Nutter

Brian said:
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

This is essentially the magic behind Passenger, which also manages the
child processes and balances requests across them. So yeah, it's doable
and not too peculiar.

- Charlie
 
D

David Palm

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

Wow. You got me all excited now!

:)
 
B

Brian Candler

Brian said:
However, don't get too excited - it doesn't play particularly well with
Rails yet. In particular, "frake test:units" doesn't run any tests.

I've fixed that, and a number of other issues, and now it actually plays
rather well with Rails.

The new code detects that you are using rails and start multiple
processes, one for each environment of interest (by default 'test' and
'development'), so that you can have a near-instant startup for either
purpose.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,174
Messages
2,570,940
Members
47,484
Latest member
JackRichard

Latest Threads

Top