Scala’s DynamicVariable

For most of my career, I’ve built web applications in scripting languages like PHP or Ruby. In both of these environments, a new instance of your controller is instantiated for every request, so it’s trivial to set an instance variable in preDispatch() or before and use it later in the main action.

This year I became the author (and maintainer!) of a Scala REST service at work. We already had a few other services written in Scalatra, so I used it for my service, too. Last week, I needed to add a set of result filters to all of the actions in a controller. Request parameters dictate which result filters are applied. Simple enough, I thought — I’ll just create the filters in a before() block and assign it to an instance varible. Then in each action, I can retrieve them and pass them to the appropriate model.

If you’re a seasoned Java developer reading this, you’re probably shaking your head right now. But if you work primarily with PHP or Ruby, the problem might not be as obvious.

In Java, a single instance of a servlet is used to serve requests. Thus, instance variables cannot be used to store request-specific state. Consider a request that sets a filters instance variable in before(), then uses the same variable in the main action. A second request might come in right after the first one, overriding the filters variable with something else before the first request gets to the main action. By the time the first request goes to use the filters variable, it has changed to whatever value the second request set it to. To prevent this from happening, all access to the filters variable would need to be wrapped in a synchronized block.

There had to be a better way. Scalatra exposes a request object that is scoped per-request — how is that implemented? After digging through the source a bit, I found something called withRequestResponse in ScalatraBase.scala, which is defined in DynamicScope.scala. The implementation uses something called a DynamicVariable. There’s a comment in the code that points to this blog post which helped explain things a bit better, and later I found this stackoverflow post on the topic as well. Essentially, DynamicVariable allows you to define a variable such that each thread will have its own copy of that variable in a given block.

So now I knew the nuts and bolts of how to share request-specific state between a before() block and an action, but it wasn’t quite a solution yet. Fortunately, a little further googling turned up this thread, which was exactly what I was looking for. A little tweaking and I ended up with this ResultFilters trait:

trait ResultFilters extends ScalatraKernel {
  override def executeRoutes() {
    _filters.withValue(new ListBuffer[ResultFilter]) {
      super.executeRoutes()
    }
  }

  implicit def filters = _filters.value

  protected val _filters = new DynamicVariable[ListBuffer[ResultFilter]](null)
}

Mixing this trait into a servlet class allows me to add filters in before() and access them from my actions. All the messy thread stuff is abstracted away. From the servlet code’s point of view, there’s a magic filters variable that behaves just like the request variable provided by Scalatra.

class MyServlet extends ScalatraServlet
  with ResultFilters {

  before() {
    filters += new StateFilter(params.getOrElse("state", "published"))
  }

  get("/") {
    MyModel.get(filters)
  }

  get("/:type") {
    filters += new TypeFilter(params.get("type"))
    MyModel.get(filters)
  }
}
Tagged ,

Leave a Reply

Your email address will not be published. Required fields are marked *