use of io.seata.saga.statelang.domain.State in project seata by seata.
the class StateInstruction method getState.
public State getState(ProcessContext context) {
if (getTemporaryState() != null) {
return temporaryState;
}
String stateName = getStateName();
String stateMachineName = getStateMachineName();
String tenantId = getTenantId();
if (StringUtils.isEmpty(stateMachineName)) {
throw new EngineExecutionException("StateMachineName is required", FrameworkErrorCode.ParameterRequired);
}
StateMachineConfig stateMachineConfig = (StateMachineConfig) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONFIG);
StateMachine stateMachine = stateMachineConfig.getStateMachineRepository().getStateMachine(stateMachineName, tenantId);
if (stateMachine == null) {
throw new EngineExecutionException("StateMachine[" + stateMachineName + "] is not exist", FrameworkErrorCode.ObjectNotExists);
}
if (StringUtils.isEmpty(stateName)) {
stateName = stateMachine.getStartState();
setStateName(stateName);
}
State state = stateMachine.getStates().get(stateName);
if (state == null) {
throw new EngineExecutionException("State[" + stateName + "] is not exist", FrameworkErrorCode.ObjectNotExists);
}
return state;
}
use of io.seata.saga.statelang.domain.State in project seata by seata.
the class CompensationHolder method findStateInstListToBeCompensated.
public static List<StateInstance> findStateInstListToBeCompensated(ProcessContext context, List<StateInstance> stateInstanceList) {
List<StateInstance> stateListToBeCompensated = null;
if (CollectionUtils.isNotEmpty(stateInstanceList)) {
stateListToBeCompensated = new ArrayList<>(stateInstanceList.size());
StateMachine stateMachine = (StateMachine) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE);
StateMachineInstance stateMachineInstance = (StateMachineInstance) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_INST);
for (StateInstance stateInstance : stateInstanceList) {
if (stateNeedToCompensate(stateInstance)) {
State state = stateMachine.getState(EngineUtils.getOriginStateName(stateInstance));
AbstractTaskState taskState = null;
if (state instanceof AbstractTaskState) {
taskState = (AbstractTaskState) state;
}
// The state machine needs to exit directly without compensation.
if (stateInstance.isForUpdate() && taskState != null && StringUtils.isBlank(taskState.getCompensateState())) {
String message = "StateMachineInstance[" + stateMachineInstance.getId() + ":" + stateMachine.getName() + "] have a state [" + stateInstance.getName() + "] is a service for update data, but no compensateState found.";
EngineExecutionException exception = ExceptionUtils.createEngineExecutionException(FrameworkErrorCode.CompensationStateNotFound, message, stateMachineInstance, stateInstance);
EngineUtils.failStateMachine(context, exception);
throw exception;
}
if (taskState != null && StringUtils.isNotBlank(taskState.getCompensateState())) {
stateListToBeCompensated.add(stateInstance);
}
}
}
}
return stateListToBeCompensated;
}
use of io.seata.saga.statelang.domain.State in project seata by seata.
the class TaskStateRouter method route.
@Override
public Instruction route(ProcessContext context, State state) throws EngineExecutionException {
StateInstruction stateInstruction = context.getInstruction(StateInstruction.class);
if (stateInstruction.isEnd()) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("StateInstruction is ended, Stop the StateMachine executing. StateMachine[{}] Current State[{}]", stateInstruction.getStateMachineName(), state.getName());
}
return null;
}
// check if in loop async condition
if (Boolean.TRUE.equals(context.getVariable(DomainConstants.VAR_NAME_IS_LOOP_STATE))) {
return null;
}
// The current CompensationTriggerState can mark the compensation process is started and perform compensation
// route processing.
State compensationTriggerState = (State) context.getVariable(DomainConstants.VAR_NAME_CURRENT_COMPEN_TRIGGER_STATE);
if (compensationTriggerState != null) {
return compensateRoute(context, compensationTriggerState);
}
// There is an exception route, indicating that an exception is thrown, and the exception route is prioritized.
String next = (String) context.getVariable(DomainConstants.VAR_NAME_CURRENT_EXCEPTION_ROUTE);
if (StringUtils.hasLength(next)) {
context.removeVariable(DomainConstants.VAR_NAME_CURRENT_EXCEPTION_ROUTE);
} else {
next = state.getNext();
}
// If next is empty, the state selected by the Choice state was taken.
if (!StringUtils.hasLength(next) && context.hasVariable(DomainConstants.VAR_NAME_CURRENT_CHOICE)) {
next = (String) context.getVariable(DomainConstants.VAR_NAME_CURRENT_CHOICE);
context.removeVariable(DomainConstants.VAR_NAME_CURRENT_CHOICE);
}
if (!StringUtils.hasLength(next)) {
return null;
}
StateMachine stateMachine = state.getStateMachine();
State nextState = stateMachine.getState(next);
if (nextState == null) {
throw new EngineExecutionException("Next state[" + next + "] is not exits", FrameworkErrorCode.ObjectNotExists);
}
stateInstruction.setStateName(next);
if (null != LoopTaskUtils.getLoopConfig(context, nextState)) {
stateInstruction.setTemporaryState(new LoopStartStateImpl());
}
return stateInstruction;
}
use of io.seata.saga.statelang.domain.State in project seata by seata.
the class TaskStateRouter method compensateRoute.
private Instruction compensateRoute(ProcessContext context, State compensationTriggerState) {
// and the compensation process is interrupted.
if (Boolean.TRUE.equals(context.getVariable(DomainConstants.VAR_NAME_FIRST_COMPENSATION_STATE_STARTED))) {
Exception exception = (Exception) context.getVariable(DomainConstants.VAR_NAME_CURRENT_EXCEPTION);
if (exception != null) {
EngineUtils.endStateMachine(context);
return null;
}
StateInstance stateInstance = (StateInstance) context.getVariable(DomainConstants.VAR_NAME_STATE_INST);
if (stateInstance != null && (!ExecutionStatus.SU.equals(stateInstance.getStatus()))) {
EngineUtils.endStateMachine(context);
return null;
}
}
Stack<StateInstance> stateStackToBeCompensated = CompensationHolder.getCurrent(context, true).getStateStackNeedCompensation();
if (!stateStackToBeCompensated.isEmpty()) {
StateInstance stateToBeCompensated = stateStackToBeCompensated.pop();
StateMachine stateMachine = (StateMachine) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE);
State state = stateMachine.getState(EngineUtils.getOriginStateName(stateToBeCompensated));
if (state != null && state instanceof AbstractTaskState) {
AbstractTaskState taskState = (AbstractTaskState) state;
StateInstruction instruction = context.getInstruction(StateInstruction.class);
State compensateState = null;
String compensateStateName = taskState.getCompensateState();
if (StringUtils.hasLength(compensateStateName)) {
compensateState = stateMachine.getState(compensateStateName);
}
if (compensateState == null && (taskState instanceof SubStateMachine)) {
compensateState = ((SubStateMachine) taskState).getCompensateStateObject();
instruction.setTemporaryState(compensateState);
}
if (compensateState == null) {
EngineUtils.endStateMachine(context);
return null;
}
instruction.setStateName(compensateState.getName());
CompensationHolder.getCurrent(context, true).addToBeCompensatedState(compensateState.getName(), stateToBeCompensated);
((HierarchicalProcessContext) context).setVariableLocally(DomainConstants.VAR_NAME_FIRST_COMPENSATION_STATE_STARTED, true);
if (compensateState instanceof CompensateSubStateMachineState) {
((HierarchicalProcessContext) context).setVariableLocally(compensateState.getName() + DomainConstants.VAR_NAME_SUB_MACHINE_PARENT_ID, EngineUtils.generateParentId(stateToBeCompensated));
}
return instruction;
}
}
context.removeVariable(DomainConstants.VAR_NAME_CURRENT_COMPEN_TRIGGER_STATE);
String compensationTriggerStateNext = compensationTriggerState.getNext();
if (StringUtils.isEmpty(compensationTriggerStateNext)) {
EngineUtils.endStateMachine(context);
return null;
}
StateInstruction instruction = context.getInstruction(StateInstruction.class);
instruction.setStateName(compensationTriggerStateNext);
return instruction;
}
use of io.seata.saga.statelang.domain.State in project seata by seata.
the class StateMachineParserImpl method parse.
@Override
public StateMachine parse(String json) {
JsonParser jsonParser = JsonParserFactory.getJsonParser(jsonParserName);
if (jsonParser == null) {
throw new RuntimeException("Cannot find JsonParer by name: " + jsonParserName);
}
Map<String, Object> node = jsonParser.parse(json, Map.class, true);
if (DesignerJsonTransformer.isDesignerJson(node)) {
node = DesignerJsonTransformer.toStandardJson(node);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("===== Transformed standard state language:\n{}", jsonParser.toJsonString(node, true));
}
}
StateMachineImpl stateMachine = new StateMachineImpl();
stateMachine.setName((String) node.get("Name"));
stateMachine.setComment((String) node.get("Comment"));
stateMachine.setVersion((String) node.get("Version"));
stateMachine.setStartState((String) node.get("StartState"));
String recoverStrategy = (String) node.get("RecoverStrategy");
if (StringUtils.isNotBlank(recoverStrategy)) {
stateMachine.setRecoverStrategy(RecoverStrategy.valueOf(recoverStrategy));
}
Object isPersist = node.get("IsPersist");
if (Boolean.FALSE.equals(isPersist)) {
stateMachine.setPersist(false);
}
// customize if update origin or append new retryStateInstLog
Object isRetryPersistModeUpdate = node.get("IsRetryPersistModeUpdate");
if (isRetryPersistModeUpdate instanceof Boolean) {
stateMachine.setRetryPersistModeUpdate(Boolean.TRUE.equals(isRetryPersistModeUpdate));
}
// customize if update last or append new compensateStateInstLog
Object isCompensatePersistModeUpdate = node.get("IsCompensatePersistModeUpdate");
if (isCompensatePersistModeUpdate instanceof Boolean) {
stateMachine.setCompensatePersistModeUpdate(Boolean.TRUE.equals(isCompensatePersistModeUpdate));
}
Map<String, Object> statesNode = (Map<String, Object>) node.get("States");
statesNode.forEach((stateName, value) -> {
Map<String, Object> stateNode = (Map<String, Object>) value;
String stateType = (String) stateNode.get("Type");
StateParser<?> stateParser = StateParserFactory.getStateParser(stateType);
if (stateParser == null) {
throw new IllegalArgumentException("State Type [" + stateType + "] is not support");
}
State state = stateParser.parse(stateNode);
if (state instanceof BaseState) {
((BaseState) state).setName(stateName);
}
if (stateMachine.getState(stateName) != null) {
throw new IllegalArgumentException("State[name:" + stateName + "] is already exists");
}
stateMachine.putState(stateName, state);
});
Map<String, State> stateMap = stateMachine.getStates();
for (State state : stateMap.values()) {
if (state instanceof AbstractTaskState) {
AbstractTaskState taskState = (AbstractTaskState) state;
if (StringUtils.isNotBlank(taskState.getCompensateState())) {
taskState.setForUpdate(true);
State compState = stateMap.get(taskState.getCompensateState());
if (compState instanceof AbstractTaskState) {
((AbstractTaskState) compState).setForCompensation(true);
}
}
}
}
return stateMachine;
}
Aggregations