觀察終止消息將提醒系統遠程參與者已經死亡,但是存在如何完全響應已終止的遠程參與者的問題。假設一個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);
}
}
}
謝謝你的回答。當我從不在演員身邊的一段代碼向遠程演員發送消息時,這將如何工作。例如,我使用actor選擇器向遠程actor獲得IActorRef,並通過Ask()發送消息。由於調用系統本身沒有任何演員,我不會讓演員接收終止消息。我想我可以爲此創建一個演員,但是有沒有其他方式可以實現這一點,而無需創建這樣一個專門的演員? – cfcal