public void A_supervisor_hierarchy_must_handle_failure_in_creation_when_supervision_strategy_returns_Resume_and_Restart()
{
var createAttempt = new AtomicCounter(0);
var preStartCalled = new AtomicCounter(0);
var postRestartCalled = new AtomicCounter(0);
EventFilter.Exception<Failure>()
.And.Exception<InvalidOperationException>("OH NO!")
.And.Error(start: "changing Recreate into Create")
.And.Error(start: "changing Resume into Create")
.Mute(() =>
{
//Create:
// failresumer
// |
// failingChild
// | (sometimes)
// workingChild
var failresumer = ActorOf((resumerDsl, context) =>
{
resumerDsl.Strategy = new OneForOneStrategy(ex => ex is ActorInitializationException ? (createAttempt.Current % 2 == 0 ? Directive.Resume : Directive.Restart) : Directive.Escalate);
var failingChild = context.ActorOf((childDsl, childContext) =>
{
var ca = createAttempt.IncrementAndGet();
if (ca <= 6 && ca % 3 == 0)
childContext.ActorOf(BlackHoleActor.Props, "workingChild" + ca);
if (ca < 6)
throw new InvalidOperationException("OH NO!");
childDsl.OnPreStart = _ => preStartCalled.IncrementAndGet();
childDsl.OnPostRestart = (e, _) => postRestartCalled.IncrementAndGet();
childDsl.ReceiveAny((m, actorContext) => actorContext.Sender.Tell(m));
}, "failingChild");
resumerDsl.ReceiveAny((m, _) => failingChild.Forward(m));
}, "failresumer");
//Send failresumer some meatballs. This message will be forwarded to failingChild
failresumer.Tell("Köttbullar");
ExpectMsg("Köttbullar");
});
createAttempt.Current.ShouldBe(6);
preStartCalled.Current.ShouldBe(1);
postRestartCalled.Current.ShouldBe(0);
}