3
votes

Complete beginner here in Akka 2.2, trying a modified version of the Hello World. The modification is that I create 1000 actors instead of one. Running it, I don't get all 1000 hello worlds returned, with this error trace, repeated for several messages:

[07/23/2013 22:22:45.924] [Main-akka.actor.default-dispatcher-2] [akka://Main/user/app/$Si] Message [net.clementlevallois.akkatest.Greeter$Msg] from Actor[akka://Main/user/app#1478796310] to Actor[akka://Main/user/app/$Si#-1309206213] was not delivered. 1 dead letters encountered. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.

The two classes:

public class App extends UntypedActor {

    @Override
    public void preStart() {
        // create the greeter actors
        List<ActorRef> actorRefs = new ArrayList();
        for (int i = 0; i < 1000; i++) {
            final ActorRef greeter = getContext().actorOf(Props.create(Greeter.class, i));
            this.getContext().watch(greeter);
            actorRefs.add(greeter);
        }
        // tell it to perform the greeting
        for (ActorRef actorRef : actorRefs) {
            actorRef.tell(Greeter.Msg.GREET, getSelf());
        }
    }

    @Override
    public void onReceive(Object msg) {

        if (msg instanceof DeadLetter) {
            System.out.println(msg);
        } else if (msg == Greeter.Msg.DONE) {
            // when the greeter is done, stop this actor and with it the application
            getContext().stop(getSelf());
        } else {
            unhandled(msg);
        }
    }

}



public class Greeter extends UntypedActor {

    String input;

    public static enum Msg {
        GREET, DONE;
    }

    public Greeter(int i) {
        input = String.valueOf(i);
    }

    @Override
    public void onReceive(Object msg) {
        if (msg == Msg.GREET) {
            System.out.println("Hello World! " + input);
            getSender().tell(Msg.DONE, getSelf());
        } else {
            unhandled(msg);
        }
    }
}

I would appreciate any help on debugging, and advice on whether creating lists of actors as done here is alright or not.

1
Wouldn't you have 999 Msg.DONE's sitting in the App actor's queue since you shutdown after the first one?Noah
So I simply misunderstood: I thought getContext().stop(getSelf()) was shutting down the actor, not the app? (the comment in the original "Hello World" says this is shutting down the actor...?)seinecle
ps: indeed I get everything fine now. Thx! Where should getContext().stop(getSelf()) be situated then?seinecle

1 Answers

5
votes

As @Noah astutely pointed out, when the App actor receives a DONE response, it is stopping itself. Now, stop just stops any more messages from being recevied by the actor but it will still process what was in its mailbox prior to being stopped, so more than 1 message will likely be processed. Once this actor is stopped, the ActorRef that was passed along to the other actor via getSelf is now pointing to DeadLetter and that's why you start to see messages being routed to deadletter. If you really want to test this fully, decrement a counter (that starts out at 1000) each time you receive a response in the App actor. When it reaches 0, you can safely stop it:

public class App extends UntypedActor {
  private int counter = 1000;

  @Override
  public void preStart() {
    // create the greeter actors
    List<ActorRef> actorRefs = new ArrayList();
    for (int i = 0; i < counter; i++) {
        final ActorRef greeter = getContext().actorOf(Props.create(Greeter.class, i));
        this.getContext().watch(greeter);
        actorRefs.add(greeter);
    }
    // tell it to perform the greeting
    for (ActorRef actorRef : actorRefs) {
        actorRef.tell(Greeter.Msg.GREET, getSelf());
    }
  }

  @Override
  public void onReceive(Object msg) {

    if (msg instanceof DeadLetter) {
        System.out.println(msg);
    } else if (msg == Greeter.Msg.DONE) {
        if (--counter <= 0){
          getContext().stop(getSelf());
        }

    } else {
        unhandled(msg);
    }
  }

}