使用停止策略失败后调用预启动
Prestart being called after failure with stopping strategy
我正在为远程服务上的参与者创建 retry/reconnect 功能。 actor 应该在启动前调用选择引用来订阅来自远程服务上的 actor 的消息。如果由于某种原因演员不在那里,我希望我的演员在报告连接失败之前重试几次。
我正在使用 TestKit 来测试功能。我 运行 遇到的问题是,当演员抛出超时异常时,即使我有停止策略,也会在之后调用预启动。
我是不是对actor的生命周期理解有误?如果策略是在失败后停止,那么调用 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));
}
}
Jeff 回答后我的解决方案
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 的一部分,可以为测试的监护人设置主管策略
var props = Props.Create(() => new MyActor(probe.Ref.Path))
.WithSupervisorStrategy(new OneForOneStrategy(exception => Directive.Stop));
这为 MyActor 设置了主管策略,它将用于 MyActor 的子级而不是 MyActor 本身。
Sys.ActorOf(props);
这是在默认情况下具有 OneForOne Restart 指令的 /user
监护人下创建 MyActor。这就是您的 actor 重新启动的原因。
要得到你想要的,你需要用自定义监管者策略创建一个父actor,并在其下创建MyActor
。
我正在为远程服务上的参与者创建 retry/reconnect 功能。 actor 应该在启动前调用选择引用来订阅来自远程服务上的 actor 的消息。如果由于某种原因演员不在那里,我希望我的演员在报告连接失败之前重试几次。
我正在使用 TestKit 来测试功能。我 运行 遇到的问题是,当演员抛出超时异常时,即使我有停止策略,也会在之后调用预启动。
我是不是对actor的生命周期理解有误?如果策略是在失败后停止,那么调用 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));
}
}
Jeff 回答后我的解决方案
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 的一部分,可以为测试的监护人设置主管策略
var props = Props.Create(() => new MyActor(probe.Ref.Path))
.WithSupervisorStrategy(new OneForOneStrategy(exception => Directive.Stop));
这为 MyActor 设置了主管策略,它将用于 MyActor 的子级而不是 MyActor 本身。
Sys.ActorOf(props);
这是在默认情况下具有 OneForOne Restart 指令的 /user
监护人下创建 MyActor。这就是您的 actor 重新启动的原因。
要得到你想要的,你需要用自定义监管者策略创建一个父actor,并在其下创建MyActor
。