If the strategy is declared inside the supervising actor (as opposed to within a companion object) its decider has access to all internal state of the actor in a thread-safe fashion, including obtaining a reference to the currently failed child (available as the sender of the failure message).
But what about the following alternative:
class Supervisor(f: Actor => Decider) extends Actor {
override val supervisorStrategy =
OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute)(f(this))
}
val decider: Actor => Decider = (actor: Actor) => {
case e =>
actor.sender() // this should be the ActorRef of the Actor that throw the exception
Resume
}
val supervisor = system.actorOf(Supervisor.props(decider), "supervisor")
I’m not sure what your question is? You are declaring the strategy inside the supervision actor, and as such you have access to this.sender() (even if you add some indirection by passing around a function).
Does this not appear to work for you? Or did you find the documentation unclear? How would you document this more clearly?
Hello Arnout, thanks for answering.
My question is about declaring the supervisorStrategy inside the Actor but the decider outside of it (so I don’t have acess to sender()) and I want to access supervisor internal state (sender() and more) from it to choose the Directive.
For example (fiddle):
class MyDecider(actor: SupervisorActor, limit: Int) extends Decider {
import akka.actor.SupervisorStrategy._
override def isDefinedAt(x: Throwable): Boolean = true
override def apply(v1: Throwable): SupervisorStrategy.Directive = v1 match {
case ActorException(ref,t,msg) if actor.restarts < limit =>
actor.restarts = actor.restarts + 1 // <-- I understand that this is safe (although may not be elegant)
Restart
case ActorException(ref,t,msg) =>
Stop
case notmatched =>
SupervisorStrategy.defaultDecider.apply(notmatched)
}
}
class SupervisorActor(decider: SupervisorActor => Decider) extends Actor {
// just for the example. I know that exist akka ways to limit the number of restarts
var restarts = 0
var child: Option[ActorRef] = None
override val supervisorStrategy = OneForOneStrategy()(decider(this))
override def receive: Receive = {
case Terminated(_) => println("The worker has stopped")
case props: Props =>
val _child = context.actorOf(props)
context.watch(_child)
child = Some(_child)
case e => child.foreach(_ forward e)
}
}
val deciderBuilder = (limit: Int) => (supervisor: SupervisorActor) => new MyDecider(supervisor,limit)
val supervisor = system.actorOf(SupervisorActor.props(deciderBuilder(3)))
I understand that this is safe because the child actors sends Failures to supervisor as simple akka messages.