Question

I have a Play framework 2 application that also uses Akka. I have an Actor that receives messages from a remote system, the amount of such messages can be very huge. After a message is received, i log it into the database (using the built-in Ebean ORM) and then continue to process it. I don't care, how fast this database logging works, but it definitely should not block the further processing. Here is a simplified code sample:

public class MessageReceiver extends UntypedActor {

    @Override
    public void onReceive(Object message) throws Exception {
        if (message instanceof ServerMessage) {
            ServerMessage serverMessage = (ServerMessage) message;
            ServerMessageModel serverMessageModel = new ServerMessageModel(serverMessage);
            serverMessageModel.save();
            //now send the message to another actor for further processing
        } else {
            unhandled(message);
        }
    }
}

As i understand, database inserting is blocking in this realization, so it does not meet my needs. But i can't figure out how to make it unblocking. I've read about the Future class, but i can't get it to work, since it should return some value, and serverMessageModel.save(); returns void.I understand that writing a lot of messages one-by-one into the database is unefficient, but that is not the issue at the moment.

Am i right that this implementation is blocking? If it is, how can i make it run asynchronously?

Was it helpful?

Solution

If you wish to use Future - construct an Akka Future with a Callable (anonymous class), whose apply() will actually implement the db save code. You can actually put all of this (future creation and apply()) in your ServerMessageModel class -- maybe call it asynchSave(). Your Future maybe Future where status is the result of asynchSave...

public Future<Status> asyncSave(...) { /* should the params be ServerMessageModel? */
  return future(new Callable<Status>() {
     public Status call() {
        /* do db work here */
     }
 }

In your onReceive you can go ahead with tell to the other actor. NOTE: if you want to make sure that you are firing the tell to the other actor after this future returns, then you could use Future's onSuccess.

Future<Status> f = serverMessageModel.asyncSave();
f.onSuccess(otherActor.tell(serverMessage, self());

You can also do failure handling... see http://doc.akka.io/docs/akka/2.3.4/java/futures.html for further details.

Hope that helps.

OTHER TIPS

Future solution seems good to me. I haven't used Futures from Java, but you can just return arbitrary Integer or String if you definitely need some return value.

Other option is to send that message to some other actor which would do the saving to the DB. Then you should make sure that the mailbox of that actor would not overfill.

Have you considered akka-persistence for this? Maybe that would suit your use-case.

Persist actor state with Martin Krassers akka-persistence extension and my jdbc persistence provider akka persistence jdbc https://github.com/dnvriend/akka-persistence-jdbc

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top