Akka Typed Actors: Exploring the receptionist pattern

3 minute read

In this article we’ll explore another of Akka-Typed patterns. This time we’ll show you how you can use the receptionist patterns. This is the third and last article on a series on Akka-Typed. The other two articles can also be found on this site. If you don’t know anything about Akka-Typed yet, it’s a good idea to first read the “First steps with Akka Typed article”:

  • First steps with Akka Typed: http://www.smartjava.org/content/akka-typed-first-steps-typed-actors-scala
  • Exploring the receiver pattern: http://www.smartjava.org/content/akka-typed-actors-exploring-receiver-pattern

The idea behind the Receptionist pattern is very simple and is explained by the ScalaDoc:

/**
 * A Receptionist is an entry point into an Actor hierarchy where select Actors
 * publish their identity together with the protocols that they implement. Other
 * Actors need only know the Receptionist’s identity in order to be able to use
 * the services of the registered Actors.
 */
object Receptionist {
...

So basically a client only needs to know how to access the receptionist and from there it can access any other actor which is registered at the Receptionist. So let’s first create a couple of actors that we register with the receptionist. For this we define two very simple actors:

Nothing special, just two services that print out each message that they receive. Besides these two services we also create a service which will act as a client to these two services:

As you can see, also a rather basic actor, which changes behavior once it receives a registerAddresses message. After it has changed its behavior it’ll act on sendMessage messages to call the registered services. Now how do we tie all this together?

For this we create another actor which kicks off this scenario for us:

That is a lot of code but it is really easy to see what is happening. The first thing we do is use ctx.spawn to create a set of child actors of the type we just discussed. Once we’ve defined the actors we need to register our FirstService and SecondService actors with the receptionist. For this we need to send a message like this:

/**
   * Associate the given [[akka.typed.ActorRef]] with the given [[ServiceKey]]. Multiple
   * registrations can be made for the same key. Unregistration is implied by
   * the end of the referenced Actor’s lifecycle.
   */
  final case class Register[T](key: ServiceKey[T], address: ActorRef[T])(val replyTo: ActorRef[Registered[T]]) extends Command

In our example we do that in the following way:

As you can see we create an adapter to handle the replyTo parameter of the Register message (where we just ignore the response in this case). We then use these adapters to register our service actors with the receptionist. At this point we’ve registered our services with the receptionist and can now use the Find message:

  /**
   * Query the Receptionist for a list of all Actors implementing the given
   * protocol.
   */
  final case class Find[T](key: ServiceKey[T])(val replyTo: ActorRef[Listing[T]]) extends Command

.. to get a list of registered actors for a specific type:

Important to note here is line 99:

Here we sent the information about the registered services to our actor which serves as a client.

Now all that is left to do is send a sendMessage message to the sender, and it should be sent to all the registered services:

When we now run this, the output looks like this:

First Service Receiver: FirstServiceMsg1(Hello1)
First Service Receiver: FirstServiceMsg1(Hello1)
First Service Receiver: FirstServiceMsg1(Hello1)
Second Service Receiver: SecondServiceMsg1(Hello1)
First Service Receiver: FirstServiceMsg1(Hello2)
First Service Receiver: FirstServiceMsg1(Hello2)
Second Service Receiver: SecondServiceMsg1(Hello1)
First Service Receiver: FirstServiceMsg1(Hello2)
Second Service Receiver: SecondServiceMsg1(Hello1)
Second Service Receiver: SecondServiceMsg1(Hello2)
Second Service Receiver: SecondServiceMsg1(Hello2)
Second Service Receiver: SecondServiceMsg1(Hello2)

Easy right!

Updated: