Akka.net faulttolerance,SuperVisorStrategy并丢失导致异常的消息

时间:2015-12-22 13:09:30

标签: akka.net

我正在查看Akka.net faulttolerance,并设置了一个简单的示例,其中Actor1告诉Actor2一条消息。 Actor2抛出异常。 Actor1有一个SuperVisorStrategy,告诉失败的actor恢复。

我实际上预计该消息将再次传递给Actor2。但事实并非如此。所以Actor2恢复并可以继续处理新消息。 但是现在让演员失败的消息已经消失了。应如何处理?我不想丢失导致异常的消息。我希望Actor2再次处理该消息。

namespace ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            using (ActorSystem actorSystem = ActorSystem.Create("test"))
            {
                IActorRef customer = actorSystem.ActorOf(Props.Create<Actor1>(), "actor1");

                customer.Tell(new Start());
                Console.Read();
            }
        }
    }

    public class Actor1 : UntypedActor
    {
        protected override SupervisorStrategy SupervisorStrategy()
        {
            return new OneForOneStrategy(3, TimeSpan.FromSeconds(5), ex =>
            {
                if (ex is ApplicationException)
                    return Directive.Resume;

                return Directive.Escalate;
            });
        }

        protected override void OnReceive(object message)
        {
            if (message is Start)
            {
                IActorRef actor2Ref = Context.ActorOf<Actor2>("actor2");
                Context.Watch(actor2Ref);

                actor2Ref.Tell(new DoSomething());
            }

            else if (message is Response)
            {
                Console.WriteLine("Response received");
                return;
            }
            else if (message is Terminated)
            {
                Console.WriteLine("Terminated");
            }
        }
    }

    public class Actor2 : UntypedActor
    {
        protected override void OnReceive(object message)
        {
            if (message is DoSomething)
            {
                // only called once.
                throw new ApplicationException("testexception");
            }
        }
    }

    public class Start
    {
    }

    public class DoSomething
    {
    }

    public class Response
    {
    }
}

1 个答案:

答案 0 :(得分:2)

通常,您不太可能连续多次重新处理相同的容易出错的消息。如果它导致异常,在同一毫秒内反复处理它可能会带来完全相同的结果。

可能想要实现的目标是在一段时间后尝试重新处理它,即因为您尝试重新连接到外部服务。在这种情况下,您可能希望将其包装到另一个消息中,并在ActorSystem调度程序中安排重新发送。基本示例:

sealed class Retry
{
    public readonly object Message;
    public readonly int Ttl;

    public Retry(object message, int ttl)
    {
        Message = message;
        Ttl = ttl;
    }
}

class MyActor : ReceiveActor 
{
    ...

    protected override void PreRestart(Exception reason, object message)
    {
        Retry oldRetry;
        var retry = (oldRetry = message as Retry) != null 
            ? new Retry(oldRetry.message, oldRetry.Ttl - 1)
            : new Retry(message, retryCount);

        if (retry.Ttl > 0)
            Context.System.Scheduler.ScheduleTellOnce(delay, Self, retry, Sender);

        base.PreRestart(reason, message);
    }
}

根据您的需要,其他一些案例也可能涉及使用CircuitBreakers或更可靠的传递语义 - 默认情况下,Akka.NET提供最多一次传递语义,您可以使用Akka.Persistence中的AtLeastOnceDelivery组件来更改此信息。插件。