我正在为远程服务上的actor创建重试/重新连接功能。 actor应该在prestart上调用选择引用来订阅来自远程服务上的actor的消息。如果由于某种原因演员不在那里,我希望我的演员在报告连接失败之前重试几次。
我正在使用TestKit来改进功能。我遇到的问题是,当actor抛出超时异常时,即使我有一个停止策略,也会在之后调用prestart。
我想知道演员的生命周期吗?如果战略要在失败后停止,似乎很奇怪调用PreStart。
public class MyActor : ReceiveActor
{
private readonly ActorPath path;
private ActorSelection selection;
private int retry = 0;
protected override void PreStart()
{
selection = Context.ActorSelection(path);
selection.Tell("prestart");
SetReceiveTimeout(TimeSpan.FromSeconds(1));
}
public MyActor(ActorPath path)
{
this.path = path;
Receive<ReceiveTimeout>(timeout =>
{
if (retry < 2)
{
retry++;
selection.Tell("retry");
return;
}
throw new Exception("timeout");
});
}
}
public class Test : TestKit
{
[Fact]
public void FactMethodName()
{
var probe = CreateTestProbe();
var props = Props.Create(() => new MyActor(probe.Ref.Path))
.WithSupervisorStrategy(new OneForOneStrategy(exception => Directive.Stop));
Sys.ActorOf(props);
//Initial
probe.ExpectMsg<string>(s => s=="prestart",TimeSpan.FromSeconds(2));
//Retries
probe.ExpectMsg<string>(s => s == "retry", TimeSpan.FromSeconds(2));
probe.ExpectMsg<string>(s => s == "retry", TimeSpan.FromSeconds(2));
//No more
probe.ExpectNoMsg( TimeSpan.FromSeconds(10));
}
}
杰夫回答后的解决方案
public class ParentActor : UntypedActor
{
private readonly Func<IUntypedActorContext, IActorRef> creation;
private IActorRef actorRef;
public ParentActor(Func<IUntypedActorContext, IActorRef> creation)
{
this.creation = creation;
}
protected override void PreStart()
{
actorRef = creation(Context);
}
protected override void OnReceive(object message)
{
actorRef.Tell(message);
}
}
public class MyActor : ReceiveActor
{
private readonly ActorPath path;
private int retry;
private ActorSelection selection;
public MyActor(ActorPath path)
{
this.path = path;
Receive<ReceiveTimeout>(timeout =>
{
if (retry < 2)
{
retry++;
selection.Tell("retry");
return;
}
throw new Exception("timeout");
});
}
protected override void PreStart()
{
selection = Context.ActorSelection(path);
selection.Tell("prestart");
SetReceiveTimeout(TimeSpan.FromSeconds(1));
}
}
public class Test : TestKit
{
[Fact]
public void FactMethodName()
{
var probe = CreateTestProbe();
var props = Props.Create(
() => new ParentActor(context => context.ActorOf(Props.Create(
() => new MyActor(probe.Ref.Path), null), "myactor")))
.WithSupervisorStrategy(new OneForOneStrategy(exception => Directive.Stop));
Sys.ActorOf(props);
//Initial
probe.ExpectMsg<string>(s => s == "prestart", TimeSpan.FromSeconds(2));
//Retries
probe.ExpectMsg<string>(s => s == "retry", TimeSpan.FromSeconds(2));
probe.ExpectMsg<string>(s => s == "retry", TimeSpan.FromSeconds(2));
//No more
probe.ExpectNoMsg(TimeSpan.FromSeconds(10));
}
}
有效,但感觉它可能是TestKit的一部分,可以为测试的监护人设定监督策略
答案 0 :(得分:1)
var props = Props.Create(() => new MyActor(probe.Ref.Path))
.WithSupervisorStrategy(new OneForOneStrategy(exception => Directive.Stop));
这为MyActor设置了主管策略,它将用于MyActor的孩子而不是MyActor本身。
Sys.ActorOf(props);
这是在/user
监护人下创建MyActor,默认情况下具有OneForOne Restart指令。这就是你的演员重新开始的原因。
要获得所需内容,您需要使用自定义主管策略创建父actor,并在其下创建MyActor
。