Question

I am chaining actors in akka-scala and at each step, the newly created actor will send a message to the supervisor actor. In response, the supervisor will increment a counter.

I don't understand why during this operations deadLetters are produced at random, sometimes no deadLetters, sometimes I get a few.

Moreover it appears that the supervisor does not increment the counter. Here's my code

import akka.actor._

object ScopeMessages{
  case object AddChild
  case object Counter
}

class ScopeSet(n: Int) extends Actor{
  import ScopeMessages._

  var root:ActorRef = context.actorOf(Props(classOf[ScopeActor],n, self))

  var counter = 0

  def receive:Receive = {
    case AddChild => counter += 1
    case Counter => sender ! counter
    case _ => ()
  }
}

class ScopeActor(id: Int, apex:ActorRef) extends Actor{
  import ScopeMessages._

  var sub:List[ActorRef] = Nil

  if (id > 0){
    sub = context.actorOf(Props(classOf[ScopeActor], id-1, apex))::Nil
    apex ! AddChild
  }

  def receive:Receive = {case _ => ()}
}

object ScopeTest extends App {
  import akka.testkit.TestProbe
  import ScopeMessages._

  implicit val system = ActorSystem("TestSys")
  val p = TestProbe()

  val n:Int = 10
  val base_actor = system.actorOf(Props(classOf[ScopeSet], n))

  p.send(base_actor, Counter)
  p.expectMsg(n)

  system.shutdown()
}

Thanks for help.

Was it helpful?

Solution

Remember that you have an asynchronous system here. The reason you are not seeing the correct count in your assertion is that the count is being checked before the entire tree of actors has been created. You can verify this by putting a sleep for a couple of seconds before the call to p.send. This is also probably the reason you are getting deadletters as you are shutting the system down before it's had time to set itself up. The apex actor is probably terminated but still receiving AddChild messages from the subordinates that are trying to be created while things are shutting down.

OTHER TIPS

Everything cmbaxter said is true. Here's some hints on a way to fix it. Try constructing ScopeSet with the ActorRef of your TestProbe and adding a condition to you receive of AddChild. Also don't shut the actor system until the testProb has received the counter.

class ScopeSet(n: Int, testProb: ActorRef) extends Actor{
  import ScopeMessages._

  var root:ActorRef = context.actorOf(Props(classOf[ScopeActor],n, self))

  var counter = 0

  def receive:Receive = {
    case AddChild => {
        counter += 1
        if (counter == n) { testProb ! counter }
    }
    case _ => ()
  }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top