My http request becomes null inside an Akka future

akka, scala, scalatra

Solution

I don't know Scalatra, but it's fishy that you are accessing a value called `request` that you do not define yourself. My guess is that it is coming as part of extending `ScalatraServlet`. If that's the case, then it's probably mutable state that it being set (by Scalatra) at the start of the request and then nullified at the end. If that's happening, then your workaround is okay as would be assigning `request` to another val like `val myRequest = request` before the `future` block and then accessing it as `myRequest` inside of the future and closure.

Problem

My server application uses Scalatra, with json4s, and Akka. Most of the requests it receives are POSTs, and they return immediately to the client with a fixed response. The actual responses are sent asynchronously to a server socket at the client. To do this, I need to `getRemoteAddr` from the http request. I am trying with the following code: ``` case class MyJsonParams(foo:String, bar:Int) class MyServices extends ScalatraServlet { implicit val formats = DefaultFormats post("/test") { withJsonFuture[MyJsonParams]{ params => // code that calls request.getRemoteAddr goes here // sometimes request is null and I get an exception println(request) } } def withJsonFuture[A](closure: A => Unit)(implicit mf: Manifest[A]) = { contentType = "text/json" val params:A = parse(request.body).extract[A] future{ closure(params) } Ok("""{"result":"OK"}""") } } ``` The intention of the `withJsonFuture` function is to move some boilerplate out of my route processing. This sometimes works (prints a non-null value for `request`) and sometimes `request` is null, which I find quite puzzling. I suspect that I must be "closing over" the `request` in my future. However, the error also happens with controlled test scenarios when there are no other requests going on. I would imagine `request` to be immutable (maybe I'm wrong?) In an attempt to solve the issue, I have changed my code to the following: ``` case class MyJsonParams(foo:String, bar:Int) class MyServices extends ScalatraServlet { implicit val formats = DefaultFormats post("/test") { withJsonFuture[MyJsonParams]{ (addr, params) => println(addr) } } def withJsonFuture[A](closure: (String, A) => Unit)(implicit mf: Manifest[A]) = { contentType = "text/json" val addr = request.getRemoteAddr() val params:A = parse(request.body).extract[A] future{ closure(addr, params) } Ok("""{"result":"OK"}""") } } ``` This seems to work. However, I really don't know if it is still includes any bad concurrency-related programming practice that could cause an error in the future ("future" meant in its most common sense = what lies ahead :).

Original source