Don't like ads? PRO users don't see any ads ;-)
Guest

Untitled

By: a guest on Aug 19th, 2012  |  syntax: None  |  size: 7.34 KB  |  hits: 11  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. # Two Applications, One Trinidad Server
  2.  
  3. One of the advantages of running Ruby on the JVM is that we can deploy multiple applications to the same webserver.  Using one JRuby webserver means that there is only one process to manage, monitor, start and stop. Your sysadmins will thank you.
  4.  
  5. But having mutliple application on one virtual machine also means we can configure them to share resources, thus reducing the overhead required for a production server.  In this post, we'll walk through an example of deploying two applications to one Trinidad server.  
  6.  
  7. Trinidad is a light-weight JRuby web server that runs Rails and Rack applications in an embedded Apache Tomcat container.  Let's install it by running this command:
  8.  
  9.     $ gem install trinidad -v 1.3.4
  10.  
  11. Next, let's create a Trinidad home directory.  The examples in this post will use `/opt/trinidad`, but you can use whatever you'd like.
  12.  
  13. Under the `/opt/trinidad` directory, we'll create two more directories called `thing1` and `thing2`, which will contain the applications we're going to run on our single Trinidad server.  In the `thing1` directory, create a `config.ru` file and put this code in it:
  14.  
  15.     require 'rubygems'
  16.     require 'sinatra'
  17.  
  18.     get '/' do
  19.       "I'm thing one!"
  20.     end
  21.  
  22.     run Sinatra::Application
  23.  
  24. In the `thing2` directory, create another `config.ru` file and put this code in it:
  25.  
  26.     require 'rubygems'
  27.     require 'sinatra'
  28.  
  29.     get '/' do
  30.       "I'm thing two!"
  31.     end
  32.  
  33.     run Sinatra::Application
  34.  
  35. Next, we'll create a `/opt/trinidad/trinidad.yml` file, which will be used to configure our Trinidad server.  
  36.  
  37.     web_apps:
  38.       default:                                  # use the "/" context
  39.         web_app_dir: '/opt/trinidad/thing1'
  40.       thing2:                                   # use the "/thing2" context
  41.         web_app_dir: '/opt/trinidad/thing2'
  42.  
  43. Our Trinidad home directory should look like this:
  44.  
  45.     /opt/trinidad/
  46.     |-- trinidad.yml/
  47.     |-- thing1/
  48.         `-- config.ru/
  49.     `-- thing2/
  50.         `-- config.ru/
  51.  
  52. Before we start the server, let's make sure Sinatra is installed by running this command:
  53.  
  54.     $ gem install sinatra
  55.  
  56. Now we can run our Trinidad server by executing this command:
  57.  
  58.     $ trinidad --config /opt/trinidad/trinidad.yml
  59.     Mar 29, 2012 11:46:52 PM org.apache.coyote.AbstractProtocol init
  60.     INFO: Initializing ProtocolHandler ["http-bio-3000"]
  61.     Mar 29, 2012 11:46:52 PM org.apache.catalina.core.StandardService startInternal
  62.     INFO: Starting service Tomcat
  63.     Mar 29, 2012 11:46:52 PM org.apache.catalina.core.StandardEngine startInternal
  64.     INFO: Starting Servlet Engine: Apache Tomcat/7.0.23
  65.     2012-03-30 04:46:52 INFO: No global web.xml found
  66.     2012-03-30 04:46:53 INFO: jruby 1.6.7 (ruby-1.8.7-p357) (2012-02-22 3e82bc8) (Java HotSpot(TM) 64-Bit Server VM 1.6.0_29) [darwin-x86_64-java]
  67.     2012-03-30 04:46:56 INFO: The start() method was called on component [Realm[Simple]] after start() had already been called. The second call will be ignored.
  68.     2012-03-30 04:46:56 INFO: jruby 1.6.7 (ruby-1.8.7-p357) (2012-02-22 3e82bc8) (Java HotSpot(TM) 64-Bit Server VM 1.6.0_29) [darwin-x86_64-java]
  69.     2012-03-30 04:46:58 INFO: Starting ProtocolHandler ["http-bio-3000"]
  70.  
  71. As the server starts up, we'll see that its instatiated two runtimes -- one for each of our applications.  We can see each of them by browsing to `http://localhost:3000` and `http://localhost:3000/thing2`.
  72.  
  73. The two applications are completely isolated.  That means if you monkey-patch the `String` class in one application, it won't affect the other application.  If you set a global variable to a constant value in one application, you can set it to a different value in the other application.
  74.  
  75. Now let's move on and really take advantage of what we've created!
  76.  
  77. Because these applications are running in the same JVM, they can share a Database Connection Pool.  To do this, we'll need to use the `trinidad_dbpool_extension`.  Trinidad provides an extension mechanism that allows us to plug-in many kinds of features.They are particularly useful when we need to hook into the embedded Tomcat container, as our database connection pool will.
  78.  
  79. To use the `trinidad_dbpool_extension`, we'll need to add an `extensions:` entry to our `trinidad.yml` file.  The new entry will contain the configuration for the Database Connection Pool.  The entire file should look like this now:
  80.  
  81.     web_apps:
  82.       default:
  83.         web_app_dir: '/opt/trinidad/thing1'
  84.       thing2:
  85.         web_app_dir: '/opt/trinidad/thing2'
  86.     extensions:
  87.       postgresql_dbpool:                                  
  88.         jndi: 'jdbc/trinidad'                          
  89.         username: 'postgres'                              
  90.         password: 'Passw0rd'                              
  91.         url: 'jdbc:postgresql://localhost:5432/trinidad'  
  92.  
  93. The extension creates the database connection pool inside the Tomcat container and gives it a JNDI name.  JNDI is a registry service for resources inside of a JVM.
  94.  
  95. You'll have to use a real database for this to work, but you don't have to use PostgreSQL.  The extension also supports MySQL, MSSQL, Oracle, and a generic adapter that covers most other JDBC implementations.  
  96.  
  97. Next, let's use the pool in our applications.  Change the `thing1/config.ru` file to look like this:
  98.  
  99.     require 'rubygems'
  100.     require 'sinatra'
  101.     require 'active_record'
  102.  
  103.     get '/' do
  104.       ActiveRecord::Base.establish_connection(
  105.         :adapter => "jdbcpostgresql",
  106.         :jndi => "java:/comp/env/jdbc/trinidad"
  107.       )
  108.  
  109.       r = ActiveRecord::Base.connection.execute(
  110.         "select count(*) from pg_catalog.pg_tablespace")
  111.  
  112.       "Thing one found: #{r.inspect}"
  113.     end
  114.  
  115.     run Sinatra::Application
  116.  
  117. First, we're loading the `active_record` Gem, which we'll use to interface with our database.  Next, we've added two statements to our `get` service.  The first statement establishes a connection from the pool by referencing the JNDI resource we definined earlier.  The second line executes a simple query against PostgreSQL's internal tables.  Finally, we're returning the result of the query as the service response.
  118.  
  119. Next, modify `thing2/config.ru` so it looks similar to the code above, but with "Thing two" in the response.
  120.  
  121. Before we can launch these applications, we'll need to install a few more gems by running these commands:
  122.  
  123.     $ gem install trinidad_postgresql_dbpool_extension
  124.     $ gem install activerecord-jdbcpostgresql-adapter
  125.  
  126. Now kill the Trinidad server if it's still running by pressing `Ctrl+C` from it's console, and start it up again by running this command once more:
  127.  
  128.     $ trinidad --config /opt/trinidad/trinidad.yml
  129.  
  130. When we point our browser to `http://localhost:3000` and `http://localhost:3000/thing2` we'll see something like this (depending on the number of tables in your database):
  131.  
  132.     Thing one found: [{"count" => 0}]
  133.  
  134. Both applications are connecting to the database!
  135.  
  136. Sharing a database connection pool simplifies our production architecture by eliminating the need for additional layers like pg_pool.  Trinidad makes it very easy to configure, but this same kind of setup can be achieved with any JRuby web server -- including TorqueBox and Warbler+Tomcat/Jetty/etc.
  137.  
  138. If you found this useful, I encourage you to pick up a copy of my book, Deploying with JRuby, which has tons of other JRuby examples like this one.
  139.  
  140. The complete source for this example can be found here: https://github.com/jkutner/trinidad-dbpool-example