弹簧状态机 - 管理长时间运行的进程

时间:2017-07-27 12:21:25

标签: java spring spring-statemachine

我需要一些使用弹簧状态机进行长时间运行的建议。我想设计一些流程。让我们说我有下一个状态:开始 - >步骤1 - >步骤2 - >步骤3 - >结束。我有一个控制器,可以发送事件到状态机来管理状态之间的转换。我有一个StateMachinePersister。我有一个从StateMachineContext到byte []的转换器。听起来对我的业务目标很有帮助。所以一切都应该正常。

但我有问题吗?当我决定改变流程时,我无法理解如何管理案例。我的意思是,如果我有一个生产环境,其中某些流程持续存在于" step2"州。但我被迫改变流程。假设我想添加一个步骤或删除流程中的一个步骤。我想在状态机反序列化期间我会遇到问题。

所以问题是:可能春天状态机不适合我,或者有一些食谱如何管理这种情况?

我有一个实体,我想管理状态,过渡等。

@Entity
@Access(AccessType.FIELD)
@Table(name = "processes", indexes = @Index(columnList = "currentState"))
public class Process extends AbstractPersistable<Long> implements ContextEntity<ProcessState, ProcessEvent, Long> { // NOSONAR

    private static final long serialVersionUID = 8848887579564649636L;

    @JsonIgnore
    StateMachineContext<ProcessState, ProcessEvent> stateMachineContext; // NOSONAR

    @Enumerated(EnumType.STRING)
    ProcessState currentState;


    @Override
    public void setStateMachineContext(StateMachineContext<ProcessState, ProcessEvent> stateMachineContext) {
        if (stateMachineContext == null) {
            throw new IllegalStateException("stateMachineContext can't be null");
        }
        this.currentState = stateMachineContext.getState();
        this.stateMachineContext = stateMachineContext;
    }


    @Override
    public StateMachineContext<ProcessState, ProcessEvent> getStateMachineContext() {
        return stateMachineContext;
    }

...
}

我有StateMachinePersist bean,它负责为特定进程初始化stateMachineContext。

@Bean public StateMachinePersist&gt; persist(){     返回新的StateMachinePersist&gt;(){

    @Override
    public StateMachineContext<ProcessState, ProcessEvent> read(
            ContextEntity<ProcessState, ProcessEvent, Serializable> process) throws Exception {
        return process.getStateMachineContext();
    }

    @Override
    public void write(StateMachineContext<ProcessState, ProcessEvent> context,
            ContextEntity<ProcessState, ProcessEvent, Serializable> process) throws Exception {
        process.setStateMachineContext(context);
    }
};

}

我有StateMachineAdapter,它负责持久化和恢复状态机

public class DefaultStateMachineAdapter<S, E, T> {

    final StateMachineFactory<S, E> stateMachineFactory;

    final StateMachinePersister<S, E, T> persister;

    public DefaultStateMachineAdapter(StateMachineFactory<S, E> stateMachineFactory, StateMachinePersister<S, E, T> persister) {
        this.stateMachineFactory = stateMachineFactory;
        this.persister = persister;
    }

    public StateMachine<S, E> restore(T contextObject) throws Exception {
        StateMachine<S, E> stateMachine = stateMachineFactory.getStateMachine();
        return persister.restore(stateMachine, contextObject);
    }

    public void persist(StateMachine<S, E> stateMachine, T order) throws Exception {
        persister.persist(stateMachine, order);
    }

    public StateMachine<S, E> create() {
        StateMachine<S, E> stateMachine = stateMachineFactory.getStateMachine();
        stateMachine.start();
        return stateMachine;
    }

}

我有StateMachineContextConverter,它负责StateMachineContext的序列化/反序列化。我使用Kryo进行这项操作。

public class StateMachineContextConverter implements AttributeConverter<StateMachineContext, byte[]> {

    @Override
    public byte[] convertToDatabaseColumn(StateMachineContext attribute) {
        return serialize(attribute);
    }

    @Override
    public StateMachineContext convertToEntityAttribute(byte[] dbData) {
        return deserialize(dbData);
    }


}

我有控制器负责切换状态

public class ProcessEventController {


    final DefaultStateMachineAdapter<ProcessState, ProcessEvent, ContextEntity<ProcessState, ProcessEvent, ? extends Serializable>> processStateMachineAdapter;

    public ProcessEventController(DefaultStateMachineAdapter<ProcessState, ProcessEvent, ContextEntity<ProcessState, ProcessEvent, ? extends Serializable>> processStateMachineAdapter) {
        this.processStateMachineAdapter = processStateMachineAdapter;
    }

    @RequestMapping(path = "/processes/{id}/{event}", method = RequestMethod.POST)
    @Transactional
    public HttpEntity<Void> receiveEvent(@PathVariable("id") Process process, @PathVariable("event") ProcessEvent event) throws Exception {
        StateMachine<ProcessState, ProcessEvent> stateMachine = processStateMachineAdapter.restore(process);
        if (stateMachine.sendEvent(event)) {
            processStateMachineAdapter.persist(stateMachine, process);
            return ResponseEntity.accepted().build();
        } else {
            return ResponseEntity.unprocessableEntity().build();
        }
    }
}

1 个答案:

答案 0 :(得分:0)

显然,您无法修改现有的正在运行的计算机,但由于您已经在使用持久性,我假设您至少停止了计算机。

查看statemachine-examples-datajpa使用现有的机器apis将配置存储在数据库中。我们有StateMachineModelFactory,如果任何内置实现不适合你,它几乎允许你将你的东西存储在任何地方。每次发送新事件时,此示例都将构建新的机器实例。即,您可以使用内置编辑器访问数据库并添加新的转换,而无需重新启动主Java进程。

这为您提供了一些灵活性,但如果您需要更改正在运行的代码,则事情将无法实现。