【问题标题】:Child actor does not get restarted on failure子actor在失败时不会重新启动
【发布时间】:2017-04-06 21:23:41
【问题描述】:

我有一个父演员是:

public sealed class PersistenceSupervisor : ReceiveActor
{

    protected override void PreStart()
    {
        base.PreStart();

        Become(Active);
    }

    protected override SupervisorStrategy SupervisorStrategy()
    {
        return new OneForOneStrategy(
            10,
            TimeSpan.FromSeconds(0),
            x =>
            {
                return Directive.Restart;
            });
    }

    private void Active(object message)
    {
        IInventorPersister inventorPersistor = new InventorPersister();
        IActorRef persister = Context.ActorOf(Props.Create<Persister>(inventorPersistor), "persisterActor");
        var task = persister.Ask(message);
        task.Wait();
        Sender.Tell(task.Result);
    }
}

还有用于测试目的的具有随机失败功能的子actor:

public sealed class Persister : ReceiveActor
{
    private readonly IInventorPersister inventorPersister;

    protected override void PreStart()
    {
        base.PreStart();

        Become(ActiveAsync);
    }

    private async void ActiveAsync(object message)
    {
        try
        {
            var savedSender = Context.Sender;
            Task persisting = Persist(message as CreatePublication);
            await persisting;
            savedSender.Tell("Success");
        }
        catch (Exception e)
        {
            throw new Exception(e.ToString());
        }
    }

    public Persister(IInventorPersister inventorPersister)        
    {
        this.inventorPersister = inventorPersister;
    }

    private async Task Persist(CreatePublication message)
    {
        RandomFailure.Fail();    
        // This function is to make an UPDATE query to db        
        await inventorPersister.Persist(message.PublicationNumber, message.Inventors);            
    }

    // Random failure for testing purpose
    private static class RandomFailure
    {
        private static readonly Random R = new Random();
        public static void Fail()
        {
            if (R.Next(0, 2) == 0)
            {
                throw new InvalidOperationException("Random failure");
            }
        }
    }
}

这个想法是重新启动子actor直到它成功。但是,当失败发生时,应用程序会立即停止并崩溃。我很感激任何帮助。非常感谢。

【问题讨论】:

    标签: c# .net akka console-application akka.net


    【解决方案1】:

    一些更一般的提示:

    1. 您正在使用ReceiveActor,它希望通过actor 构造函数中的Receive/ReceiveAsync 方法提供消息处理程序。 Become(ActiveAsync) 由非类型化 Actor 而非 ReceiveActor 继承者使用。
    2. 您处于活动状态的异步方法不会返回纯 void 的任务 - 很难预测系统将如何运行,何时会从此类方法引发异常。
    3. 不要在actor的构造函数中使用Become,如果没有必要,不要使用PreStart方法。在actor初始化期间抛出的异常总是会导致actor被停止(即使它的监督策略是重新启动它)。

    话虽如此,最简单的方法就是向您的演员提供ReceiveAsync 处理程序。

    public sealed class Persister : ReceiveActor
    {
        private readonly IInventorPersister inventorPersister;
    
        public Persister(IInventorPersister inventorPersister)
        {
            this.inventorPersister = inventorPersister;
            ReceiveAsync<CreatePublication>(async message =>
            {
                await Persist(message);
                Context.Sender.Tell("Success");
            });
        }
        private async Task Persist(CreatePublication message) { ... }
    
        ...
    }
    

    【讨论】:

    • 感谢您的帮助,但我没有得到您的答复,因为我想故意抛出异常来测试主管策略
    • 我不知道你为什么要测试它。大多数例外的演员Default strategy 是重新启动。您可以对其进行测试,但这样您就不会测试您的域,而是测试框架本身。我附加的代码显示了 ReceiveActor 的配置,因为我怀疑您初始化演员的方式破坏了他们的内部结构。
    • 因为我想确保如果发生任何异常。子actor将重新启动,直到它成功从数据库中获取数据。此外,异常不是来自构造函数,而是来自函数RandomFailure.Fail()。我已经尝试过您的代码,但它不起作用(抛出异常并使应用程序崩溃)
    • 1.除了烧毁您的应用程序服务器之外,尝试无限循环地从数据库中获取数据是没有意义的。 2. 我展示的片段仍然允许您测试代码以进行演员重试,并且是设计演员行为的实际方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-27
    • 2014-04-06
    • 2013-01-20
    • 1970-01-01
    • 2021-05-07
    • 2015-01-08
    • 2021-11-20
    相关资源
    最近更新 更多