Hello, Nailgun; Goodbye, JVM Startup Delays
One of the frustrations of working with JRuby is that every single time you run it, you start a whole new JVM. This takes seconds:
>time jruby -e 'puts(123)' 123 jruby -e 'puts(123)' 1.94s user 0.11s system 178% cpu 1.144 total
If you’re using JRuby, and working with gem, rspec, irb, and other JRuby tools, this waiting time adds up and can be frustrating.
Nailgun is a Java utility that starts up a JVM and behaves like a server, accepting client requests to run Java based software on it. The JRuby team did a great job of integrating it into JRuby, making it trivially simple to use.
To start the server, just run:
jruby --ng-server # 'jruby' can be replaced with 'ruby' if running in rvm
To connect to it, all you need to do is add “–ng” to the JRuby command or the JRUBY_OPTS environment variable’s value. If you always wanted to use it, you could just include “–ng” in the export of JRUBY_OPTS in your startup script (.bashrc, .zshrc, etc.). However, this may not be a good idea. The Nailgun web site says “…it’s not secure. Not even close”. In addition, you probably want longer running tasks to have their own JVM’s. This being the case, it can be better to default to not use Nailgun, instead specifying the use of it when needed.
In my work, I found that I always wanted to use Nailgun with utilities (rspec, irb, etc.), but that I couldn’t use it with my gem’s bin executable running in 1.9 mode. (I believe this is fixed in a 1.7 version of JRuby.) So here’s what I did…
I created the scripts below in my ~/bin directory. (I use a ~/bin directory for home grown scripts and such that I don’t want to bother installing in a root-owned directory.)
ngs, to run the Nailgun server:
JRUBY_OPTS="" ruby --ng-server
I set JRUBY_OPTS to the empty string because my default setting is “–1.9″, and at this version, the Nailgun server will not start when JRUBY_OPTS is nonempty or when certain options are specified on its command line. (See issues 6246, 5611, and 6251).
ng, to run any JRuby command with Nailgun (used by ngem, etc.):
JRUBY_OPTS="$JRUBY_OPTS --ng" $*
nruby, to run the JRuby interpreter itself:
JRUBY_OPTS="$JRUBY_OPTS --ng" ruby $*
ng gem $*
ng rspec $*
ng irb $*
This can also be done with rails, of course, but I haven’t tested it thoroughly, so I suggest keeping an eye on things to make sure it works ok.
ng rails $*
To quickly create these all, change to the directory that will contain them and run this script:
echo 'JRUBY_OPTS="" ruby --ng-server' > ngs; chmod +x ngs echo 'JRUBY_OPTS="$JRUBY_OPTS --ng" $*' > ng; chmod +x ng echo 'JRUBY_OPTS="$JRUBY_OPTS --ng" jruby $*' > nruby; chmod +x nruby echo 'ng rspec $*' > nrspec; chmod +x nrspec echo 'ng irb $*' > nirb; chmod +x nirb echo 'ng gem $*' > ngem; chmod +x ngem echo 'ng rails $*' > nrails; chmod +x nrails # Rehash reloads binaries from your path to be available for autocompletion # on the command line in this shell. rehash
It would probably be simpler to create aliases instead of shell scripts, but I like being able to easily modify these kinds of scripts, sometimes with multiple lines, so this works well for me.
If you’ll be executing the code below, make sure you’ve started the Nailgun server, either using the ngs script we created, or the command shown at the top of the article.
The scripts will not always work. When the arguments include quoted strings that include spaces, things may get messed up. Here’s an example:
>nruby -e "puts 123" # (produces blank string) >nruby -e "puts(123)" 123
Running the same trivial Ruby script as before, but with Nailgun this time, we get:
>time nruby -e 'puts(123)' 123 nruby -e 'puts(123)' 0.00s user 0.01s system 3% cpu 0.197 total
I recently needed to do some cycles of delete gem; build gem; install gem. This was easy to put together on a single line so I could just scroll up my history to repeat the process. Here are the timings, first without, and then with, Nailgun. I’ve removed irrelevant output for brevity’s sake.
>time (echo Y | gem uninstall life_game_viewer; gem build *gemspec; gem install life_game_viewer) 31.74s user 1.29s system 235% cpu 14.021 total
>time (echo Y | ngem uninstall life_game_viewer; ngem build *gemspec; ngem install life_game_viewer) 0.01s user 0.02s system 0% cpu 3.073 total
Pretty amazing, eh?
Leave a Response
You must be logged in to post a comment.