Search code examples
scalaakka

akka 2.0 send message to self


using Akka 2.0 trying to send a message to self (using the ask pattern)

import akka.pattern.ask
import scala.concurrent.{Await, Future}
import akka.actor.{Props, Actor, ActorSystem}
import scala.concurrent.duration._
import akka.util.Timeout
object askTest extends App{
   implicit val timeout = Timeout(5 seconds)
   val system = ActorSystem("AskTestSystem")
   val myActor = system.actorOf(Props(new TestActor), name = "myActor")
   val future: Future[Foo] = ask(myActor, Foo("test")).mapTo[Foo]
   val result = Await.result(future, timeout.duration)
   println(result)
}
case class Foo(name:String){
  override def toString = "Foo "+name
}

  class TestActor extends Actor {
  def receive = {
    case Foo(a) => self ! Foo("buzz "+a)
    case any => println(any+" that was unexpected")
  }
 }

however it crashes with Timeout exception with the following trace :

 Exception in thread "main" java.util.concurrent.TimeoutException: Futures timed out after [5 seconds]
    at scala.concurrent.impl.Promise$DefaultPromise.ready(Promise.scala:96)
    at scala.concurrent.impl.Promise$DefaultPromise.result(Promise.scala:100)
    at scala.concurrent.Await$$anonfun$result$1.apply(package.scala:107)
    at scala.concurrent.BlockContext$DefaultBlockContext$.blockOn(BlockContext.scala:53)
    at scala.concurrent.Await$.result(package.scala:107)
    at akkaTest.askTest$delayedInit$body.apply(askTest.scala:33)
    at scala.Function0$class.apply$mcV$sp(Function0.scala:40)
    at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:12)
    at scala.App$$anonfun$main$1.apply(App.scala:71)
    at scala.App$$anonfun$main$1.apply(App.scala:71)
    at scala.collection.immutable.List.foreach(List.scala:318)
    at scala.collection.generic.TraversableForwarder$class.foreach(TraversableForwarder.scala:32)
    at scala.App$class.main(App.scala:71)
    at akkaTest.askTest$.main(askTest.scala:13)
    at akkaTest.askTest.main(askTest.scala)

Solution

  • Your code does what you told it to do: the actor indefinitely sends a message to itself. Because it sends the message to no one except self, your ask pattern just can't work, because ask is waiting for a message to be sent to the sender, not self.

    self is a reference to the current actor, you use it when you want the actor to send message to itself. sender is a reference to an actor which has sent the message which is currently being processed. You use it if you want to "answer" to the sender.

    ask pattern creates an implicit actor which becomes sender reference in the target actor - this is very natural. So you need to change self ! Foo("buzz " + a) to sender ! Foo("buzz " + a), and your code will work.