I have defined the SM like below in my codebase wherein OperationState Enum depicts the state for the StateMachine and the same property is part of the one of the hibernate Entity [OpInfo.java]
Basically I have below 2 questions:
1.As per my requirement, I need to persist the operation state to OpInfo table whenever there is a state change. Currently, I have configured the entry action i.e. updateOperationState() for each of the state but that looks very naive approach. I hope there must be some interface/functionality provided by StateMachine TPL which will do this persistence in much cleaner way or there should be some way to define common entryaction for each state.
2.During high concurrency, what I have observed is, the call to entryAction i.e. updateOperationState() is being missed by StateMachine. I would like to understand the root cause for the same and would like to know if there are any configuration exposed by SM to tune in regards of this problem.
StateMachineBuilder.Builder<OperationState, OperationEvent> builder = StateMachineBuilder.builder();
builder.configureStates().withStates()
.states(EnumSet.allOf(OperationState.class))
.initial(genericOp.getOpState())
.state(CREATED, updateOperationState(), null)
.state(IDLE, updateOperationState(), null)
.state(APPLYING, updateOperationState(), null)
.state(APPLIED, updateOperationState(),null);
builder.configureTransitions().withExternal()
.source(CREATED).target(APPLYING).event(TRIGGER)
.and().withExternal()
.source(CREATED).target(IDLE).event(SCHEDULE)
.and().withExternal()
.source(IDLE).target(APPLYING).event(TRIGGER)
.and().withExternal()
.source(APPLYING).target(APPLIED).event(SUCCESS)
.and().withExternal();
@Bean
private static Action<OperationState, OperationEvent> updateOperationState() {
return context -> {
OperationState tgtOpState = context.getStateMachine().getState().getId();
if (context.getMessage() == null) {
return;
}
opInfoRepository.updateOpState(opId, tgtOpState);
log.debug("Updating the operation [{}] state to [{}]", opId, tgtOpState);
};
}
@Entity
@Builder
public class OpInfo {
@Id
@ToString.Include
private String id;
@Enumerated(EnumType.STRING)
@ToString.Include
private OperationType operationType;
@Enumerated(EnumType.STRING)
OperationState operationState = OperationState.CREATED;
}
Use can take advantage of the
StateMachineListenerinterface and implement a callback onstateEnteredortransitionEndedphase to save the current state of your state machine in databaseSee more here in Spring documentation