Search code examples
javaakkaactor

What is the second argument of the "ActorRef.tell" method?


I started to learn Akka and downloaded example from official guid:

I didn't understand tell method second argument usage:

In main method written:

howdyGreeter.tell(new WhoToGreet("Akka"), ActorRef.noSender());

Thus second argument is ActorRef.noSender()

on actor side entry point looks like this:

@Override
public Receive createReceive() {
  return receiveBuilder()
      .match(WhoToGreet.class, wtg -> {
        this.greeting = message + ", " + wtg.who;
      })
      .match(Greet.class, x -> {
        //#greeter-send-message
        printerActor.tell(new Greeting(greeting), getSelf());
        //#greeter-send-message
      })

Thus I can't have access to passed reference.

Additionally you can see that this actor send message to another actor in case of message type is Greet.class

printerActor.tell(new Greeting(greeting), getSelf());

Here second argument is getSelf() but I tried to change it with ActorRef.noSender() and behaviour was not changed.

printer actor entry point looks like this:

@Override
public Receive createReceive() {
  return receiveBuilder()
      .match(Greeting.class, greeting -> {
          log.info(greeting.message);
      })
      .build();
}

Thus it just prints provided message


Solution

  • printerActor.tell(new Greeting(greeting), getSelf());
    

    Here second argument is getSelf() but I tried to change it with ActorRef.noSender() and behaviour was not changed.

    The second argument to the tell() method is the sender reference to which the recipient actor can send a reply. In other words, if actor A sends a message to actor B with getSelf() as the second argument to a tell() call, then actor B can use getSender() to obtain a reference to actor A. Passing ActorRef.noSender() as the second argument is appropriate when the recipient actor doesn't need a reference to the sender. Note that you can use any ActorRef as the second argument to tell().

    The printer actor in the quickstart guide doesn't call getSender() when it receives a Greeting message. The only thing that the printer actor does when it receives a Greeting message is log the greeting. That being the case, it would make more sense for the greeter actor to use ActorRef.noSender() instead of getSelf() (but, again, in this case it makes no difference because the printer actor doesn't call getSender()):

    printerActor.tell(new Greeting(greeting), ActorRef.noSender());
    

    If you want to see how the sender reference could be used, you could change the printer actor's behavior:

    @Override
    public Receive createReceive() {
      return receiveBuilder()
        .match(Greeting.class, greeting -> {
          log.info(greeting.message);
          getSender().tell(new PrinterAck(), ActorRef.noSender());
      })
      .build();
    }
    

    Then change the greeter actor to handle a PrinterAck message (obviously you would need to define a PrinterAck class):

    @Override
    public Receive createReceive() {
      return receiveBuilder()
        .match(WhoToGreet.class, wtg -> {
          this.greeting = message + ", " + wtg.who;
        })
        .match(Greet.class, x -> {
          printerActor.tell(new Greeting(greeting), getSelf());
        })
        .match(PrinterAck.class, x -> {
          log.info("Received an ack from the printer actor.");
        })
        .build();
    }