[英]Akka.net - How to wait child actor to process all pending messages prior to stop
我們有一個名為 A 的集群分片 Actor,它有多個子 Actor,每個實體模式都使用子 Actor 創建,如下所示。 當我們告訴演員 B 給 D 的 100 條消息,演員 D 需要 500 毫秒來處理每條消息,同時,當我們使用 Context.Parent.Tell 將毒丸發送給演員 A 時(new Passivate (PoisonPill.Instance )); 它立即停止所有子actor,包括actor D,而不處理待處理的消息。
A
|
B
/ \
C D
有沒有辦法等待演員 D 處理所有消息?
https://stackoverflow.com/a/70286526/377476是一個好的開始; 您將需要自定義關閉消息。 當父actor終止時,它的子actor通過/system
消息自動殺死,這些消息取代了隊列中任何未處理的/user
消息。
因此,您需要做的是確保他們的所有/user
消息都在父級終止之前得到處理。 使用GracefulStop
擴展方法和您的自定義停止消息有一種簡單的方法:
public sealed class ActorA : ReceiveActor{
private IActorRef _actorB;
private readonly ILoggingAdapter _log = Context.GetLogger();
public ActorA(){
Receive<StartWork>(w => {
foreach(var i in Enumerable.Range(0, w.WorkCount)){
_actorB.Tell(i);
}
});
ReceiveAsync<MyStopMessage>(async _ => {
_log.Info("Begin shutdown");
// stop child actor B with the same custom message
await _actorB.GracefulStop(TimeSpan.FromSeconds(10), _);
// shut ourselves down after child is done
Context.Stop(Self);
});
}
protected override void PreStart(){
_actorB = Context.ActorOf(Props.Create(() => new ActorB()), "b");
}
}
public sealed class ActorB : ReceiveActor{
private IActorRef _actorC;
private IActorRef _actorD;
private readonly ILoggingAdapter _log = Context.GetLogger();
public ActorB(){
Receive<int>(i => {
_actorC.Tell(i);
_actorD.Tell(i);
});
ReceiveAsync<MyStopMessage>(async _ => {
_log.Info("Begin shutdown");
// stop both actors in parallel
var stopC = _actorC.GracefulStop(TimeSpan.FromSeconds(10));
var stopD = _actorD.GracefulStop(TimeSpan.FromSeconds(10));
// compose stop Tasks
var bothStopped = Task.WhenAll(stopC, stopD);
await bothStopped;
// shut ourselves down immediately
Context.Stop(Self);
});
}
protected override void PreStart(){
var workerProps = Props.Create(() => new WorkerActor());
_actorC = Context.ActorOf(workerProps, "c");
_actorD = Context.ActorOf(workerProps, "d");
}
}
public sealed class WorkerActor : ReceiveActor {
private readonly ILoggingAdapter _log = Context.GetLogger();
public WorkerActor(){
ReceiveAsync<int>(async i => {
await Task.Delay(10);
_log.Info("Received {0}", i);
});
}
}
我在這里創建了此示例的可運行版本: https://dotnetfiddle.net/xiGyWM - 您會看到在示例開始后不久收到了MyStopMessage
,但在C 和 D 已經完成工作之后。 在此場景中任何參與者終止之前,所有這些工作都已完成。
您可以定義自己的停止消息,並讓參與者使用Context.Stop(Self)
來處理它,而不是發送PoisonPill
- 這是一條系統消息,因此比傳統消息具有更高的優先級。
class MyShardedActor : ReceiveActor {
public MyShardedActor() {
Receive<MyStopMessage>(_ => Context.Stop(Self));
}
}
您可以使用ClusterSharding.Start方法重載注冊您的自定義消息,以與集群自行觸發的鈍化調用一起使用,該方法采用handOffMessage
參數,將在Passivate
請求而不是PoisonPill
中發送。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.