代码之家  ›  专栏  ›  技术社区  ›  user_mda

Akka有限状态机实例

  •  44
  • user_mda  · 技术社区  · 7 年前

    我试图利用Akka的有限状态机框架来处理我的用例。我正在开发一个系统来处理一个经过各种状态的请求。

    这里的请求是需要与其依赖的应用程序一起部署的应用程序名称:

    Request for application A -> A is in a QUEUED state
    Discover A's dependency B -> B is in a QUEUED state
    B is being processed -> B is in a PROCESSING STATE
    A is being processed -> A is in a PROCESSING STATE
    B is processed -> B is in a DONE state
    A is processed -> A is in a DONE state
    

    为此,我在发现时初始化一个有限状态机。所以呢 A 的FSM在请求传入时创建, B 的FSM在 B类 是从一个演员那里发现的。

    我是否初始化并将FSM实例传递给所有参与者,同时 tell FSM如何处理数据以使状态机处于正确的状态?

    以下是状态机的相关部分:

    when(QUEUED, matchEvent(requestAccepted.class, MyApp.class,
        (requestAccepted, service) -> 
        goTo(PROCESSING).replying(PROCESSING)));
    
    when(PROCESSING, matchEvent(completed.class, MyApp.class,
        (completed, service) -> goTo(DONE).replying(DONE)));
    
    // During transitions, save states in the database.
    onTransition(matchState(PROCESSING, DONE, () -> {
      nextStateData().setServiceStatus(DONE);
      databaseWriter.tell(nextStateData(), getSelf());
    

    下面是一个处理请求的参与者的例子:

    ProcessingActor extends AbstractActor {
    
        @Override
          public void onReceive(Object message) throws Throwable {
            if (message instanceof processApplication) {
             // process the app
             // Initialize FSM for the Application
             FSM myFSM = Props.create(MYFSM.class);
             myFSM.tell( new completed(processApplication.app)
        }
    

    这是初始化状态机并使用它的正确方法吗?或者初始化应该发生在 ProcessingActor ? 但在这种情况下,每个应用程序(数据)不会有一个状态机。

    0 回复  |  直到 7 年前
        1
  •  1
  •   Curiosa Globunznik    4 年前

    虽然OP中对状态和转换的描述相当模糊,但所选实现的状态、其含义和替代方案的含义可以得到解决。

    手头的实现可以算作“每个请求的参与者”方法,而不是更常见的状态机参与者缓冲和处理多个请求的方法。下文将进一步介绍。

    在目前的形式中,给定的实现是唯一的 每个请求的抽象FSM 我知道,实际上还有另一个FSM下游,它不能再被称为“每个请求”,很可能可以避免。大致如下:

    actor per request FSM

    “每个请求的参与者”最初似乎出现在 this discussion ,这给了 this blog 一段时间后,甚至偶尔声称 a pattern . 部分原因似乎是复制了 Spray framework ,类似于Akka http的前身。

    关于这个问题的另一次讨论结束了 inconclusive result 在问题上是否喜欢一个单一的演员,而不是一个要求,并提出 routing 作为第三种选择,因为路由器也充当负载平衡器,所以触摸 back-pressure 主题。

    这种方法经常与 AbstractFSM 不过,它的变种是一个单一的FSM参与者,缓冲了 利用 whenUnhandled 方法在默认情况下累加它们,无论当前状态是什么(例如,Akka in Action,chapter) "Finite State Machines and Agents" 或者光弯 buncher example ). 我不能用证据来支持这个说法,但看起来 AbstractFSM更多地被认为是对处理多个请求的参与者的状态进行建模,而不是对经过多个阶段的请求进行建模 . 与行动计划有关,那意味着 ProcessingActor 它本身可以扩展 抽象有限状态机 .

    public class ProcessingActor extends AbstractFSM<sample.so.State, RequestQueue> {
    {
        startWith(Idle, new RequestQueue());
    
        when(Idle, /* matchEvent(EventType, DataType, Action) */
                matchEvent(
                        Request.class,
                        RequestQueue.class,
                        (request, queue) -> goTo(Processing).using(queue.push(request)));
        /* more state-matchers */
    
        whenUnhandled(
                matchEvent(
                        Request.class,
                        RequestQueue.class,
                        (request, qeue) -> stay().using(qeue.push(request)));
    
        initialize();
    }
    

    对于“请求”部分,这里的数据库写入不再由状态表示,而是由状态进入和退出操作表示。请注意,所有 未处理时 分支不会出现在图中,因为它与状态更改无关。

    single actor FSM

    不必过多地权衡(模糊的)需求和所选择的实现, 抽象有限状态机 将每个请求的状态序列记录到数据库似乎是一个相当笨拙的机器。Akka的2.4版本的文档提供了一个状态机 without 使用AbstractFsm讨论了区分第一个事件和状态的可能性。在 抽象有限状态机 -DSL您必须在事件(和数据)之前识别状态。甚至可以说,有理由放弃阿克卡FSM altogether .

    一种更轻量级的方法来构建FSM become/unbecome ,一个很好的演示是 here ,安 抽象有限状态机 与变得/不相称的讨论可以找到 here . 更接近业务规则是前者的主要论点。

    进入了比较滑的地带,判断使用抽象有限状态机在had执行任务。我认为,有些事情可以说,鉴于阅读的要求是大致可以的。

    这些状态形成一个线性链,因此这两个“每个请求的抽象FSM”可以被其他每个请求结构所取代:

    • 一个单一的演员链,每个人代表一个国家

    chain of actors

    • 一个参与者,向自身发送事件,上面显示的每个步骤一个事件类型,在每个点向数据库编写器发送消息。也许枚举也足够了。

    考虑到这一点,这些版本的吸引力可能会增加:由于给定的实现在每个请求中使用(至少)一个FSM,因此问题就出现了,如何进行转换 QUEUED->PROCESSING 发生(或 discovery processing -> discovery done 那又怎么样 QUEUED 与技术水平有关。项目从不在队列中,总是在独占参与者中(另一方面,队列状态在 single-FSM 实际上使用队列的方法,但是 状态不适用于参与者,但适用于参与者处理的项 ). 不明显,这 external event 应该会导致这种转变。Akka有限状态机是用来描述确定性的 FSM (另见 this ,以相反的理由给出相同的论点),但如果此转换不是由外部事件触发的,则FSM必须 nondeterministic 触发它自己的 epsilon-transitions ~转换不是由任何输入引起的。一个相当复杂的结构,可能是这样实现的:

    onTransition(
        matchState(Initial, Queued, () -> {                    
            getSelf().tell(new Epsilon(), getSelf());
        }));