2016-12-22 55 views
1

我在akka.net中使用遠程演員長期保持windows服務。我使用ActorSelection爲遠程actor創建一個IActorRef,並在服務中保持IActorRef長時間處於活動狀態。 IActorRef指向在另一個Windows服務中運行的角色系統。 我明白,遠程actor的重啓不會使遠程actor參數失效。但是,可以想象,遠程Windows服務可能會在某個時間點重新啓動,並且調用Windows服務中的IActorRef將失效。如何處理陳舊的akka​​.net遠程iactorref

處理此問題的最佳做法是什麼? 幼稚的方法是每次我想打電話給遠程actor時,使用ActorSelection來獲得一個新的IActorRef。這顯然是低效的。

另一種方法可能是簡單地將每個我在該IActorRef上進行的調用包裝在某種錯誤處理信封中,以捕獲異常並使用actors選擇和重試獲取新的IActorRef?或者信封可能在每次實際呼叫之前進行測試呼叫,以查看遠程演員是否仍然活着,如果沒有得到新演員參考。

有沒有更好的辦法?

回答

1

檢測死亡演員的默認選項是Watch(參見documentation)。當一個演員觀看另一個演員時,它將收到Terminated消息,一旦觀看的演員死亡或無法到達。

+0

謝謝你的回答。當我從不在演員身邊的一段代碼向遠程演員發送消息時,這將如何工作。例如,我使用actor選擇器向遠程actor獲得IActorRef,並通過Ask()發送消息。由於調用系統本身沒有任何演員,我不會讓演員接收終止消息。我想我可以爲此創建一個演員,但是有沒有其他方式可以實現這一點,而無需創建這樣一個專門的演員? – cfcal

0

觀察終止消息將提醒系統遠程參與者已經死亡,但是存在如何完全響應已終止的遠程參與者的問題。假設一個actor通過它的構造函數獲得一個IActorRef給一個遠程actor,那麼當這個actor再次活躍時,如何獲得一個新的IActorRef給遠程actor。一種方法是讓演員失敗並委託給父代演員,然後通過演員選擇獲得一個新的IActorRef給遠程演員。然而,問題在於,遠程參與者的原始參與者選擇可能發生在通常會發生依賴性注入的組合根中的非參與者代碼中。我想你可以通過傳遞一個actor選擇工廠委託來解決這個問題,它可以用來重建遠程IActorRef。我想出的另一種方法是創建一個實現IActorRef的包裝類,名爲FaultTolerantActorRef。

該類在構造函數中使用遠程(或本地)actor的路徑,並定期執行一個actor選擇以獲得對遠程actor的刷新IActorRef。這樣,如果由於某種原因,遠程參與者死亡時調用FaultTolerantActorRef將在遠程參與者死亡時以死信結束。但是,當遠程參與者最終重新聯機時,對FaultTolerantActorRef的調用最終將到達新近重新啓動的遠程參與者,而不必對調用本地參與者採取任何明確的行動。

有一個Invalidate方法將強制FaultTolerantActorRef在下次調用時執行新的actor選擇。這可能會被一個演員響應來自遠程演員的終止消息而被調用。即使不調用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); 
     } 
    } 
}