我的要求是启动一个长时间运行的流程来标记所有过期的产品。这是每天凌晨1:00运行。客户可能正在访问网站上的某些产品,因此他们在作业运行时都有实例。其他人在持久媒体中,尚未拥有实例,因为客户没有访问它们。
我应该在哪里连接逻辑以从持久性媒体中读取演员的最新状态并创建一个全新的演员?我应该在 Prestart 覆盖方法中进行该调用吗?如果是这样,我如何告诉 ProductActor 正在创建一个新的actor。
或者我应该向 ProductActor 发送消息,例如 LoadMeFromAzureTable ,它会在创建演员后从持久媒体加载状态?
答案 0 :(得分:3)
根据您的需要,有不同的方法可以做到这一点,而不是只有一个"对"答案。
您可以使用Persistent Actor在启动时自动从持久存储中恢复状态(或者在崩溃的情况下恢复)。或者,如果您不想使用该模块(截至2015年7月仍处于测试阶段),您可以自己选择以下两种方式之一:
1)您可以在PreStart
中加载您的状态,但是如果您可以通过数据库客户端使操作异步并使用the PipeTo
pattern将结果发回,我只会使用此状态逐渐地给自己。但是如果你在开始工作之前需要将所有州都留在记忆中,那么你需要......
2)制作一个finite state machine using behavior switching。从一个门控状态开始,给自己发送一条消息来加载你的数据,然后存入所有进来的东西。然后切换到一个接收状态,并在你的状态加载完成后取消所有消息。这是我喜欢的方法。
示例(仅使用Task
模拟数据库负载):
public class ProductActor : ReceiveActor, IWithUnboundedStash
{
public IStash Stash { get; set; }
public ProductActor()
{
// begin in gated state
BecomeLoading();
}
private void BecomeLoading()
{
Become(Loading);
LoadInitialState();
}
private void Loading()
{
Receive<DoneLoading>(done =>
{
BecomeReady();
});
// stash any messages that come in until we're done loading
ReceiveAny(o =>
{
Stash.Stash();
});
}
private void LoadInitialState()
{
// load your state here async & send back to self via PipeTo
Task.Run(() =>
{
// database loading task here
return new Object();
}).ContinueWith(tr =>
{
// do whatever (e.g. error handling)
return new DoneLoading();
}).PipeTo(Self);
}
private void BecomeReady()
{
Become(Ready);
// our state is ready! put all those stashed messages back in the mailbox
Stash.UnstashAll();
}
private void Ready()
{
// handle those unstashed + new messages...
ReceiveAny(o =>
{
// do whatever you need to do...
});
}
}
/// <summary>
/// Marker interface.
/// </summary>
public class DoneLoading {}