JettyRails 0.7, Merb 1.0 support

After the 1.0 official release, Merb is gaining more and more attention.

I’ve updated JettyRails to support Merb 1.0 applications, making it a good choice to run your rails and merb applications with JRuby, particularly in development time.

The release notes include:

* Merb 1.0 support!
* jruby-rack updated to the latest release (0.9.3)
* jetty server update to 6.1.14
* JSP and JSP Expression Language support
* some minor bugs

It is very simple to run any Merb 1.0.x and Rails 2.x applications. You just need to have JRuby properly installed, but JettyRails doesn’t work with jruby-1.1.4 (JRUBY-2959). First step is to install jetty-rails:

jruby -S gem install jetty-rails

Then, for Rails applications:

cd myrailsapp
jruby -S jetty_rails

And for Merb applications:

cd mymerbapp
jruby -S jetty_merb

Please note that you can’t use Merb with DataMapper in JRuby right now, but ActiveRecord does the job. Work is being done by Yehuda Katz (wycats) and Nick Sieger to port the native parts of DataObjects (used by DataMapper) in the do_jdbc project. Because of that, you can’t just install the merb gem. Wanted Merb modules should be installed separately:

jruby -S gem install merb-core # required
jruby -S gem install merb-more # extras

Play with JMaglev yourself

JMaglev is finally public available!

I’m releasing my experiments with JRuby and Terracotta, so you can play with JMaglev and contribute some code. The project is in Github.

I had to patch JRuby to make RubyObjects a little less dependent from the JRuby Runtime. It isn’t perfect yet, but is working. The patch against the current jruby trunk (rev. 8091) and the patched jruby-complete are included in the project.

The code in Github is just a TIM (Terracotta Integration Module) with a sample maven project and the JMaglev use-case included. Unfortunately, I haven’t any time yet to upload the TIM to Terracotta Forge. BTW, does anyone know how to do this?

For those who want to reproduce my JMaglev demo, here is a step-by-step. You must have GIT, Maven 2 and the JDK properly installed. It only works on Linux and OS X. Is anyone wanting to contribute support for Windows users?

  1. git clone git://github.com/fabiokung/clustered-jruby.git
  2. long time waiting, because terracotta-2.7.1 (vanilla) and jruby-complete (patched) are bundled.
  3. cd clustered-jruby
  4. mvn install (although mvn package is enough)
  5. cd jmaglev
  6. start the terracotta server:
    lib/terracotta-2.7.1/bin/start-tc-server.sh
  7. open another two terminals
  8. run the simplified jirb inside them:
  9. cd clustered-jruby/jmaglev
    ./bin/jmaglev jmaglev.rb

  10. Follow the demo. You will be able to share global variables among all jmaglevs:
    require 'hat'
    $hat
    require 'rabbit'
    $hat.put(Rabbit.new)
    
  11. in the other terminal, try to see the magic hat contents:
    $hat
    

I haven’t tested it with rails applications, but right now, it isn’t able to run IRB. I never thought that running IRB could be so hard. 🙂

More drawbacks and limitations are being discussed in the JRuby Users Mailing List.

I hope to see many contributions. Happy hacking!

JRuby, sharing objects across multiple runtimes. JMagLev?

MagLev was a show from the last RailsConf (2008). Presentation and demos of the product are really impressive.

Recently, Brian Takita asked in the JRuby mailing list:

JRuby + TerraCotta == Maglev?

What an idea! In the last few days I’ve tried to make something useful and I’m happy to have something to show.

JRuby + Nailgun and JRuby + Terracotta

Screencast: Reproducing Avi Bryant's Demo with JRuby + Nailgun and JRuby + Terracotta. (5 min)

The first demo runs with Nailgun. The basic idea is to share a single Java VM across all clients, so they can share some objects. The second is much more complete, as its clients have their own Java VM. There are many true interpreters running, and they are sharing objects through Terracotta. Terracotta is responsible for sharing memory in Java VM clusters and, despite of its slow startup, has much more to offer. The shared objects (hats and rabbits) could be automatically persisted by Terracotta, as MagLev also does.

I’ve patched JRuby and configured Terracotta to make demos run. I’ll upload the patches and configuration somewhere, ASAP.

Working on JRuby to make it run multiple runtimes (VMs) at the same time is being really fun!

JRuby and autotest (ZenTest)

JRuby 1.1.2 is going to be released (probably) today and it fixes a bug with $~ constants (Regexp.last_match), which made autotest finally work!

jruby -S gem install ZenTest
cd myproject
jruby -S autotest

I’ve previously submitted a patch to ZenTest guys. It makes the use of autotest possible with any JRuby 1.x, but now, with JRuby 1.1.2, autotest should just work out of the box!

jetty-rails 0.4 is also jetty-merb

I’ve just released a new version of the jetty-rails gem. Now, you can also run Merb applications inside JRuby and Jetty!

jruby -S gem install jetty-rails
cd mymerbapp
jruby -S jetty_merb

Unfortunately, it’s blocking my console (ctrl + c doesn’t terminate it). Has anyone suggestions on this?

I’ve also updated the basic documentation, as you can see here.

The Merb support was actually done in JRuby Rack. It was quite simple to support it. Many thanks to Nick Sieger, Dudley Flanders e cia!

jetty-rails gem – Simple JRuby On Rails Development with Servlet Containers

This is the first time I’m writing about it, but jetty-rails is already 0.3!

Most people doing JRuby on Rails development are using JMongrels1 for development and some real Java Application Server in production.

The common flow is:

$ jruby script/server 
=> Booting Mongrel (use 'script/server webrick' to force WEBrick)
=> Rails application starting on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
** Starting Mongrel listening at 0.0.0.0:3000
** Starting Rails with development environment...

code, code, test, code, code, test, … (shouldn’t it be red-green-refactor?)

$ jruby -S warble
$ cp myapp.war $TOMCAT_HOME/webapps
$ $TOMCAT_HOME/bin/startup.sh

Sure you can automate those things with ant, rake, sake or anything else. Some people are still using the goldspike-plugin, but be warned: I suspect it won’t get much more attention.

The great Warbler from Nick Sieger is becoming the de facto standard for JRuby on Rails packaging. The Warbler’s recent move from goldspike to JRuby-Rack adapter reveals two interesting points:

  1. Goldspike is likely going to be deprecated (or merged with jruby-rack adapter?).
  2. Warbler will soon package any rack compatible application to be runned inside Java Containers. Such applications include Merb, Sinatra, Vintage, Camping ones, and growing

Although Warbler works really well, it introduces complexity in the development cycle. You can no more save code and immediately test it in your browser:

  1. change code;
  2. warble it;
  3. deploy war file;
  4. restart server; (takes long time)
  5. open browser;
  6. change code;

It breaks one of the most important rails development characteristics: instant feedback. During development, it’s very important to see changes without have to wait for server/context restarting.

JMongrel and Glassfish Gem are good candidates for JRuby on Rails development with instant feedback, but you can’t use Java (Servlet specification) specific features, such as web.xml; they aren’t complete Servlet Containers. Some things have an alternative in pure-rails as Servlet Filters and Servlet Listeners, but many haven’t. Servlet Context might be a good way to share things between rails runtimes. I know railers should “share nothing”, but -hey- sometimes it’s so good to share!

You can take the Servlet Application Context as your in-memory cache store (fragment and page caching), eliminating the need for filesystem or database overhead and even memcached, in many cases.

I had also a specific reason to share the same HttpSession between Rails and “pure Java” applications. Single sign-on wasn’t an option, so I needed to run both applications in the same context. I’m going to tell more about it soon.

Anyone can fall in cases, like mine, when you just can’t use jmongrel or glassfish_rails. Now, we fortunately have jetty-rails to rescue!

It’s a (one more) gem to run rails applications, based on the nice JRuby-Rack adapter, which I recommend you to take a look. Jetty is a very powerful Servlet Container, known for being pioneer at being embedded and at using NIO Connectors.

The gem creates a Jetty Server with two Handlers. The first is for static content and the last to serve dynamic requests using JRuby-Rack. These handlers are applied in order and request processing stops when one responds. That way, no rails code is runned to serve static content, improving response times. Take a look at the rdocs for more details.

Jetty is also very quick to start. I’ve measured (in a complete inaccurate way) some start times just for ugly2 comparison:

$ jruby -v
ruby 1.8.6 (2008-03-28 rev 6360) [i386-jruby1.1]
$ time jruby script/server
=> Booting Mongrel (use 'script/server webrick' to force WEBrick)
=> Rails application starting on http://0.0.0.0:3000
...
** INT signal received.
Exiting

real	0m13.947s
user	0m11.327s
sys	0m0.892s

$ ruby -v
ruby 1.8.6 (2007-09-24 patchlevel 111) [universal-darwin9.0]
$ time ./script/server 
=> Booting Mongrel (use 'script/server webrick' to force WEBrick)
=> Rails application starting on http://0.0.0.0:3000
...
** INT signal received.
Exiting

real	0m6.273s
user	0m1.893s
sys	0m0.611s

With the same JRuby 1.1 (and without Charles recent speedup patch for jruby startup):

$ time jruby -S jetty_rails
2008-05-04 10:50:00.846::INFO:  Logging to STDERR via org.mortbay.log.StdErrLog
2008-05-04 10:50:01.013::INFO:  jetty-6.1.9
...
2008-05-04 10:50:02.987::INFO:  Started SelectChannelConnector@0.0.0.0:8080

real	0m7.035s
user	0m4.387s
sys	0m0.296s

As you can see, jetty_rails is very close to mongrel running in MRI, but please, don’t take those numbers so seriously.

Jetty Rails should be ready to run any rails application (tell me otherwise!) with no dependencies on extra jars. All gems used by the application must be installed in your JRuby. I’ve made some simple benchmarks with JMeter and only one thread, firing 500 consecutive requests to a simple rails blog application. All requests pointed to ‘/posts’ controller, and there was only one Post is the MySQL database.

The machine used to run all tests is a Intel Core2 Duo E4500 @ 2.20GHz, 2.0GB RAM, running Ubuntu 7.10, Ruby (MRI) 1.8.6 and JRuby 1.1.1. MRI tests were done using plain ruby activerecord-mysql-adapter and JRuby tests were done using activerecord-jdbcmysql-adapter.

Mongrel: 30.7 req/s
JMongrel: 19.1 req/s

Glassfish Gem: 17.5 req/s
dropping JVM warm time: 23.8 req/s

Jetty Rails: 18.2 req/s
dropping JVM warm time: 26.6 req/s

This is obviously a simple measure, just to feel how jetty-rails is going. But I’m very happy with the results. If we ignore the time that JVM takes to warm and JIT compile things, jetty-rails comes close to Mongrel! Impressive. I knew Jetty was always very fast, but I really didn’t expect those results.

There is much more to do. Things from the roadmap I wanted to see working soon include:

  • read warble.rb configuration files and register extra jars and public folders defined there;
  • use any custom web.xml defined in config/web.xml (or config/web.erb.xml), following Wabler conventions.
  • jetty_merb
  • jetty_camping

The source code lives in GitHub. Feel free to fork, contribute, send patches and suggestions!


  1. Can we stop calling everything that comes from Java with that damn J-at-start or with –let termination? 😉
  2. I’ve stopped the processes (ctrl+c) as soon as I saw they were ready to respond to requests.