Managing MongoDB connections with the Scala Casbah database driver

UPDATE: November 14, 2012. This article describes problems I had when attempting to use the Scala Casbah driver for the MongoDB database. In the end, it turned out I was doing something wrong. However, because this article shows how to troubleshoot MongoDB and Casbah database connection problems, it seems like a good idea to leave it here. If you want to see the correct way to use Casbah with MongoDB, I created this Github project, which shows the correct approach. At some point I'll write an article about that code, but for the time being, if you want to see the correct way to use Casbah with MongoDB and Scala, please see that small Github project. Also, please see the Comments section below for a little more information.

Here's the original article:

This is a little hard to explain, because I can't share all my source code, but if you're using the Scala Casbah driver for MongoDB, and you're having a problem managing database connections, I hope this short tutorial and source code example is helpful.

To spare you everything I went through and get right to the source code, here's a method I used to (a) get a MongoDB database connection, (b) get access to a collection from that connection, (c) save a MongoDBObject to that collection, and (d) close the connection:

def saveWidget(widget: Widget) {
  val mongoObj = buildMongoDbObjectFromWidget(widget)
  using(MongoFactory.getConnection) { conn =>
    MongoFactory.getCollection(conn).save(mongoObj)
  } 
}

This code is so concise in part because of the using function, which helps me get access to my database connection and automatically closes my connection when I'm done with it. I started to write something like this "using" function myself, but then found exactly what I was looking for in the excellent book, Beginning Scala. (I haven't used C#, but apparently it has a "using" control structure, while in Scala you just create your own using function, as shown in the book, and below.)

Managing Casbah MongoDB database connections

Prior to coming up with this approach, I was having a hard time getting a handle on how I was supposed to work with database connections and collections using the MongoDB Casbah driver, but just before switching to this style I did learn that when you use Casbah you have to:

  • Manually get a connection object (and keep a local object reference to it).
  • Get the collection object from that connection so you can use save, remove, update, etc.
  • Call the .close() method on the connection object.

Based on something I read online, I thought the connection object was magically closed for me, but that isn't the case, so I was unknowingly leaking connection objects until I got some sort of MongoDB "out of connections" error message (I don't remember the exact error).

The MongoFactory class

My MongoFactory class isn't a factory in the classic sense of the term, but it's a little like that, so I've kept that name for now. Here's the source code for it, with a few changes to the database-related strings:

import com.mongodb.casbah.MongoCollection
import com.mongodb.casbah.MongoConnection

object MongoFactory {
  
  private val SERVER     = "localhost"
  private val PORT       = 27017
  private val DATABASE   = "animals"
  private val COLLECTION = "dogs"

  def getConnection: MongoConnection = {
    return MongoConnection(SERVER) 
  }

  def getCollection(conn: MongoConnection): MongoCollection = {
    return conn(DATABASE)(COLLECTION)
  }

  def closeConnection(conn: MongoConnection) {
    conn.close
  }

}

Note: The connection and collection methods can be shortened, like this:

  def getConnection = MongoConnection(SERVER) 
  def getCollection(conn: MongoConnection) = conn(DATABASE)(COLLECTION)

but in this case, I personally prefer to see that I'm returning MongoConnection and MongoCollection references.

The 'Beginning Scala' Control class

The magic of the using method comes from the Beginning Scala Control class:

object Control {
  
  def using[A <: { def close(): Unit }, B](param: A)(f: A => B): B =
    try {
      f(param)
    } finally {
      param.close()
    }

  import scala.collection.mutable.ListBuffer

  def bmap[T](test: => Boolean)(block: => T): List[T] = {
    val ret = new ListBuffer[T]
    while (test) ret += block
    ret.toList
  }
}

I don't use the bmap function in my example, but if you have the Beginning Scala book, I thought I'd share that here for completeness.

I'll describe how the using function works in another tutorial, but in short, it uses the Scala version of duck typing to expect an object that has a close() method. Because Scala is a strongly typed language, it uses the technique shown here, which is known as structural typing.

One thing I need to note is that in my Scalatra servlet class, where I access the Casbah connection and collection objects, I use this import statement to use the Control class:

import Control._

How you can tell you're leaking MongoDB connections

There might be a better way to tell if you're leaking MongoDB connections, but here's the approach I used. I am developing on a Mac OS X system, so I opened a Terminal window, then used the Unix/Linux lsof command like this:

$ sudo lsof | grep mongod | grep TCP

When I was leaking MongoDB database connections I saw output like this to show I had leaked three connections:

$ sudo lsof | grep mongod | grep TCP
mongod    5733             Al    6u     IPv4 0x08761278       0t0       TCP *:28017 (LISTEN)
mongod    5733             Al    7u     IPv4 0x07c7eb98       0t0       TCP *:27017 (LISTEN)
mongod    5733             Al    9u     IPv4 0x08761688       0t0       TCP 192.168.1.103:27017->192.168.1.103:64752 (ESTABLISHED)
mongod    5733             Al   12u     IPv4 0x08761a98       0t0       TCP 192.168.1.103:27017->192.168.1.103:64754 (ESTABLISHED)
mongod    5733             Al   13u     IPv4 0x095fa748       0t0       TCP 192.168.1.103:27017->192.168.1.103:64770 (ESTABLISHED)

and once I solved the problem my output always looked like this after running my tests:

$ sudo lsof | grep mongod | grep TCP
mongod    5733             Al    6u     IPv4 0x08761278       0t0       TCP *:28017 (LISTEN)
mongod    5733             Al    7u     IPv4 0x07c7eb98       0t0       TCP *:27017 (LISTEN)

Managing Casbah connections - Summary

I hope this example of how to manage Casbah database connections has been helpful. As I write this tutorial/example in April, 2012, the only Casbah documentation I can find will lead you down a path of leaking MongoDB database connections, so I wanted to share this to spare you the problems I ran into.