1

Assuming I have a parent actor that sends one message at a time to its child actor.

When the child is done processing the current message it notifies the parent that in it turn will send a new message to the child.

In order to keep this loop even if the child crashs on a certain message, I added a SupervisorStrategy to the parent:

    private static SupervisorStrategy strategy =
        new OneForOneStrategy(10, Duration.create("1 minute"),
                new Function<Throwable, SupervisorStrategy.Directive>() {
                    @Override
                    public SupervisorStrategy.Directive apply(Throwable t) {
                        if (t instanceof NullPointerException) {
                            return resume();
                        } else {
                            return escalate();
                        }
                    }
                });

The idea is that no matter what heppens to the child, it will resume and the parent will be able to send it the next message.

But how the parent knows when the error occured, in order to send the next message?

What is the trigger for the parent that something happend to the child?

Is there something like "onChileError" method that I need to override?

(will appriciate a Java over Scala example)

Thanks.

t-rex-50
  • 201
  • 1
  • 4
  • 10

2 Answers2

1

When the child is done processing the current message it notifies the parent that in it turn will send a new message to the child....

The idea is that no matter what heppens to the child, it will resume and the parent will be able to send it the next message.

Your current supervisor strategy does the following: If a NullPointerException is thrown in the child, the child is resumed as if nothing happened. If a different exception is thrown, it's escalated farther up the actor hierarchy, which likely means that the default supervisor strategy kicks in, in which case the child is restarted. If you want the child to resume regardless of the exception, change your strategy to the following (I'm using the DeciderBuilder):

private static SupervisorStrategy strategy =
  new OneForOneStrategy(10, Duration.create(1, TimeUnit.MINUTES), DeciderBuilder.
    match(Exception.class, e -> {
      // getSelf() is the parent and getSender() is the child
      GiveMeAnotherMessage message = // ...
      getSelf().tell(message, getSender());
      resume();
    })
    .matchAny(o -> escalate())
    .build());

@Override
public SupervisorStrategy supervisorStrategy() {
  return strategy;
}

But how the parent knows when the error occured, in order to send the next message?

What is the trigger for the parent that something happend to the child?

Is there something like "onChileError" method that I need to override?

The decider can access the reference of the currently failed child via getSender(), so all you have to do is send a message to the parent to let it know that the child is ready to process another message from within the strategy itself, as the above code shows.

Jeffrey Chung
  • 19,319
  • 8
  • 34
  • 54
0

I would suggest to implement the next scenario (samples are in Scala):

Configure supervisor strategy to stop on errors

// Stop actors on error - DeathWatch will handle restart sequence
override def supervisorStrategy: SupervisorStrategy = SupervisorStrategy.stoppingStrategy

Subscribe to child's death watch on creation

def createWorker() = {
  val worker = actorOf(...)
  context.watch(worker)
  worker
}

If the child is terminated unexpectedly, create a new one and resend the current portion of work to do (or the next one if appropriate)

case Terminated(actor) => 
  val worker = createWorker()
  worker ! DoWork(...)

This will also help once you start scaling actors in cluster, since when a node becomes unreachable in a cluster it will not trigger supervision strategy, only remote death watch.

Vasiliy Ivashin
  • 425
  • 2
  • 12