Container Managed Database Connections With Rails
This is a follow up to my recent post about running Redmine on Tomcat.
One of the more useful features of Java application servers is their ability to provide services to the applications they host, freeing them up from the task to set up these services themselves. Most commonly this is used for database connections - instead of each application managing its own connections, the application server becomes the central place where database connections are configured.
So how do we get hold of such a container-managed connection for our Rails app to use?
This happens through JNDI, which in general is a protocol used to resolve resources in application servers by their name. So the only piece of configuration that needs to be shared between server and application is the JNDI name of the configured connection resource.
Connection pool setup
First things first, if we want the app server to manage our DB connections, it needs the JDBC driver, which until now was only bundled in our WAR file. You can download it from the PostgreSQL web pages, or simply copy the jar from the jdbc-postgres gem:
$ cp $GEM_HOME/gems/jdbc-postgres-9.4.1200/lib/postgresql-9.4-1200.jdbc41.jar ~/apache-tomcat-8.0.24/lib
Resources like the connection pool can either be configured globally (in case you
want to share the same database between applications), or just for a given
application, which is what we do here by creating an XML file corresponding to the
context our application runs in.
Simply put: if your Rails app runs at /redmine
, name the file redmine.xml
:
$ vi ~/apache-tomcat-8.0.24/conf/Catalina/localhost/redmine.xml
Yay, finally some XML! Here you go:
<Context>
<Resource name="jdbc/redmine_db" auth="Container"
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
type="javax.sql.DataSource"
driverClassName="org.postgresql.Driver"
url="jdbc:postgresql://127.0.0.1:5432/jruby_redmine_dev"
username="redmine" password="secret" maxTotal="20" maxIdle="10"
maxWaitMillis="-1"
timeBetweenEvictionRunsMillis="30000"
removeAbandoned="true"
removeAbandonedTimeout="60"
testWhileIdle="true"
validationQuery="select 1"
/>
</Context>
This declares a connection pool managing connections to our PostgreSQL instance. The
name
attribute holds the JNDI name of our connection, which we may freely
choose. Just remember it for the next step and amend database connection
string, username and password as needed. Check out the docs
for more information about the other attributes.
JNDI Resource lookup
Inside the application, we need to reference the JNDI name in two places. First of
all in web.xml
, which is the central piece of metadata describing the
application. Luckily Warbler has us covered here - just uncomment
the config.webxml.jndi
line at the very end of config/warble.rb
and set
the JNDI name:
config.webxml.jndi = 'java:comp/env/jdbc/redmine_db'
That java:comp/env/
prefix is probably different in other application servers, for
Tomcat (and AFAIR also JBoss) it has to be like that.
Also be sure to change config/database.yml
so it points to the connection pool:
production:
adapter: postgresql
jndi: java:comp/env/jdbc/redmine_db
Turn off the built in connection pooling of ActiveRecord
With Tomcat providing the connection pooling it is a good idea to
disable Rails’ connection pooling altogether. That’s not totally trivial, as suggested
in the ActiveRecord-JDBC docs, we use Bogacs for that. After
adding it to the Gemfile
(Gemfile.local
in the case of Redmine) we initialize
the FalsePool
in config/application.rb
:
if Rails.env.production?
pool_class = ActiveRecord::Bogacs::FalsePool
ActiveRecord::ConnectionAdapters::ConnectionHandler.connection_pool_class = pool_class
end
Congratulations! You may now call your Rails app Enterprise Ready.