I’ve been working on a little piece of Ruby-and-Rack-based Web integration goo, and it’s done enough that we have to figure out deployment. One reason I picked Rack is that it’s advertised as deploying on anything. The environment where this will live has some of this and some of that, and we’re using GlassFish to tie it all together, which seems like an appropriate choice. So, the problem is: How to plug a simple Rack application into GlassFish?
[Update: It’s been suggested by several that all I need is the
GlassFish Gem; see also
Vivek Pandey’s
Plug-in any Ruby/Rack based framework to GlassFish.
Perhaps that would have been a better approach. My concerns were first, my
impression (perhaps wrong?) that the gem brings along a large amount of Rails
stuff and so on, probably not appropriate in an Internet-facing server when
you’re not using that stuff. Second, that my code is heading for a large
hosting environment, run by its own group,
where lots of code aside from mine is being run by an army of GlassFishes;
they want a .war
that they can manage according to their
policies. In any case, the gem might work for you.]
GlassFish is Java-land so we want JRuby. Fortunately, our own Nick Sieger has done a bunch of work on this problem, most of it encapsulated in JRuby-Rack (also see here) and Warbler (see also here and here and here).
Pretty quickly, you discover that for real Rack pipe-fitting you’re going to need Rackup. You’ll notice that name has no link; might a reader suggest one? Rackup is, um, lightly documented. I found (Tutorial) Rackup HowTo and A Passenger Rackup File for Sinatra. Rackup is based on the Rack::Builder DSL, whose documentation is thin even by Ruby’s forgiving standards.
OK, I’ve moaned enough. Here’s how to hook up a minimal Rack application
for GlassFish. Let’s assume you have a class Whatever
whose
call
method you’ll be asking Rack to invoke for
each incoming request. You’ll need to make an instance of
Whatever
, probably initializing it with all sorts of
configuration info specific to your app. Here we go:
Make sure your app runs under
JRuby. It’s a pretty easy install,
and if you’re like most people, you’ll discover instantly that you’re relying
on a whole bunch of gems. No problem, JRuby has its own gem
command, so go get ’em. For JSON you’ll want json_pure
and if
you’re doing any secure Net stuff jruby-openssl
.
My app was fairly lightweight, only a couple thousand lines, and once I got the gems, all the unit tests ran and then it worked first time.
To make sure things were working, I ran it under Mongrel just like I had been with native Ruby (Mongrel comes in a J-flavor too).
Install
GlassFish.
The download I got was a .sh
file, and the installer was an ugly
Swing app, but it did what I wanted and got out of the way. There are lots of
docs online about how to start and stop and manage GlassFish.
Now you’ll need a Rackup config file, which by convention is called config.ru
. It took me a while to figure out
that it’s actually read by the Ruby interpreter, so you can do your object
initialization here using as much Ruby as you need. As for the parameters to
initialize
your Whatever
object, there are lots of ways to get them in:
YAML, web.xml context attributes, JNDI, whatever.
At the top of config.ru
, you might want to to have a
$LOAD_PATH.unshift ...
to make your app files loadable.
Thus, the second last line of config.ru
probably looks like
w = Whatever.new(....)
and for your last line, use
run w
Now set up Warbler, which is just another gem.
Warbler will take your Ruby project, read config.ru
, and pack it
all into a .war
file that you can drop into GlassFish; it
contains everything you need, starting with JRuby itself
By default, Warbler assumes you’re running Rails and sets up all sorts of
stuff for that. The first time you run warble, it makes a file called
config/warble.rb
, which is really a nice piece of work; it shows
you all the options you can set, with the default values, and provides
commentary and example code for how you might go about changing them. You are
almost certainly going to want to change a few things. I told it to include
the gems my code needed, not to include Rails, and give my
.war
a nice friendly name.
Once you’re ready to go, just type warble
and you’ll get your
.war
file. It’ll be big, because it contains more or less all of
Ruby and the gems you need; mine was over 10M in size.
I think that’s about it; you’re ready to go with any old Java app server now. There is all sorts of app-server-fu about how and where you deploy things; I’m no expert and you probably have Operations types who live and breathe this stuff anyhow, and will tell you how things have to be.
As of now, nobody can tell from the outside that my code is now running on GlassFish instead of Mongrel, except for the first couple of requests are slower, and all the rest are faster.
(Thanks to Nick Sieger for advice.)
Comment feed for ongoing:
From: Vivek Pandey (Apr 18 2009, at 01:13)
You can cut down lost of steps. With glassfish v3 all you need is this: http://is.gd/t6AB, a Ruby friendly way, no need to WAR. This is a minimal Rack+Ruby for GlassFish combination as you would do with Mongrel. It would work with both GlassFish v3 (trunk builds) as wel as GlassFish gem.
[link]
From: Rob Britton (Apr 18 2009, at 08:12)
Don't forget to include all your gems in config/warble.rb or they will not get packaged into the .war (at least mine don't).
[link]