在AKKA中重试/重播失败的消息

时间:2016-09-01 13:03:48

标签: scala akka actor akka.net

我在当前的.NET项目中使用AKKA.NET。

我的问题是:经验丰富的AKKA开发人员如何使用最新的AKKA库来实现Java或.NET的重播消息模式?

以下是一些更多细节。

我想确保多次重播/重试失败的消息(即导致异常的actor接收的消息),每次之间的时间间隔。通常,失败的消息被抛弃后重新启动actor。

我已经编写了这样的小辅助方法来解决它:

   public void WithRetries(int noSeconds, IUntypedActorContext context, IActorRef receiver, IActorRef sender, Object message, Action action)
    {
            try
            {
                action();
            }
            catch (Exception e)
            {
                context.System.Scheduler.ScheduleTellOnce(new TimeSpan(0, 0, noSeconds), receiver, message, sender);
                throw;
            }
        }
    }

现在我的演员通常看起来像这样:

 Receive<SomeMessage>(msg =>
        {

            ActorHelper.Instance.WithRetries(-1, Context, Self, Sender, msg, () =>     {
              ...here comes the actual message processing  
            });
        });

我喜欢上述解决方案,因为它很简单。但是,我不喜欢它在我的代码中添加了另一层间接,如果我在很多地方使用这个辅助方法,代码会变得更乱。此外,它有一些局限性。首先,重试次数不受辅助方法的约束。它由主管的监督策略管理,我认为这是凌乱的。此外,时间间隔是固定的,而在某些情况下,我会在每次重试时增加时间间隔。

我更喜欢可以使用HOCON配置的东西。或者可以作为交叉问题应用的东西。

我可以看到针对Scala的AKKA,针对Java的AKKA和AKKA.NET的各种建议。我见过路由器的例子,断路器的例子(例如http://getakka.net/docs/CircuitBreaker#examples)等等。我也看到了一些使用与上述相同的想法的例子。但我觉得它应该更简单。也许它涉及一些AKKA持久性和事件的使用。

所以重复我的问题:经验丰富的AKKA开发人员如何使用最新的AKKA库来实现Java或.NET的重播消息模式?

2 个答案:

答案 0 :(得分:2)

我去年调查了这个 - 我离开了我的开发机器所以无法检查,所以这一切都来自记忆:

我似乎记得这个解决方案是存储和监督策略以及生命周期钩子的组合:)

认为你可以将你的子actor代码包装在try-catch中,然后在出错的情况下,隐藏消息并重新抛出异常,以便由主管和所有人处理通常的监管策略发挥作用。我认为你会恢复而不是重启。然后在适当的生命周期消息(onresume?!)中解压消息,这意味着将再次处理失败的消息。

现在这与你上面发布的内容并没有什么不同,所以希望有人有更好的解决方案:)

答案 1 :(得分:0)

This may be late. But another solution is to pass the comamnd (or essential params) to the actor constructor and send the command to islef when created and use the Restart directive.

// Scala code
class ResilientActor(cmd:Comman) extends Actor {
  def receive = {
     ...
  }
  self ! cmd
}

...

override val supervisorStrategy = OneForOneStrategy(maxNrOfRetries = 3){
  case _: SomeRetryableException => Restart
  case t => super.supervisorStrategy.decider.applyOrElse(t, (_:Any) => Escalate)
}