Announcing mongrel_jcluster


As I mentioned in my last post, that server/client thing wasn’t the only thing I worked on during the flight. I also did a very useful hack of mongrel_cluster, and turned it into mongrel_jcluster. It’s not very large changes, actually… Almost everything is the same, except that this mongrel plugin only runs in JRuby, and will start several mongrels in the same JVM.

jruby -S gem install mongrel_jcluster
cd your_rails_app
jruby -S mongrel_rails jcluster::configure -p 4000 -N 3 -e production -R 20202 -K thesecretkey
jruby -S mongrel_rails jcluster::start

The only difference in the configuration parameters are -R and -K which is the JRuby server port and key respectively. Now, after executing these commands, it will take some time for the mongrels to get online, so be patient (or monitor the progress in the log-files generated).

I need to warn you that this is still quite experimental and not guaranteed to work in any way. =) But it does for me.

Another thing, if you start Mongrel in production mode, the defualt Rails front-page will give you an error if you try to get at the properties. This is the expected behavior in production mode, though, and nothing wrong with JRuby.



JRuby server


I spent some time on the flight to SF hacking on an idea I’ve had for a while. The result was checked in yesterday in JRuby trunk, and the important files are bin/jrubysrv and bin/jrubycli. This is still quite experimental, and only guaranteed to work in *NIX environments right now.

So, what is it? Well, if you don’t want the overhead of running one JVM for each JRuby process, these two commands allow you to start a JVM that listens on a specific localhost port, and then you can send JRuby commands to that port. You need a key as password, otherwise the process will fail. Right now, this isn’t as high security as it should be, since the key is passed as a command line parameter. This is still not that big of a problem, since the most common scenario is to start a bunch of things, and then not start anything more. Let me illustrate what you can do with a very simple example.

Say that you have a Rails application, and Mongrel for JRuby installed. Go the the base directory of your Rails app and do this:

jrubysrv -p 20202 -k secretkey &
jrubycli -p 20202 -k secretkey -S mongrel_rails -p 4000
jrubycli -p 20202 -k secretkey -S mongrel_rails -p 4001
jrubycli -p 20202 -k secretkey -S mongrel_rails -p 4002
jrubycli -p 20202 -k secretkey -n

Now, if you are patient, in a while there will be three Mongrels running, listening on ports 4000, 4001 and 4002. And they will run inside the same JVM, but in different JRuby runtimes. Quite neat, and very simple. You may wonder about the last command, with the -n flag. That flag tells the JRuby server running at port 20202 to not start any more JRuby processes. In this way, you can start what you need, and then close it down. Due to problems with thread scheduling and safety, I haven’t implemented a way to kill a single runtime. What you instead need to do is use jrubycli with the -t flag, which will kill the whole JRuby server.

Stay tuned for my next post, on what I’ve actually used this functionality to create. (If you have some slight amount of imagination, you should be able to guess from this blog post…)

But now, of to the races. Or CommunityOne in this case. See you there.



Mongrel in JRuby


As I have told you before, we have been working on getting Mongrel working in JRuby off and on for a long while. One or two months ago, I got the Ragel definition ported correctly and the rest working. The plan is to cooperate with Zed and create a JRuby-native Mongrel gem out there, but until then I will describe the steps you need to take to get this working for yourself.

First of all, you need to install gem_plugin. The easiest way is to use gem:

jem install -y gem_plugin --no-rdoc --no-ri

After this is done, you can either download Mongrel-support from svn://rubyforge.org/var/svn/jruby-extras/trunk/mongrel-support, and build the extension manually, or you can download it directly here: http://opensource.ologix.com/http11.jar. If you decide to build it yourself, you first need a current version of JRuby from trunk. Check out mongrel-support from the Subversion repository and execute these commands:

cp $JRUBY_HOME/lib/jruby.jar lib
ant jar

After that you will have a http11.jar-file in lib. Regardless of how you get the http11.jar-file, place it in $JRUBY_HOME/lib/ruby/site_ruby/1.8/. Then you can proceed in a few different ways. You could copy the Mongrel-files from your MRI installation, or you could download Mongrel from version control. Regardless of how, you need to copy mongrel.rb, mutex_fix.rb and the mongrel-directory from Mongrel into $JRUBY_HOME/lib/ruby/site_ruby/1.8/. You can also copy bin/mongrel_rails into $JRUBY_HOME/bin and change the shebang to point to /usr/bin/env jruby. After this, you are good to go with JRuby and Mongrel.



The JRuby Tutorial #3: Playing with Mongrel


This part of the tutorial will be based on some slightly not-released software, but since it is so cool, I bet you will try it anyway. Basically, what I’m going to show you is how to get Mongrel 0.4 working with JRuby, and then how you can serve your JRuby on Rails-application with said version of Mongrel.

What you’ll need
First of all, check out the latest trunk version of JRuby. There are some smoking new fixes in there that is needed for this hack. Next, you will also need to check out the 0.4-branch of Mongrel. This can be done with the following command:

svn co svn://rubyforge.org/var/svn/mongrel/branches/mongrel-0.4

You need to manually copy two parts of mongrel into your JRuby home. If $MONGREL_SRC is the name of the directory where you checked out mongrel, these commands will suffice:

cp -r $MONGREL_SRC/lib/mongrel* $JRUBY_HOME/lib/ruby/site_ruby/1.8
cp $MONGREL_SRC/projects/gem_plugin/lib/gem_plugin.rb $JRUBY_HOME/lib/ruby/site_ruby/1.8
echo '#\!/usr/bin/env jruby' > $JRUBY_HOME/bin/mongrel_rails
cat $MONGREL_SRC/bin/mongrel_rails >> $JRUBY_HOME/bin/mongrel_rails
chmod +x $JRUBY_HOME/bin/mongrel_rails

You will need to download the JRuby-specific http11-extension library. This can be downloaded here, and should also be put in the $JRUBY_HOME/lib/ruby/site_ruby/1.8-directory.

You’re now set to go.

Simple web hosting
I will now show how to set up at small web server, that can serve both files and servlets. There really isn’t much to it. First of all, we need to include some libraries:

require 'mongrel'
require 'zlib'
require 'java'
include_class 'java.lang.System'

Next step is to create a simple HttpHandler (which is like a Servlet, for you Java-buffs):

class SimpleHandler < Mongrel::HttpHandler
def process(request, response)
response.start do |head,out|
head["Content-Type"] = "text/html"
results = <<-"EDN";
<html>
<body>
Your request:
<br/>
<pre>#{request.params.inspect}</pre>
<a href=\"/files\">View the files.</a><br/>
At:
#{System.currentTimeMillis}
</body>
</html>
EDN

if request.params["HTTP_ACCEPT_ENCODING"] == "gzip,deflate"
head["Content-Encoding"] = "deflate"
# send it back deflated
out << Zlib::Deflate.deflate(results)
else
# no gzip supported, send it back normal
out << results
end
end
end
end

Now, this handler basically just generates a bunch of HTML and sends it back. The HTML contains the request parameters. Just to show how easy it is to combine Java-output with Ruby-output, I have added a call to System.currentTimeMillis. This could of course by anything. The last part is to actually make this handler active also. To finalize, we also start the server:

@simple = SimpleHandler.new
@http_server = Mongrel::HttpServer.new('0.0.0.0',3333)
@http_server.register("/", @simple)
if ARGV[0]
@files = Mongrel::DirHandler.new(ARGV[0])
@http_server.register("/files", @files)
end

puts "running at 0.0.0.0:3333"

@http_server.run

If you start this script with:

jruby testMongrel.rb htdocs

you can visit localhost:3333 and expect to see some nice output.

Making it work with Rails
A prerequisite for this part is that you have a functional JRuby on Rails-application using ActiveRecord-JDBC. If that is the case, you just need to go your application directory and execute this command:

$JRUBY_HOME/bin/mongrel_rails --prefix "" start

and everything should just work.

So, that’s it. JRuby on Rails, with Mongrel. Enjoy.