JDBC Connection Pooling for Rails on Glassfish

August 19, 2008

In Light Engineering (LED), we’re known to be multilingual – depending on the project, we’ve been known to speak Perl, Python, Java, C++, Javascript and PHP, to name a few. Our weapon of choice is still Ruby on Rails, the popular MVC framework. Out belief is that Rails makes certain types of tasks easy, and others laughably trivial. That being said, LinkedIn is still primarily a Java shop, and for good reason. Java technologies are mature, proven, and all around solid. For this reason, LED has had a very vested interest in the development work that is going into JRuby.

We started a few months ago around the time JRuby 1.1.2 went live by switching some of our Rails applications to run on Glassfish. Using Warbler, we successfully wrapped our Rails applications into WAR files and deployed on Glassfish (we’ll probably write a more detailed tutorial of this at a future date). A WAR file is completely self contained application that can be deployed simply by copying to an autodeploy directory. No more Apache/Nginx reverse proxy, no more Capistrano, no more installing gems on a production container, no more of any of that madness. This was a huge win, and we broke out the champagne bottles.

But we weren’t done. We weren’t taking advantage of many Java technologies, most notably, we weren’t taking advantage of the JDBC connection pooling capabilities of the Glassfish application server for our MySQL database.

We started by reading this tutorial by Arun Gupta of Sun. The article is fantastic, but the one criticism I have is that it was written from the perspective of a master Java engineer that learned Rails, as opposed to that of a Rails engineer approaching JRuby.

From a high level, here are the steps needed to enable JDBC connection pooling for a Rails application running in a Glassfish container:

  1. Define a JDBC connection pool.
  2. Define a JDBC resource with a JNDI name.
  3. Download and install the MySQL connection adapter.
  4. Update database.yml to use JDBC.
  5. Configure ActiveRecord to disconnect after every query.

Believe it or not, there are only five steps. I have to admit, I was initially intimidated. Java allows so much power and flexibility that, to a novice, seeing a hundred configuration choices in the Glassfish admin web UI can be a deterrent. As it turns out, we only need to touch two parts of that UI. Let's get started:

1. Define a JDBC connection pool.

Log in to your Glassfish application server. Expand Resources->Connection Pools.

Click new. You’ll be presented with three fields. The name is arbitrary, but you’ll need to know it later. Select javax.sql.DataSource as the resource type, and MySQL as the vendor.

The next screen will have more options. Change the datasource classname to com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource

Under additional properties, there should be fields configuring the database connection. Set these as appropriate.

2. Define a JDBC resource with a JNDI name.

JNDI stands for Java Naming and Directory Interface, and will allow us to create a standardized name for the JDBC connection pool we just created.

In the navigation pane, click through to Resources -> JDBC -> JDBC Resources. Click new.

In the drop down box, select the JDBC connection pool created in step 1. For the JNDI name, it’s accepted practice to name it jdbc/connection_name.

3. Download and install the MySQL connection adapter.

tar zxvf mysql-connector-java-VERSION.tar.gz
cd mysql-connector-java-VERSION
ant
cp mysql-connector-java-VERSION-bin.jar $GLASSFISH_HOME/lib

You may have to restart Glassfish for the install to work:

asadmin stop-domain DOMAIN
asadmin start-domain DOMAIN

4. Update database.yml to use JDBC.

In your config/database.yml file, we need to tell Rails to use the connection pool rather than directly connecting to the database. Here’s a snippet of our production configuration:

production:
adapter: jdbc
jndi: jdbc/polls
driver: com.mysql.jdbc.Driver

That’s all you will need. Unlike standard configuration files, you do not need to specify things like the username, password or host because these are configured in the Application Server. I like this method because it means the engineer doing the deployment does not need to build the YAML file each time, check it in to SVN, or copy from a database.yml template with the production settings. It’s one less deployment step, and ultimately, one less item on the security checklist.

5. Configure ActiveRecord to disconnect after every query.

ActiveRecord maintains a persistent connection to the database. This is no longer necessary, as there is very little overhead in opening a connection to JDBC, which manages the connection persistence. We’ll need to disable this. I’m using code borrowed from Nick Sieger's awesome presentation at RailsConf 2008:

# config/initializers/close_connections.rb
if defined?($servlet_context)
require 'action_controller/dispatcher'


ActionController::Dispatcher.after_dispatch do
ActiveRecord::Base.clear_active_connections!
end
end

You’re done! Now all you have to do is build the WAR file and drop it in Glassfish’s autodeploy directory.

Topics