Search code examples
javaakkaakka-supervision

Message Persistence and Playback with restarted actors in Akka


Akka Java here. I have two actors, Parent and Child, where the former is the parent of the latter. If Child throws a specific exception (say, an UnrulyTeenagerExcepton), then the behavior I am looking for is as follows:

  • The Parent saves a reference to the message that was being processed by Child when the exception was thrown; then
  • Child is restarted, and the persisted message is “played back” to the Child; but
  • If this save -> restart -> replay cycle happens three times, and the Child throws the UnrulyTeenagerException three times, then we SupervisorStrategy.escalate()

My best attempt thus far:

// Groovy pseudo-code
class ChildFailureDecider extends Function<Throwable,Directive> {
    int maxRetries = 3
    int numRetries = 0

    @Override
    Directive apply(Throwable childFailure) {
        if(childFailure instanceof UnrulyTeenagerException) {
            numRetries++

            if(numRetries <= maxRetries) {
                // TODO: #1 How to persist the message that caused the ‘childFailure’?

                return SupervisorStrategy.restart()

                // TODO: #2 How to ‘play back’ the persisted message to Child?
            }
        }

        SupervisorStrategy.escalate()
    }
}

But as you can see, I’m struggling with message persistence and play back. Any ideas? Java code samples greatly appreciated, Akka is tough enough without also having to learn Scala hieroglyphics!


Solution

  • Akka persistence is about recording events (not the same thing as messages) in a persistent way (e.g. to disk, or to a database) in a persistent way so that if your whole application terminates (such as a JVM crash or hardware failure), it is possible to rebuild the state of that actor on restart. In your case, you want to remember the message sent to a single actor and resend it when that actor is restarted due to a failure, so I don't think you need the persistence API in this case.

    When an actor throws an exception, that exception is presented to the supervisor but the message that caused it is not. I don't think there is a built in way for this to be achieved. The supervisor can manage the rule of only restarting 3 times, by setting the supervision strategy with appropriate parameters: http://doc.akka.io/japi/akka/2.4-M3/akka/actor/OneForOneStrategy.html#OneForOneStrategy-int-scala.concurrent.duration.Duration-akka.japi.Function-

    The replaying of messages needs to be handled by the sender. You can implement at least once semantics by having the receiver send an acknowledgement to the sender when the message has been handled, and have the sender retry periodically if the acknowledgement is not received. See this question for more info: Akka Message Delivery Guarantees

    Sorry for the lack of code but I use the Scala API rather than Java.