This article discusses a system which is an extended version of the conventional ping pong example that comes along with the Lightbend’s minimal seed template for an Akka with Scala build i.e., activator-akka-scala-seed.

The article is majorly focussed on the design of the extended version. The implementation details can be found on github.

The Conventional Ping Pong Model

  • In the conventional ping pong system the relationship between the pinging and ponging actor is of a parent and a child i.e., there is only one actor playing the role of the pinging actor while the other playing the role of the ponging actor, as it’s child.

  • The communication or the exchange of ping and pong messages between the actors is limited to three iterations after which the pinging actor invokes actor system termination.

  • Both the actors have different class definitions.

Conventional Ping Pong System

Participating Actors & Messages

Messages Exchanged Ping Actor

Initialize

Reception of this message marks beginning of the communication.

PongMessage(text: String)

Upon reception of this message PingActor replies the PongActor with a ping message while keeping the count of number of messages exchanged between itself and the PongActor. Upon completion of three of such message exchanges it invokes actor system shut down.

Messages Exchanged Pong Actor

PingMessage(text: String)

Upon reception of this message PongActor replies to the PingActor with a pong message.

The Extended Version

  • In the extended version both the pinging and ponging actors share the same class definition i.e., PingPongActor class. The actors instead are implemented as a finite state machine where it can be in one of the following states, inactive, pinging or ponging.

Ping Pong Actor States
  • The number of pinging and ponging actors is not limited to two, unlike in the conventional ping pong example system, instead there can be as many such actors instantiated while actor system initialization. However there can only be a single actor playing the role of the pinging actor. This limitation comes with the redefinition of the ping and pong messages. The ping message can be depicted as a question, ‘Are you all alive?’, to the ponging actor who respond to the same with the pong message.

  • The parent of all the participating actors is a MasterActor who spwans all the actors and initiates the termination of the actor system.

Parent Child Relationship
Ping Pong Actors Registration
Roles Assignment of Ping Pong Actors
  • The communication between the pinging and ponging actors are channelized via a router actor, RouterActor. As part of initialization, actors self discover themselves to the router i.e., they register themselves with the RouterActor even before they are assigned any roles. This avoids maintenance of list of all actors on every other actor for the purpose of message exchanges.

Note: The messages exchanged between the pinging and ponging actors is identified with a unique identifier (a random integer) generated with every new ping message i.e., every singular message communication is identified with a unique identifier.

Ping Pong Message Exchanges
  • The RouterActor receives a ping message from the pinging actor and forwards the same to all registered ponging actors. It however doesn’t simply forwards all the pong messages received from the respective actors to the pinging actor, instead it keep a track of whether all ponging actors have replied within a time frame.

Note: The RouterActor implements the stop watch for the purpose of waiting until all messages received from the ponging actors before throwing exceptions, as Future object which upon completion sends StopWatchEnded message to the router itself.

Pong message exchanges when all ponging actors replied before stop watch expires
  • The pinging actor upon reception of the UnreachableActorException requests the RouterActor to reset roles. This would instigate the RouterActor to randomly chose an actor apart from the current actor for the pinging role. The motivation for such an implementation is that reshuffling roles may confirm if the ponging actors are not available even from newly selected pinging actor. If an actor is not reachable for at most three times, it is unregistered from the router actor’s locally maintained Set.

Pong Message Exchanges When No Replies Received From a Ponging Actor
  • If all replies received before the stop watch expires, the RouterActor replies pinging actor with a pong message otherwise it replies with UnreachableActorException.

Note: There is though a possibility that the ponging actor replies after the stop watch has already expired and the pinging actor has already replied with the ResetRoles message upon reception of UnreachableActorException. In such a case the reply could still be in the RouterActor mailbox waiting to be processed. If that pong message is processed by the RouterActor after it has already shuffled the roles, it will be ignored by the RouterActor since the messsage idenfier would have been updated to a newer value by then.

  • If in case RouterActor receives a pong message from an actor that is not in it’s registered actors lists it replies the pinging actor with an UnregisteredActorException along with the pong message.

Pong message exchanges ~ When replies received from a 'Ponging Actor' that has already been unregistered
  • The termination of the actor system is initiated by the MasterActor but is delegated to the RouterActor for the purpose of graceful termination. In other words, RouterActor first asks pinging and ponging actors to discontinue exchanging messages and move to the Inactive state by sending them Enough message, waits for the actors to finish their pending jobs, if any, and then invoke actor system termination.

Actor System Termination

Why can’t RouterActor simply forward all pong messages?

If the router were to simply forward all the pong messages it received to the pinging actor it would cause explosion in the number of messages since for every pong message received the pinging actor would simply reply with a ping message.

For example, consider the number of PingPongActors participating in the message exchange are 3. Now, as per current design, since RouterActor broadcasts every ping message to the ponging actors and there is a ping replied to every pong message received by the pinging actor, if RouterActor were to simply relay every pong message received, it would have caused message explosion.

Message Explosion

Note: The containment of all this logic within the RouterActor results in a clear separation of responsibilities. It complies with the Single Responsibility Design Principle.

Participating Actors & Messages

Messages Exchanged MasterActor

Initialize( numberOfActorsToSpawn: Int)

Upon reception of this message MasterActor creates a RouterActor and given number of PingPongActor actors asking each of them to register themselves with the SelfDiscover message. While after a wait of certain period asks RouterActor to assign roles to every registered PingPongActor with the AssignRoles message.

Terminate

Upon reception of this message the MasterActor initiates the termination of the actor system.

Messages Exchanged RouterActor

Register

Upon reception of this message the RouterActor registers the sender to it’s list of PingPongActors.

Unregister

Upon reception of this message the RouterActor unregisters the sender from it’s list of PingPongActors.

AssignRoles

Upon reception of this message from the MasterActor, RouterActor randomly selects a PingPongActor for the role of pinging actor, sends that actor the PingNow message and message PongNow to the rest of the actors in it’s list.

ResetRoles

Upon reception of this message from the PingPongActor, RouterActor reassigns the roles.

StopWatchEnded

It embarks the end of the waiting period of the reception of responses from all the ponging actors.

Terminate

Upon reception of this message from the MasterActor, RouterActor send Enough message to the PingPongActors in it’s registered list asking them to finish their incomplete tasks, unregister themselves and move to inactive state. RouterActor waits for a certain period and then invokes actor system termination.

Messages Exchanged PingPongActor

PingMessage(message: String, messageIdentifier: Int)

Upon reception of the ping message, the PingPongActor relies with the counter pong message.

PongMessage(message: String, messageIdentifier: Int)

Upon reception of the pong message the PingPongActor replies with a counter ping message.

SelfDiscover(routerActor: ActorRef)

Upon reception of this message from the MasterActor, PingPongActors send self registration messages to the RouterActor.

PingNow / PongNow

The RouterActor upon reception of AssignRoles or ResetRoles messages sends PingNow or PongNow messages to respective PingPongActor actors.

Enough

The RouterActor upon reception of termination request from the MasterActor sends this message to all the registered actors.

UnregisteredActorException

If RouterActor receives a pong message from an actor that is not present in it’s registered actors list it replies the pinging actor with this exception.

UnreachableActorException

Upon completion of the stop watch if RouterActor realizes that certain ponging actors have not replied it then replies the pinging actor with this exception.

comments powered by Disqus