【问题标题】:How to handle a stale akka.net remote iactorref如何处理陈旧的 akka.net 远程 iactorref
【发布时间】:2016-12-22 22:40:15
【问题描述】:

我在一个长期运行的 Windows 服务中使用 akka.net 中的远程参与者。我使用 ActorSelection 为远程参与者获取了一个 IActorRef,并且我在服务中保持这个 IActorRef 活动的时间很长一段时间。 IActorRef 指向在另一个 Windows 服务中运行的参与者系统。 我知道远程参与者的重新启动不会使远程参与者参考无效。但是,可以想象远程windows服务可能会在某个时候重新启动,并且调用windows服务中的IActorRef会变得无效。

处理此问题的最佳做法是什么? 一种天真的方法是每次我想调用远程参与者时使用 ActorSelection 来获取一个新的 IActorRef 。这显然是低效的。

另一种方法可能是简单地将我对该 IActorRef 所做的每个调用包装在某种错误处理信封中,该信封捕获异常并使用actorselection 和重试获取新的 IActorRef?或者信封可能会在每次实际调用之前进行测试调用,以查看远程 actor 是否还活着,如果没有,则获取一个新的 actor ref。

有更好的方法吗?

【问题讨论】:

    标签: akka.net akka-remoting


    【解决方案1】:

    检测死演员的默认选项是Watch 他们(见documentation)。当一个演员观看另一个演员时,它将收到Terminated 消息,一旦观看的演员死亡或无法访问。

    【讨论】:

    • 感谢您的回答。当我从一段不在 Actor 内部的代码向远程 Actor 发送消息时,这将如何工作。例如,我使用演员选择获取远程演员的 IActorRef,并通过 Ask() 向其发送消息。由于调用系统本身没有任何演员,我不会有演员来接收终止消息。我想我可以为此目的创建一个演员,但是有没有其他方法可以实现这一点而不必创建这样一个专门的演员?
    【解决方案2】:

    观察 Terminated 消息会提醒系统远程 actor 已经死亡,但问题是如何准确响应终止的远程 actor。假设一个actor通过其构造函数获得了一个远程actor的IActorRef,那么当它再次活跃时,该actor如何获取远程actor的一个新的IActorRef。一种方法是让actor失败并委托给父actor,然后父actor将通过actor选择获得一个新的IActorRef给远程actor。然而,这样做的问题是,远程参与者的原始参与者选择可能发生在组合根中的非参与者代码中,通常会发生依赖注入。我想你可以通过传递一个演员选择工厂委托来解决这个问题,该委托可用于重建远程 IActorRef。我想出的另一种方法是创建一个实现 IActorRef 的包装类,称为 FaultTolerantActorRef。

    该类在构造函数中获取远程(或本地)actor 的路径,并定期执行actor 选择以获取远程actor 的刷新 IActorRef。这样,如果由于某种原因远程 actor 死亡,对 FaultTolerantActorRef 的调用将在远程 actor 死亡时以死信告终。但是,当远程 Actor 最终再次上线时,对 FaultTolerantActorRef 的调用最终将到达新恢复的远程 Actor,而无需对调用本地 Actor 采取任何显式操作。

    有一个 Invalidate 方法将强制 FaultTolerantActorRef 在下一次调用时进行新的演员选择。这可能由一个actor调用,以响应来自远程actor的 Terminated 消息。即使不调用 Invalidate,也会根据传递给构造函数的刷新间隔进行新的 Actor 选择。

    using Akka.Actor;
    using System;
    using Akka.Util;
    using System.Threading;
    
    namespace JA.AkkaCore
    {
        public class FaultTolerantActorRef : IActorRef
        {
            public IActorRef ActorRef
            {
                get
                {
                    if (!_valid || DateTime.Now.Ticks > Interlocked.Read(ref _nextRefreshTime))
                        RefreshActorRef();
                    return _actorRef;
                }
    
            }
    
            public ActorPath Path
            {
                get
                {
                    return ActorRef.Path;
                }
            }
    
            object _lock = new object();
            IActorRef _actorRef;
            volatile bool _valid;
            string _path;
            IActorRefFactory _actorSystem;
            private TimeSpan _requestTimeout;
            private TimeSpan _refreshInterval;
            //private DateTime _nextRefreshTime = DateTime.MinValue;
            private long _nextRefreshTime = DateTime.MinValue.Ticks;
    
            public FaultTolerantActorRef(IActorRefFactory actorSystem, IActorRef actorRef,
                TimeSpan refreshInterval = default(TimeSpan), TimeSpan requestTimeout = default(TimeSpan))
                : this(actorSystem, actorRef.Path.ToString(), refreshInterval, requestTimeout)
            {
                _actorRef = actorRef;
                _valid = true;
            }
            public FaultTolerantActorRef(IActorRefFactory actorSystem, string actorPath,
                TimeSpan refreshInterval = default(TimeSpan), TimeSpan requestTimeout = default(TimeSpan))
            {
                if (refreshInterval == default(TimeSpan))
                    _refreshInterval = TimeSpan.FromSeconds(60);
                else
                    _refreshInterval = refreshInterval;
                if (requestTimeout == default(TimeSpan))
                    _requestTimeout = TimeSpan.FromSeconds(60);
                else
                    _requestTimeout = requestTimeout;
                _actorSystem = actorSystem;
                _valid = false;
                _path = actorPath;
            }
            private void RefreshActorRef()
            {
                lock(_lock)
                {
                    if (!_valid || DateTime.Now.Ticks > _nextRefreshTime)
                    {
                        _actorRef = _actorSystem.ActorSelectionOne(_path, _requestTimeout);
                        Interlocked.Exchange(ref _nextRefreshTime,DateTime.Now.Ticks + _refreshInterval.Ticks);
                        _valid = true;
                    }
                }
            }
    
            public void Invalidate()
            {
                _valid = false;
            }
    
            public void Tell(object message, IActorRef sender)
            {
                ActorRef.Tell(message, sender);
            }
    
            public bool Equals(IActorRef other)
            {
                return ActorRef.Equals(other);
            }
    
            public int CompareTo(IActorRef other)
            {
                return ActorRef.CompareTo(other);
            }
    
            public ISurrogate ToSurrogate(ActorSystem system)
            {
                return ActorRef.ToSurrogate(system);
            }
    
            public int CompareTo(object obj)
            {
                return ActorRef.CompareTo(obj);
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-31
      • 1970-01-01
      • 2021-04-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多