akka.net icon indicating copy to clipboard operation
akka.net copied to clipboard

Need to document `ActorInitializationException` and how it occurs in actor lifecycle

Open Aaronontheweb opened this issue 2 years ago • 2 comments

Well I learned something new today

Throwing an exception in an actor's PreStart block will not allow the actor to be restarted: https://replit.com/@Aaronontheweb/ActorsPreStart#main.cs

I'm trying to imagine if that's by design or not (it might be since the child actor can't really complete its startup sequence if it fails there.)

Either way, that means this bug is more severe than I thought. We'll get this patched right away.

Originally posted by @Aaronontheweb in https://github.com/akkadotnet/akka.net/issues/5962#issuecomment-1138580434


One implication of this is that the actor's PostStop method is also never called, which causes functions that depend on PostStop for cleanup such as IWithTimers to never run correctly.

Aaronontheweb avatar May 26 '22 20:05 Aaronontheweb

I think that's because any exception in an actor's PreStart will throw ActorInitializationException, to which the default Supervisor Strategy will react by stopping (not restarting) the actor.

If you use a supervisor with a custom-defined Supervisor Strategy that restarts on every exception, then it'll work:

public class MySupervisorActor : UntypedActor
{
    private IActorRef actor;

    protected override SupervisorStrategy SupervisorStrategy() =>
        new OneForOneStrategy(Decider.From(_ => Directive.Restart));

    protected override void PreStart()
    {
        base.PreStart();
        actor = Context.ActorOf(Props.Create<MyActor>(), "myactor");
    }

    protected override void OnReceive(object message) => actor.Forward(message);
}

public class MyActor : UntypedActor
{
    public bool _failedOnce;

    protected override void PreStart()
    {
        if (_failedOnce)
            return;

        _failedOnce = true;
        throw new ApplicationException("crashing!");
    }

    protected override void OnReceive(object message) => Context.Sender.Tell(message);
}

ismaelhamed avatar Jun 02 '22 10:06 ismaelhamed

In that case this is working as intended, but we should probably expand on this inside the documentation: https://getakka.net/articles/actors/fault-tolerance.html

Aaronontheweb avatar Jun 02 '22 12:06 Aaronontheweb