use of io.seata.saga.engine.exception.ForwardInvalidException in project seata by seata.
the class LoopTaskUtils method isForSubStateMachineForward.
/**
* forward with subStateMachine should check each loop state's status
*
* @param context
* @return
*/
public static boolean isForSubStateMachineForward(ProcessContext context) {
StateMachineInstance stateMachineInstance = (StateMachineInstance) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_INST);
StateInstruction instruction = context.getInstruction(StateInstruction.class);
StateMachineConfig stateMachineConfig = (StateMachineConfig) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONFIG);
StateInstance lastRetriedStateInstance = LoopTaskUtils.findOutLastRetriedStateInstance(stateMachineInstance, LoopTaskUtils.generateLoopStateName(context, instruction.getStateName()));
if (null != lastRetriedStateInstance && DomainConstants.STATE_TYPE_SUB_STATE_MACHINE.equals(lastRetriedStateInstance.getType()) && !ExecutionStatus.SU.equals(lastRetriedStateInstance.getCompensationStatus())) {
while (StringUtils.isNotBlank(lastRetriedStateInstance.getStateIdRetriedFor())) {
lastRetriedStateInstance = stateMachineConfig.getStateLogStore().getStateInstance(lastRetriedStateInstance.getStateIdRetriedFor(), lastRetriedStateInstance.getMachineInstanceId());
}
List<StateMachineInstance> subInst = stateMachineConfig.getStateLogStore().queryStateMachineInstanceByParentId(EngineUtils.generateParentId(lastRetriedStateInstance));
if (CollectionUtils.isNotEmpty(subInst)) {
if (ExecutionStatus.SU.equals(subInst.get(0).getCompensationStatus())) {
return false;
}
}
if (ExecutionStatus.UN.equals(subInst.get(0).getCompensationStatus())) {
throw new ForwardInvalidException("Last forward execution state instance is SubStateMachine and compensation status is " + "[UN], Operation[forward] denied, stateInstanceId:" + lastRetriedStateInstance.getId(), FrameworkErrorCode.OperationDenied);
}
return true;
}
return false;
}
use of io.seata.saga.engine.exception.ForwardInvalidException in project seata by seata.
the class ProcessCtrlStateMachineEngine method findOutLastForwardStateInstance.
/**
* Find the last instance of the forward execution state
*
* @param stateInstanceList
* @return
*/
public StateInstance findOutLastForwardStateInstance(List<StateInstance> stateInstanceList) {
StateInstance lastForwardStateInstance = null;
for (int i = stateInstanceList.size() - 1; i >= 0; i--) {
StateInstance stateInstance = stateInstanceList.get(i);
if (!stateInstance.isForCompensation()) {
if (ExecutionStatus.SU.equals(stateInstance.getCompensationStatus())) {
continue;
}
if (DomainConstants.STATE_TYPE_SUB_STATE_MACHINE.equals(stateInstance.getType())) {
StateInstance finalState = stateInstance;
while (StringUtils.hasText(finalState.getStateIdRetriedFor())) {
finalState = stateMachineConfig.getStateLogStore().getStateInstance(finalState.getStateIdRetriedFor(), finalState.getMachineInstanceId());
}
List<StateMachineInstance> subInst = stateMachineConfig.getStateLogStore().queryStateMachineInstanceByParentId(EngineUtils.generateParentId(finalState));
if (CollectionUtils.isNotEmpty(subInst)) {
if (ExecutionStatus.SU.equals(subInst.get(0).getCompensationStatus())) {
continue;
}
if (ExecutionStatus.UN.equals(subInst.get(0).getCompensationStatus())) {
throw new ForwardInvalidException("Last forward execution state instance is SubStateMachine and compensation status is " + "[UN], Operation[forward] denied, stateInstanceId:" + stateInstance.getId(), FrameworkErrorCode.OperationDenied);
}
}
} else if (ExecutionStatus.UN.equals(stateInstance.getCompensationStatus())) {
throw new ForwardInvalidException("Last forward execution state instance compensation status is [UN], Operation[forward] " + "denied, stateInstanceId:" + stateInstance.getId(), FrameworkErrorCode.OperationDenied);
}
lastForwardStateInstance = stateInstance;
break;
}
}
return lastForwardStateInstance;
}
use of io.seata.saga.engine.exception.ForwardInvalidException in project seata by seata.
the class SubStateMachineHandler method process.
@Override
public void process(ProcessContext context) throws EngineExecutionException {
StateInstruction instruction = context.getInstruction(StateInstruction.class);
SubStateMachineImpl subStateMachine = (SubStateMachineImpl) instruction.getState(context);
StateMachineEngine engine = (StateMachineEngine) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_ENGINE);
StateMachineInstance stateMachineInstance = (StateMachineInstance) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_INST);
StateInstance stateInstance = (StateInstance) context.getVariable(DomainConstants.VAR_NAME_STATE_INST);
Object inputParamsObj = context.getVariable(DomainConstants.VAR_NAME_INPUT_PARAMS);
Map<String, Object> startParams = new HashMap<>(0);
if (inputParamsObj instanceof List) {
List<Object> listInputParams = (List<Object>) inputParamsObj;
if (listInputParams.size() > 0) {
startParams = (Map<String, Object>) listInputParams.get(0);
}
} else if (inputParamsObj instanceof Map) {
startParams = (Map<String, Object>) inputParamsObj;
}
startParams.put(DomainConstants.VAR_NAME_PARENT_ID, EngineUtils.generateParentId(stateInstance));
try {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(">>>>>>>>>>>>>>>>>>>>>> Start to execute SubStateMachine [{}] by state[{}]", subStateMachine.getStateMachineName(), subStateMachine.getName());
}
StateMachineInstance subStateMachineInstance = callSubStateMachine(startParams, engine, context, stateInstance, subStateMachine);
Map<String, Object> outputParams = subStateMachineInstance.getEndParams();
boolean isForward = DomainConstants.OPERATION_NAME_FORWARD.equals(context.getVariable(DomainConstants.VAR_NAME_OPERATION_NAME));
ExecutionStatus callSubMachineStatus = decideStatus(subStateMachineInstance, isForward);
stateInstance.setStatus(callSubMachineStatus);
outputParams.put(DomainConstants.VAR_NAME_SUB_STATEMACHINE_EXEC_STATUE, callSubMachineStatus.toString());
context.setVariable(DomainConstants.VAR_NAME_OUTPUT_PARAMS, outputParams);
stateInstance.setOutputParams(outputParams);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("<<<<<<<<<<<<<<<<<<<<<< SubStateMachine[{}] execute finish with status[{}], compensateStatus[{}]", subStateMachine.getStateMachineName(), subStateMachineInstance.getStatus(), subStateMachineInstance.getCompensationStatus());
}
} catch (Exception e) {
LOGGER.error("SubStateMachine[{}] execute failed by state[name:{}]", subStateMachine.getStateMachineName(), subStateMachine.getName(), e);
if (e instanceof ForwardInvalidException) {
String retriedId = stateInstance.getStateIdRetriedFor();
StateInstance stateToBeRetried = null;
for (StateInstance stateInst : stateMachineInstance.getStateList()) {
if (retriedId.equals(stateInst.getId())) {
stateToBeRetried = stateInst;
break;
}
}
if (stateToBeRetried != null) {
stateInstance.setStatus(stateToBeRetried.getStatus());
}
}
context.setVariable(DomainConstants.VAR_NAME_CURRENT_EXCEPTION, e);
EngineUtils.handleException(context, subStateMachine, e);
}
}
use of io.seata.saga.engine.exception.ForwardInvalidException in project seata by seata.
the class ProcessCtrlStateMachineEngine method forwardInternal.
protected StateMachineInstance forwardInternal(String stateMachineInstId, Map<String, Object> replaceParams, boolean skip, boolean async, AsyncCallback callback) throws EngineExecutionException {
StateMachineInstance stateMachineInstance = reloadStateMachineInstance(stateMachineInstId);
if (stateMachineInstance == null) {
throw new ForwardInvalidException("StateMachineInstance is not exits", FrameworkErrorCode.StateMachineInstanceNotExists);
}
if (ExecutionStatus.SU.equals(stateMachineInstance.getStatus()) && stateMachineInstance.getCompensationStatus() == null) {
return stateMachineInstance;
}
ExecutionStatus[] acceptStatus = new ExecutionStatus[] { ExecutionStatus.FA, ExecutionStatus.UN, ExecutionStatus.RU };
checkStatus(stateMachineInstance, acceptStatus, null, stateMachineInstance.getStatus(), null, "forward");
List<StateInstance> actList = stateMachineInstance.getStateList();
if (CollectionUtils.isEmpty(actList)) {
throw new ForwardInvalidException("StateMachineInstance[id:" + stateMachineInstId + "] has no stateInstance, pls start a new StateMachine execution instead", FrameworkErrorCode.OperationDenied);
}
StateInstance lastForwardState = findOutLastForwardStateInstance(actList);
if (lastForwardState == null) {
throw new ForwardInvalidException("StateMachineInstance[id:" + stateMachineInstId + "] Cannot find last forward execution stateInstance", FrameworkErrorCode.OperationDenied);
}
ProcessContextBuilder contextBuilder = ProcessContextBuilder.create().withProcessType(ProcessType.STATE_LANG).withOperationName(DomainConstants.OPERATION_NAME_FORWARD).withAsyncCallback(callback).withStateMachineInstance(stateMachineInstance).withStateInstance(lastForwardState).withStateMachineConfig(getStateMachineConfig()).withStateMachineEngine(this);
contextBuilder.withIsAsyncExecution(async);
ProcessContext context = contextBuilder.build();
Map<String, Object> contextVariables = getStateMachineContextVariables(stateMachineInstance);
if (replaceParams != null) {
contextVariables.putAll(replaceParams);
}
putBusinesskeyToContextariables(stateMachineInstance, contextVariables);
ConcurrentHashMap<String, Object> concurrentContextVariables = new ConcurrentHashMap<>(contextVariables.size());
nullSafeCopy(contextVariables, concurrentContextVariables);
context.setVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONTEXT, concurrentContextVariables);
stateMachineInstance.setContext(concurrentContextVariables);
String originStateName = EngineUtils.getOriginStateName(lastForwardState);
State lastState = stateMachineInstance.getStateMachine().getState(originStateName);
Loop loop = LoopTaskUtils.getLoopConfig(context, lastState);
if (null != loop && ExecutionStatus.SU.equals(lastForwardState.getStatus())) {
lastForwardState = LoopTaskUtils.findOutLastNeedForwardStateInstance(context);
}
context.setVariable(lastForwardState.getName() + DomainConstants.VAR_NAME_RETRIED_STATE_INST_ID, lastForwardState.getId());
if (DomainConstants.STATE_TYPE_SUB_STATE_MACHINE.equals(lastForwardState.getType()) && !ExecutionStatus.SU.equals(lastForwardState.getCompensationStatus())) {
context.setVariable(DomainConstants.VAR_NAME_IS_FOR_SUB_STATMACHINE_FORWARD, true);
}
if (!ExecutionStatus.SU.equals(lastForwardState.getStatus())) {
lastForwardState.setIgnoreStatus(true);
}
try {
StateInstruction inst = new StateInstruction();
inst.setTenantId(stateMachineInstance.getTenantId());
inst.setStateMachineName(stateMachineInstance.getStateMachine().getName());
if (skip || ExecutionStatus.SU.equals(lastForwardState.getStatus())) {
String next = null;
State state = stateMachineInstance.getStateMachine().getState(EngineUtils.getOriginStateName(lastForwardState));
if (state != null && state instanceof AbstractTaskState) {
next = ((AbstractTaskState) state).getNext();
}
if (StringUtils.isEmpty(next)) {
LOGGER.warn("Last Forward execution StateInstance was succeed, and it has not Next State , skip forward " + "operation");
return stateMachineInstance;
}
inst.setStateName(next);
} else {
if (ExecutionStatus.RU.equals(lastForwardState.getStatus()) && !EngineUtils.isTimeout(lastForwardState.getGmtStarted(), stateMachineConfig.getServiceInvokeTimeout())) {
throw new EngineExecutionException("State [" + lastForwardState.getName() + "] is running, operation[forward] denied", FrameworkErrorCode.OperationDenied);
}
inst.setStateName(EngineUtils.getOriginStateName(lastForwardState));
}
context.setInstruction(inst);
stateMachineInstance.setStatus(ExecutionStatus.RU);
stateMachineInstance.setRunning(true);
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Operation [forward] started stateMachineInstance[id:" + stateMachineInstance.getId() + "]");
}
if (stateMachineInstance.getStateMachine().isPersist()) {
stateMachineConfig.getStateLogStore().recordStateMachineRestarted(stateMachineInstance, context);
}
loop = LoopTaskUtils.getLoopConfig(context, inst.getState(context));
if (null != loop) {
inst.setTemporaryState(new LoopStartStateImpl());
}
if (async) {
stateMachineConfig.getAsyncProcessCtrlEventPublisher().publish(context);
} else {
stateMachineConfig.getProcessCtrlEventPublisher().publish(context);
}
} catch (EngineExecutionException e) {
LOGGER.error("Operation [forward] failed", e);
throw e;
}
return stateMachineInstance;
}
use of io.seata.saga.engine.exception.ForwardInvalidException in project seata by seata.
the class SubStateMachineHandler method forwardStateMachine.
private StateMachineInstance forwardStateMachine(Map<String, Object> startParams, StateMachineEngine engine, ProcessContext context, StateInstance stateInstance, SubStateMachine subStateMachine) {
StateMachineConfig stateMachineConfig = (StateMachineConfig) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONFIG);
StateLogStore statePersister = stateMachineConfig.getStateLogStore();
if (statePersister == null) {
throw new ForwardInvalidException("StatePersister is not configured", FrameworkErrorCode.ObjectNotExists);
}
StateInstance originalStateInst = stateInstance;
do {
originalStateInst = statePersister.getStateInstance(originalStateInst.getStateIdRetriedFor(), originalStateInst.getMachineInstanceId());
} while (StringUtils.hasText(originalStateInst.getStateIdRetriedFor()));
List<StateMachineInstance> subInst = statePersister.queryStateMachineInstanceByParentId(EngineUtils.generateParentId(originalStateInst));
if (subInst.size() > 0) {
String subInstId = subInst.get(0).getId();
return engine.forward(subInstId, startParams);
} else {
originalStateInst.setStateMachineInstance(stateInstance.getStateMachineInstance());
return startNewStateMachine(startParams, engine, originalStateInst, subStateMachine);
}
}
Aggregations