Forum: Ruby JRuby 1.3.0 will include Nailgun

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Charles Oliver N. (Guest)
on 2009-05-14 01:46
(Received via mailing list)
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-supp...

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
David P. (Guest)
on 2009-05-14 13:25
(Received via mailing list)
On Thu, 14 May 2009 06:45:25 +0900, Charles Oliver N. wrote:
> 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
Brian C. (Guest)
on 2009-05-14 14:16
David P. wrote:
> 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" :-)
Brian C. (Guest)
on 2009-05-14 15:40
Brian C. 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 <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.
Brian C. (Guest)
on 2009-05-14 15:48
Unfortunately, the name 'railgun' has been taken by a games library :-(
Charles Oliver N. (Guest)
on 2009-05-14 19:09
(Received via mailing list)
Brian C. wrote:
> Brian C. 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

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
David P. (Guest)
on 2009-05-14 20:38
(Received via mailing list)
> 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!

:)
Brian C. (Guest)
on 2009-05-15 00:15
David P. wrote:
> Wow. You got me all excited now!

I've tidied it up a little and pushed the code to
http://github.com/candlerb/snailgun/tree/master

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'm
afraid I don't have time to investigate further.

Regards,

Brian.
Brian C. (Guest)
on 2009-05-15 18:58
Brian C. wrote:
> 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.
This topic is locked and can not be replied to.