2017-07-27 137 views
0

我需要一些關於在長時間運行進程中使用彈簧狀態機的建議。我想設計一些流程。假設我有下幾個狀態:開始 - >步驟1 - >步驟2 - >步驟3 - >完成。我有一個控制器可以發送事件給狀態機來管理狀態之間的轉換。我有一臺StateMachinePersister。我有一個從StateMachineContext轉換爲byte []的轉換器。聽起來對我的業務目標有好處。所以一切都應該正常工作。彈簧狀態機 - 管理長時間運行的進程

但我有問題嗎?當我決定改變流程時,我無法理解如何管理案例。我的意思是,如果我有一個生產環境,其中一些進程在「步驟2」狀態下持續存在。但我被迫改變流程。假設我想添加一個步驟或刪除流程中的一個步驟。我認爲在狀態機反序列化過程中我會遇到問題。

所以問題是:可能是彈簧狀態機不適合我,或者有一些食譜我怎麼能管理這種情況?


我有我想要管理的狀態,轉換等

@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豆負責初始化stateMachineContext特定過程的實體。

@Bean 公共StateMachinePersist>堅持(){ 返回新StateMachinePersist>(){

@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負責序列化/ deseriali 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(); 
     } 
    } 
} 

回答

0

顯然,你不能修改現有的跑步機,但因爲你已經與持久性的工作我想你至少停機。

statemachine-examples-datajpa它正在使用現有的機器apis將配置存儲在數據庫中。我們有StateMachineModelFactory,如果任何內置的實現不適合你,它幾乎可以讓你在任何地方存儲你的東西。每次發送新事件時,此示例都會構建新的機器實例。即,您可以使用內置編輯器轉到數據庫並添加新的轉換,而無需重新啓動主要的java進程。

這給你一些靈活性,但如果你需要改變你的運行代碼,那麼事情將不可能。

+0

感謝您的回覆。我想添加一些我的實現細節。再問一次。 我再次閱讀過文檔,並瞭解到每次從工廠創建狀態機都不是很好的方法。 所以我想返工的第一件事就是DefaultStateMachineAdapter。從池中檢索狀態機並將其重置爲特定狀態會更好。正確? –

+0

第二件事,在實例化狀態機時對我來說比開銷更重要的是狀態和轉換的未來變化。 我們假設我想用下一個狀態和事件來管理進程:step1 - event1 - > step2 - event2 - > step3。 我的要求是我的應用程序的每個用戶都可以運行多個進程。例如user1請求我的控制器並運行process1到狀態2。 –

+0

我們假設當state2被激活時,應用程序運行一些長時間運行的任務。當這個任務完成後,應用程序應該將state2更改爲state3。 我們假設在這一刻我們想改變流程定義。我的意思是我應該返工step1 - event1 - step2 - > event2 - > step3 on step1 - event1 - > step2 - > event2 - > newstep-newevent-> step3 因此,重新部署我的應用程序I想要恢復我的狀態並通過新的定義。 正如我前面提到的,我在這裏失敗了。 –

相關問題