Experimenting with Akka in Java


Akka is often used in combination with Scala, but I wanted to experiment with Akka using Java.
Currently I am working on a plain Java project that I am rewriting to make use of Akka. I would like to know if Akka makes my project cleaner, faster and more reactive.
My experiences on rewriting my application to Akka will be posted on a separate blog which will also contain my conclusions on using Akka.


In this blog I will try to explain the basic steps on how to get started with Akka using Java.

What is Akka?
Akka is an event-driven middleware framework, for building high performance and reliable distributed applications in Java and Scala. Akka decouples business logic from low-level mechanisms such as threads, locks and non-blocking i/o. Your Scala or Java program logic lives in lightweight actor objects which send and receive messages. With Akka, you can easily configure how actors will be created, destroyed, scheduled, and restarted upon failure.
(source: http://letitcrash.com/what-is-akka)

How do Actors work?
An Actor is a container for state, behavior, a mailbox, children and a supervisor Strategy. All of this is encapsulated behind an Actor reference. 
(source: http://doc.akka.io/docs/akka/snapshot/general/actors.html)

Actors can send and receive messages to and from other Actors. These messages are the only way to communicate with Actors.
Since an Actor can only be approached by an Actor reference, the Akka framework is able to move Actors around, place them on different threads or even let them run on remote machines.

How does an empty Actor look like in Java?
The system can only communicate with Actors by sending messages to an Actor, therefore the Actor only needs to implement an onReceive() method and the Actor class needs to extend from UntypedActor.

import akka.actor.UntypedActor;
public class MyActor extends UntypedActor {
    public void onReceive(Object message) {
      // handle message
    }
}

Every message that is send to this actor will be placed into a mailbox and send to the onReceive() method synchronously.
The actor needs to check and handle the message.

How do I setup my pom.xml?
The pom.xml needs the following dependency in order to use the Akka framework::

   
       
            com.typesafe.akka
            akka-actor
            2.0.2
       
   
   
       
            typesafe
            Typesafe Repository
            http://repo.typesafe.com/typesafe/releases/
       
   

How do I bootstrap the Akka framework?

To bootstrap the Akka application, you need to create an ActorSystem using the following code:
ActorSystem system = ActorSystem.create(“myAkkaSystem”);

To this system we can add one or more actors using:
ActorRef myActor = system.actorOf(new Props(MyActor.class), “myActor”);

After building the system and adding the actors we can send an initial message to an actor in order to start the application:
myActor.tell(new MyMessage());

A new MyMessage object is send to the myActor object which will process the message.

How can I send a message to an Actor?

You cannot send a message to an Actor directly, you are only able to send a message to a reference of the Actor.
Within your application you can get references to that Actor by calling the tell() method on the Actor reference.

  myActorB.tell(message);

 

When you would like to get a response from the actor, you can pass a reference of the calling Actor with the tell method:

  myActorB.tell(message, getSelf());

 
When myActorB is processing this request, he has a reference to the calling Actor.

How can an Actor reply to a sender?

If you want to have a handle for replying to a message, you can use getSender(), which gives you an ActorRef. You can reply by sending to that ActorRef by using getSender().tell(replyMsg, getSelf()). You can also store the ActorRef for replying at a later moment, or passing the reference to other Actors. If there is no sender (a message was sent without an actor or future context) then the sender defaults to a ‘dead-letter’ actor ref.

public void onReceive(Object msg) {
  Object result =
      // calculate result …
  
  // do not forget the second argument!
  getSender().tell(result, getSelf());
}


What messages can be send to actors?

The messages that can be send to an Actor can be any object but it is recommended to be an immutable PoJo.
The Actor that receives the message can check the message class to determine what action it should take but the message can also contain properties that the sender can set and can be used by the actor.

An example of a message without properties can be implemented like this:
public class MyMessage {}

An example of an immutable message with properties can be implemented like this:

public class MyOtherMessage {
    private final String request;
    public MyOtherMessage(final String request) {
        this.request = request;
    }
    public String getRequest() {
        return request;
    }
}

Where can I define my messages?

A good practice is to declare what messages an Actor can receive as close to the actor definition as possible (e.g. as static classes inside the Actor or using other suitable class), which makes it easier to know what it can receive.

public class DemoMessagesActor extends UntypedActor {

  static public class Greeting {
    private final String from;

    public Greeting(String from) {
      this.from = from;
    }

    public String getGreeter() {
      return from;
    }
  }

  public void onReceive(Object message) throws Exception {
    if (message instanceof Greeting) {
      getSender().tell(“Hello”).getGreeter(), getSelf());
    } else
      unhandled(message);
  }
}

(source: http://doc.akka.io/docs/akka/snapshot/java/untyped-actors.html)

How can I obtain a reference of an Actor?

You can pass Actor references to other Actors in the constructor when building them. The Actor is able to keep a copy of these actors and can use that to send messages to.

public MyActorA(final ActorRef myActorB, final ActorRef myActorC) {
        this.myActorB = myActorB;
        this.myActorC = myActorC;
}

Defining all actors and the messages send between actors

One way to define which Actors to build and which messages to send, is to create a diagram for each Actor and model the messages that are send between them.



When you have a diagram like this, you can start implementing the defined Actors and their reaction on the messages being received.

Do all classes in my application need to be an Actor?

You can probably model your system where every object is an Actor which only communicate between sending messages.
I am of the opinion that such a system will quickly become very complex and hard to maintain/refactor. 
It might be better to only create actors for a set of components which can run isolated and might be candidates to run simultaneously or remotely.
These components communicate with each other using Actors, but within an actor, requests can be handled using non-akka code.

How can I use a timer to periodically send messages?

Akka provides a scheduler for scheduled actions,
If you would like to send a message to an actor every XX time, you can use thesystem schedular using the following code:

         Duration duration = Duration.create(10, TimeUnit.MILLISECONDS);
        system.scheduler().schedule(duration, duration, myActor, new Message());

Now the myActor actor will receive a Message() message every 10msec.
It is also possible to call scheduleOnce() to schedule a single message after a specific period of time.

How can I use become/unbecome for multistate actors?

When an actor can have multiple states, the actor can deligate the events to another instance that implements the Procedure interface for each state.This instance can be passed to the getContext().become().To revert this, the method getContext().unbecome() can be called.The original onRevieve() method will then again me used to handle the messages.public class MyActor extends UntypedActor {    static class ReplyMessage{}    static class RequestMessage{}    public MyActor() {    }    Procedure waitingForMessages = new Procedure() {
        @Override
        public void apply(Object message) {
            if (message instanceof ReplyMessage) {
                handleClientMessages(message);
            };
            if (allDataReceived()){
                getContext().unbecome();
            }
        }
    };

    public void onReceive(Object message) {
        if (message instanceof RequestMessage) {
            // 
            sendRequestsToClients();
            getContext().become(waitingForMessages);
        } else {
            unhandled(message);
        }
    }

    private void handleClientMessages(Object msg){
      // implement client message handling
    };
    private boolean allDataReceived(){
      // return true when all messages of the client are received
    };
    private void sendRequestsToClients(){
      // send messages to client Actors
    };
}


Conclusions and findings so far:
By playing with Akka so far, I found the following difficult:

– I am missing stacktraces on exceptions or a call stack when debugging. This makes it difficult to know where a message is coming from.

– When messages do not arrive to a specific Actor, it can be difficult to find out if the messages are being send to the right Actor. Especially when you are refacturing your code, it is possible that you have forgotten to re-route the message flow correctly. 

– There is no type checking. All references are of the type ActorRef. When passing Actor references, it is quite easy to send the wrong actor. The compiler will not check for this.

– The advantage of using Actors is that the code is isolated and can easily be moved to e.g. a remote location.

Links:
http://doc.akka.io/docs/akka/snapshot/java/untyped-actors.html
http://doc.akka.io/docs/akka/snapshot/general/actors.html

Geef een reactie

Gelieve met een van deze methodes in te loggen om je reactie te plaatsen:

WordPress.com logo

Je reageert onder je WordPress.com account. Log uit /  Bijwerken )

Google+ photo

Je reageert onder je Google+ account. Log uit /  Bijwerken )

Twitter-afbeelding

Je reageert onder je Twitter account. Log uit /  Bijwerken )

Facebook foto

Je reageert onder je Facebook account. Log uit /  Bijwerken )

Verbinden met %s