Akka有限状态机实例

时间:2018-06-04 13:14:05

标签: java scala akka state-machine

我正在尝试利用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在从其中一个角色发现B时初始化了FSM。

我是否初始化并将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的构造函数中?但在这种情况下,每个应用程序(数据)不会有一个状态机。

1 个答案:

答案 0 :(得分:1)

尽管在OP中对状态和过渡的描述相当含糊,但是可以解决所选实现的状态,其含义以及替代方案的含义。

手头的实现可以算作“每个请求的执行者”方法,与之相比,状态机执行者可以缓冲并处理多个请求,而这种发现更为常见。它将在下面进一步介绍。

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

actor per request FSM

“每个请求的执行者”最初似乎出现在this discussion中,这给this blog带来了加薪,后来甚至偶尔获得了a pattern的称号。似乎部分是由于复制Spray framework的功能之一而产生的,{@ 3}是Akka http的前身。

关于SO的另一讨论是关于inconclusive result的问题,即每个请求是否偏向于单个参与者,并提出了routing作为第三种选择,因为路由器还充当负载均衡器,触摸back-pressure主题。

不过,与AbstractFSM及其变体结合使用的方法更为常见,它是单个FSM参与者,它可以缓冲 无论当前状态如何,默认情况下,使用whenUnhandled方法的传入消息都会累积它们(例如Akka in Action,第"Finite State Machines and Agents"章或Lightbend buncher example)。我无法使用参考来备份该主张,但看起来 AbstractFSM更被认为是对处理多个请求的参与者的状态进行建模,而不是对经历多个阶段的请求进行建模。 与OP相关,该方法意味着ProcessingActor 本身可以扩展AbstractFSM

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();
}

在“请求”部分到达类似这样的内容,在该部分中,数据库写操作不再由状态表示,而不再由状态进入和退出动作表示。请注意,所有whenUnhandled分支都不会出现在图中,因为它与状态更改无关。

single actor FSM

AbstractFSM无需过多权衡所选实现的(模糊)需求,似乎是一个笨拙的机制,可将每个请求的状态序列记录到数据库中。 Akka 2.4版本的文档介绍了一个使用AbstractFsm的状态机without,并讨论了区分第一个事件然后区分状态或相反状态的可能性。在AbstractFSM-DSL中,您必须先识别事件(和数据)之前的状态。甚至可以出于某些理由而对Akka FSM altogether投弃权票。

构建become/unbecome的更轻巧的方法是使用herehere是一个很好的演示,chain of actors中有AbstractFSM与变得/变得不受欢迎的讨论。从视觉上更接近业务规则为前者提供了主要依据。

进入一个更加湿滑的领域,以判断对had的任务使用AbstractFSM。我认为,鉴于阅读要求大约还可以,所以可以说些什么。

状态形成一条线性链,因此两个“每个请求的AbstractFSM”可以用其他每个请求的结构代替:

  • 单个参与者链,每个参与者代表一个州

single-FSM

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

考虑到以下因素,这些版本的吸引力可能会增加:由于给定实现每个请求至少使用一个FSM,因此出现了一个问题,即过渡QUEUED->PROCESSING是如何实现的(或discovery processing -> discovery done事项),以及QUEUED与技术水平有关的内容。项目从不在队列中,而总是在独占参与者中(另一方面,在实际上使用队列的external event方法中,排队状态会更加明显,但是该状态不适用于演员,但演员要处理的项目)。哪个FSM会导致该过渡并不明显。 Akka FSM旨在描述确定性this(另请参见nondeterministic,出于相反的原因也给出相同的论点),但是如果此转换不是由外部事件触发的,则FSM必须变为{{3 }}并触发自己的epsilon-transitions〜过渡,该过渡不是由任何输入引起的。一个相当复杂的结构,可能是这样实现的:

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