A little while ago we created an activator template where we showcase how to combine Apache Spark, MLlib, Scala, Akka and the Play Framework (all technologies are linked in the reference section; you’ll find the application at sentiment.openforce.com). This post shows how we used the so called „cameo pattern“ and what benefits you get if you use Akka this way.

The usual way of sending messages between actors in Akka is using the tell pattern, which is a fire-and-forget approach. The idea is that the sending actor fires a message to another actor and doesn’t wait for a response. The response will be received later via a message the actor is waiting for.

Alternatively Akka supports the ask pattern, which returns a future as response for a sent message. This is very convenient for some scenarios like bridging a Play controller with an Akka actor system as you can see implemented in the Application controller. Here is a piece of code to show you what this means:

By calling classifier < – (director ? GetClassifier).mapTo[ActorRef] we get a future and can use the actor directly from within our for comprehension. By using a future the application doesn’t have to block the current thread to handle the task. This saves resources which can be used e.g. to handle more requests concurrently. However there are tradeoffs that come with the ask pattern.

  • Every time an actor asks another actor for a response using futures a new PromiseActorRef is created. This is a waste of resources
  • Using the ask pattern requires a timeout to be defined. This often leads to hard to debug applications, as stacktraces don’t give you a clue which actor timed out. This is happens because futures don’t have names (like actors)
  • In a larger application it is difficult to set the right value for a timeout so that various timeouts in the application work together in a sensible way

To avoid all that it is preferable to use the fire-and-forget approach with the lightweight tell pattern. In our application we used the aforementioned „cameo pattern” defined by Jamie Allen in his book Effective Akka.

All participants of this pattern can be found in the Classifier file. The Classifier creates the FetchResponseHandler and passes its reference to the TwitterHandler telling it to send the fetched tweets to the handler instead of itself. To do this we cannot use the exclamation mark syntax twitterHandler ! Fetch(token) but have to use the tell method directly twitterHandler.tell(Fetch(token), handler).

The FetchResponseHandler creates a TrainingModelResponseHandler which it sends to the OnlineTrainer and BatchTrainer as sender reference. This is done via the fetchResponse message:

The TrainingModelResponseHandler is the actor which collects all results and only sends the final ClassificationResult message to the original sender when all results have been received. The original sender (Application controller) is passed through all of these actors.

You might have noticed the timeout messages FetchResponseTimeout and TrainingModelRetrievalTimeout in the Classifier file. As mentioned earlier with the ask pattern you have to define an implicit timeout, as you can see in the Application controller.

When you use tell instead you don’t have to do that. If you want though you can still enforce timeout semantics on the request by scheduling a timeout message that you send to yourself. In regards to the TrainingModelResponseHandler it means that the handler is scheduling a TrainingModelRetrievalTimeout to be sent in 3 seconds. If the handler doesn’t receive a result from the online or batch trainer beforehand it will send the timeout message to the original sender. However if it receives the result in time it will cancel the scheduler and return the actual results. Let me show you how this is done in the TrainingModelResponseHandler:

As you can see the timeout is defined and created when the actor itself is created. It schedules a method which sends the TrainingModelRetrievalTimeout after three seconds. If the actor receives the data it needs before it receives the timeout message, the scheduled timeout function gets cancelled (done in the predict function).

By using cameo actors (FetchResponseHandler and TrainingModelResponseHandler) we can avoid using the ask pattern and its associated problems.

 

References