igx
igx

Reputation: 4231

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)

Upvotes: 1

Views: 11146

Answers (4)

Anand Tiwari
Anand Tiwari

Reputation: 77

An Example of inifinite loop by sending a message to self-

 class Swapper extends Actor {
    override def preStart(): Unit = {
      super.preStart()
      self ! Swap
    }

    override def receive: Receive = {
      case Swap =>
        println("Hi")
        self ! Swap
    }

  }

  case object Swap

Upvotes: 0

Douglas Liu
Douglas Liu

Reputation: 1682

My apology, I know this is really an old question but it recently surfaced in my use cases. Just wanted to share my 2 cents.

I wanted to handle a message by routing it to self with updated parameters. And I'm expecting results by using ask pattern. To get this working, I had to use a second proxy actor, which main purpose is to relay to message back to the main actor.

       (augmented)
Main Actor --> Proxy Actor --> Main Actor
           ask             ask

This has allowed me to ask for the results, at the costs of some extra overheads.

Upvotes: 0

Alexey Romanov
Alexey Romanov

Reputation: 170735

You can send messages to self, but you can't wait for a reply. Because you won't get the new message until you finish handling the current message, and if you use ask, you won't finish handling the current message until you get a reply to the new message! So you are creating a deadlock.

But in the case of code in question, you are not asking self for a reply at all. The actor created by ask is waiting for the reply from myActor, and isn't getting it (because the code of TestActor doesn't send any reply, and sends a message to self instead).

You can see that self ! message works by changing TestActor a bit:

case class Bar(name: String)

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

Upvotes: 6

Vladimir Matveev
Vladimir Matveev

Reputation: 127781

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.

Upvotes: 7

Related Questions