有关状态机的总结及思考

有关状态机的总结及思考

Tags
State Machine
Published
June 21, 2020
Author
Joybean

概念

State

  • Pseudo States
    • Initial
    • End
    • Choice
    • Junction
    • History
    • Fork
    • Join

Event

  • Normal event
  • Timer event

Transition

  • Internal Transition
  • External Transitions
  • Local Transitions

Action

  • State Entry Action
  • State Action
  • State Exit Action
  • Transition Action

Guard

  • if else
  • enable/disable action/transition

公式

Current State +  Event + Action= Another State
notion image

状态机框架

Spring StateMachine

  • 核心用法
/** * Send an event {@code E} wrapped with a {@link Message} to the region. * * @param event the wrapped event to send * @return true if event was accepted */ boolean sendEvent(Message event);
  • 优点
    • 高级功能:支持嵌套状态、延迟事件、并行控制、条件分支等高级功能
    • 扩展性:拦截器、监听器等扩展点
    • 文档、社区完善
  • 缺点
    • 状态机实例的构造比较重,需要依赖上下文(维护了当前状态、接受的事件列表、变量等)

Squirrel

  • 核心用法
/** * Fires the specified event * @param event the event * @param context external context */ void fire(E event, C context); /** * Fires event with context immediately, if current state machine is busy, the next processing event * is this event. * @param event the event * @param context external context */ void fireImmediate(E event, C context);
  • 优点
    • 轻量级:定义状态机和创建状态机实例开销小,可以灵活设置状态机实例的初始状态,实例随用随new
    • 支持嵌套状态、并行状态、条件分支等高级功能
    • 扩展性:监听器、post processor等扩展点
  • 缺点
  • 一些伪状态不支持更新维护不是很频繁,近几年release版本发布少

COLA StateMachine

  • 核心用法
/** * Send an event {@code E} to the state machine. * * @param sourceState the source state * @param event the event to send * @param ctx the user defined context * @return the target state */ S fireEvent(S sourceState, E event, C ctx);
  • 优点
    • 状态机的无状态设计,状态机实例中没有维护当前状态,多线程安全
    • 更轻量级,性能更好
  • 缺点
    • 无法从状态机实例中获取当前状态
    • 当前发送事件可能要依赖上一次发送事件返回的当前状态机实例状态,会存在一些额外状态判断的逻辑
    • 扩展点较少
    • 大部分高级功能不支持

SSM实现解读

状态机内部变量

  • current state
  • states
  • transitions
  • event queue:被状态机接受的事件队列
  • deferred event queue:需要延迟处理的事件队列
  • trigger queue:触发器事件队列

事件处理

notion image

状态转换

notion image

一些思考

1. 业务状态的流转被收口在状态机中,只需要给状态机输入特定事件和业务数据,然后关注在某个状态处理做哪些处理即可。 2. 有时候需要抽象出父子状态,父子状态职责要划分清楚,方便在父状态和子状态分别做某些逻辑处理。 3. 若使用轻量级状态机的实现方式,可以不持久化状态机上下文,利用已有的数据库中的业务数据初始化状态机实例。 4. 若依赖的事件是外部系统事件,可能存在各种不确定性因素,为了系统容错性考虑,可能需要关注以下几点:
  • 考虑增加一个事件处理表,接收到外部系统事件时就新增一条事件记录,初始状态为未处理状态,相关业务逻辑处理完成再更新该事件的状态为成功/失败状态。
  • 处理事件时,查询当前最新的处理成功的事件构造状态机实例的当前状态,然后交由状态机处理该事件,若事件在不合适的时机到来则忽略处理。
  • 考虑到某些场景下接收到外部系统事件是乱序的,处理某个事件时先从数据库捞出未处理成功的并且需要在该事件之前处理的事件进行回放。