【问题标题】:How do I warm up an actor's state from database when starting up?启动时如何从数据库中预热演员的状态?
【发布时间】:2015-05-11 02:46:58
【问题描述】:

我的要求是启动一个长时间运行的过程来标记所有过期的产品。这是每晚凌晨 1:00 运行的。客户可能正在访问网站上的某些产品,因此他们在作业运行时有实例。其他的在持久媒体中,还没有实例,因为客户没有访问它们。

我应该在哪里连接逻辑以从持久媒体读取演员的最新状态并创建一个全新的演员?我应该在 Prestart 覆盖方法中调用吗?如果是这样,我如何告诉 ProductActor 正在创建一个新演员。

或者我应该向 ProductActor 发送消息,例如 LoadMeFromAzureTable,它会在创建 Actor 后从持久媒体加载状态?

【问题讨论】:

  • 我是否理解您的意思是您正在为每个产品创建一个演员??
  • 为每个产品创建一个参与者将有助于扩展。我也不想让他们留在系统中,因为这是一项工作,所以工作完成后,所有产品参与者都需要被杀死。

标签: persistence akka.net


【解决方案1】:

根据您的需要,有不同的方法可以做到这一点,而不是只有一个“正确”的答案。

您可以使用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 {}

【讨论】:

    猜你喜欢
    • 2017-04-11
    • 2019-04-23
    • 1970-01-01
    • 2017-12-27
    • 2017-03-15
    • 1970-01-01
    • 2011-11-05
    • 2022-07-29
    • 2012-09-02
    相关资源
    最近更新 更多