ticofab
ticofab

Reputation: 7717

Scala Akka Play, Future doesn't return

I'm using Scala 2.10, Akka 2.1 and Play 2.1. When I send an http request to my backend, I ask one actor to compute something. The idea is to return the result of the calculation if it returns before a timeout, otherwise a different string. See code below.

val futureInt: Future[Int] = ask(testActor, Calculate(number.toInt)).mapTo[Int]
val timeoutFuture = play.api.libs.concurrent.Promise.timeout("Oops", 2.seconds)

Async {
  Future.firstCompletedOf(Seq(futureInt, timeoutFuture)).map {
    case i: Int => Ok("Got result " + i)
    case t: String => Ok("timeout expired")
  }
}

The actor is as follows:

class TestActor() extends Actor {
  def receive = {
    case Calculate(tonumber: Int) =>
      for (a <- 1 to tonumber) {
        val c: Double = scala.math.pow(a, 2)
        println("a: " + a + ", c: " + c)
      }
      12345 // hardcoded value to return when the calculation finishes
    case _ =>
      println("bah")
  }
}

My problem is that even if the actor finishes before the timeout, nothing is "returned" by the Future and so the timeout always expires. What am I doing wrong? Thanks a lot.

Upvotes: 3

Views: 1415

Answers (1)

Dylan
Dylan

Reputation: 13922

From http://doc.akka.io/docs/akka/snapshot/scala/actors.html

Using ask will send a message to the receiving Actor as with tell, and the receiving actor must reply with sender ! reply in order to complete the returned Future with a value.

and

Warning

To complete the future with an exception you need send a Failure message to the sender. This is not done automatically when an actor throws an exception while processing a message.

So instead of "returning" like you would in a usual scala function, do something along the lines of

def receive = {
  case Calculate(tonumber: Int) =>
    ...
    sender ! 12345
  case _ =>
    sender ! akka.actor.Status.Failure(new InvalidArgumentException)
}

Upvotes: 3

Related Questions