【问题标题】:How to represent that an Akka actor is in a long running operation using FSM-s如何使用 FSM-s 表示 Akka actor 正在进行长时间运行的操作
【发布时间】:2013-10-06 05:45:20
【问题描述】:

使用 FSM 描述的我的演员正在等待触发器(处于空闲状态)。当它得到它时,它开始处理一些数据(并进入运行状态),当它完成后它又回到空闲状态。

如果我正确理解 FSM 模型,从这个角度来看,有两个事件: 处理开始(空闲->运行)和处理完成(运行->空闲)。

但从演员的角度来看,只有一条消息。

一种可能性是将处理本身委托给另一个参与者。所以我可以转发触发事件并进入运行状态,然后在得到结果时进入空闲状态。 它的优点是 FSM 本身可以快速响应请求(例如询问当前状态是什么),但它使设计更加复杂。

还有一个是在actor完成处理后向self发送一条完成的消息,这会触发Running -> Idle的过渡,但是对我来说看起来有点奇怪。

我还有什么其他选择?

注意:还有其他几个具有各种转换的状态,所以我想坚持 FSM 模型。

【问题讨论】:

    标签: scala akka fsm state-machine


    【解决方案1】:

    由于您似乎有一个演员需要进行处理并转换到 FSM,我建议您遵循以下准则(一些基本代码大纲遵循此列表):

    • 参与者 A 收到将触发某些处理的相关消息
    • Actor A 将一个单独的 FSM Actor,比如 F,(akka.actor.FSM) 转换到适当的状态。 Actor A 在启动时会生成特定的 FSM 以跟踪相应上下文的状态(例如,所有事务或每个事务的状态或其他一些上下文)。下面的代码大纲使用所有正在处理或已完成的事务作为示例的上下文,但可能需要更改。
    • 然后参与者 A 触发应该为消息触发的任何处理。请记住,演员通常不应该阻止,但这里有一个答案,它提供了更多关于 when an Akka actor may block 的指导。
    • 替代方案:如果您可以在不阻塞的情况下触发长时间运行的处理,并确保您在对方处理阶段后接收到必要的事件,那么您可以消除前面的 Actor A 而只拥有 FSM Actor F。你应该看看@在这种情况下为 987654328@。

    所以我的代码大纲建议是基于我从问题中理解的:

    /* Events */
    sealed trait MyEvents
    case class ProcessingStarted(txnId: Long) extends MyEvents
    case class ProcessingFinished(txnId: Long, result: Result) extends MyEvents
    
    /* Valid states for your FSM */
    sealed trait MyStates 
    case object Idle extends MyStates
    /* Constructor arguments could be anything, I randomly chose a Long for a transaction ID which may be specific to a job */
    case object Processing extends MyStates
    /* define more case classes or objects depending on the rest of the states */
    
    /* Valid internal state data types for FSM */
    sealed trait MyDataTypes
    case object Uninitialized extends MyDataTypes
    case class StateData(processingIds: Seq[Long], resultMap: Map[Long, Result]) extends MyDataTypes
    
    import akka.actor.{ Actor, ActorRef, FSM }
    import scala.concurrent.duration._
    
     class ActorF extends FSM[MyStates, MyDataTypes] {
       startWith(Idle, Uninitialized)
    
       when(Idle) {
         case Event(ProcessingStarted(txnId), Uninitialized) =>
           goto(Processing) using StateData(Seq(txnId), Map.empty[Long, Result])
         case Event(ProcessingStarted(txnId), StateData(emptyIds, resultMap)) =>
           goto(Processing) using StateData(Seq(txnId), resultMap)
       }
    
       when(Processing) {
         case Event(ProcessingFinished(txnId, result), StateData(processingIds, resultMap)) => {
           val remainingIds = processingIds diff Seq(txnId)
           val newResultMap = resultMap + (txnId -> result)
           if (remainingIds.isEmpty) {
             goto(Idle) using StateData(remainingIds, newResultMap)
           } else {
             stay using StateData(remainingIds, newResultMap)
           }
         }
       }
    
       initialize()
     }
    
     // inside Actor A do something like this for creating the FSM actor (just like other actors)
     val f = system.actorOf(Props(classOf[ActorF], this))
    
     // send an event message to it just like other types of actors
     f ! ProcessingStarted(txnId)
    

    如果您选择触发对代码其他部分的非阻塞处理请求,您可以根据需要使用onTransition 添加触发代码。您可能还希望将 MyEvents 案例类更新为不同的时态。上面使用的事件命名是为了表明其他东西负责触发它(例如,演员 A 收到了做一些事情的初始消息)。

    还要注意Supervision capabilities of Akka,这里可以使用它来监督相关演员。

    有关更多详细信息,请阅读以下内容,这可能有助于进一步构建 FSM、对其进行测试、使用非阻塞方法在外部触发长时间运行的处理。所有这些都可能对您的需求有用:

    【讨论】:

    • 感谢您的详细回答。它似乎与我描述为第一个替代解决方案的当前解决方案非常相似。在这种情况下,FSM 创建了“worker”(它的存在仅用于处理此请求,并按照链接页面上的建议使用单独的调度程序),并且 FSM 控制其生命周期。与此相比,您的解决方案(FSM 是受控参与者)有什么优势吗?
    • 在我看来,我提出的解决方案中的前端参与者可以更粗粒度,并且可以非常轻松地管理更细粒度的 FSM 的生命周期。例如接收外部消息的前端参与者可能会接受系统级消息,但管理每个用户或订单的单个 FSM(更细粒度的上下文)。我在我的解决方案中提出的替代方案是您的替代方案:产生/管理非阻塞处理部分(可能是演员或不是演员)的 FSM 演员。您选择的解决方案取决于您的需求,问题中没有明确说明。 HTH。
    • 上述解决方案的重要部分是考虑事项列表,并链接到有关演员何时可以阻止的其他答案。这些只是您可以自己回答的问题,这些问题在您的原始问题中没有明确说明。代码大纲就是这样。我在不知道您需要在 Akka 中演示 FSM 的情况下提出了一个解决方案,但如上所述,可能需要进行一些调整以适应您理解的实际需求。
    猜你喜欢
    • 2018-07-31
    • 2016-02-15
    • 2011-01-05
    • 2023-03-17
    • 1970-01-01
    • 2015-10-23
    • 1970-01-01
    • 1970-01-01
    • 2015-09-09
    相关资源
    最近更新 更多