Search in sources :

Example 11 with StateInstruction

use of io.seata.saga.engine.pcext.StateInstruction in project seata by seata.

the class ServiceTaskHandlerInterceptor method postProcess.

@Override
public void postProcess(ProcessContext context, Exception exp) throws EngineExecutionException {
    StateInstruction instruction = context.getInstruction(StateInstruction.class);
    ServiceTaskStateImpl state = (ServiceTaskStateImpl) instruction.getState(context);
    StateMachineInstance stateMachineInstance = (StateMachineInstance) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_INST);
    StateInstance stateInstance = (StateInstance) context.getVariable(DomainConstants.VAR_NAME_STATE_INST);
    if (stateInstance == null || !stateMachineInstance.isRunning()) {
        LOGGER.warn("StateMachineInstance[id:" + stateMachineInstance.getId() + "] is end. stop running");
        return;
    }
    StateMachineConfig stateMachineConfig = (StateMachineConfig) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONFIG);
    if (exp == null) {
        exp = (Exception) context.getVariable(DomainConstants.VAR_NAME_CURRENT_EXCEPTION);
    }
    stateInstance.setException(exp);
    decideExecutionStatus(context, stateInstance, state, exp);
    if (ExecutionStatus.SU.equals(stateInstance.getStatus()) && exp != null) {
        if (LOGGER.isInfoEnabled()) {
            LOGGER.info("Although an exception occurs, the execution status map to SU, and the exception is ignored when " + "the execution status decision.");
        }
        context.removeVariable(DomainConstants.VAR_NAME_CURRENT_EXCEPTION);
    }
    Map<String, Object> contextVariables = (Map<String, Object>) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONTEXT);
    Object serviceOutputParams = context.getVariable(DomainConstants.VAR_NAME_OUTPUT_PARAMS);
    if (serviceOutputParams != null) {
        try {
            Map<String, Object> outputVariablesToContext = ParameterUtils.createOutputParams(stateMachineConfig.getExpressionFactoryManager(), state, serviceOutputParams);
            if (CollectionUtils.isNotEmpty(outputVariablesToContext)) {
                contextVariables.putAll(outputVariablesToContext);
            }
        } catch (Exception e) {
            String message = "Task [" + state.getName() + "] output parameters assign failed, please check 'Output' expression:" + e.getMessage();
            EngineExecutionException exception = ExceptionUtils.createEngineExecutionException(e, FrameworkErrorCode.VariablesAssignError, message, stateMachineInstance, stateInstance);
            if (stateMachineInstance.getStateMachine().isPersist() && state.isPersist() && stateMachineConfig.getStateLogStore() != null) {
                stateMachineConfig.getStateLogStore().recordStateFinished(stateInstance, context);
            }
            EngineUtils.failStateMachine(context, exception);
            throw exception;
        }
    }
    context.removeVariable(DomainConstants.VAR_NAME_OUTPUT_PARAMS);
    context.removeVariable(DomainConstants.VAR_NAME_INPUT_PARAMS);
    stateInstance.setGmtEnd(new Date());
    if (stateMachineInstance.getStateMachine().isPersist() && state.isPersist() && stateMachineConfig.getStateLogStore() != null) {
        stateMachineConfig.getStateLogStore().recordStateFinished(stateInstance, context);
    }
    if (exp != null && context.getVariable(DomainConstants.VAR_NAME_IS_EXCEPTION_NOT_CATCH) != null && (Boolean) context.getVariable(DomainConstants.VAR_NAME_IS_EXCEPTION_NOT_CATCH)) {
        // If there is an exception and there is no catch, need to exit the state machine to execute.
        context.removeVariable(DomainConstants.VAR_NAME_IS_EXCEPTION_NOT_CATCH);
        EngineUtils.failStateMachine(context, exp);
    }
}
Also used : StateInstruction(io.seata.saga.engine.pcext.StateInstruction) StateMachineConfig(io.seata.saga.engine.StateMachineConfig) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map) EngineExecutionException(io.seata.saga.engine.exception.EngineExecutionException) EngineExecutionException(io.seata.saga.engine.exception.EngineExecutionException) Date(java.util.Date) ServiceTaskStateImpl(io.seata.saga.statelang.domain.impl.ServiceTaskStateImpl) StateMachineInstance(io.seata.saga.statelang.domain.StateMachineInstance) StateInstance(io.seata.saga.statelang.domain.StateInstance)

Example 12 with StateInstruction

use of io.seata.saga.engine.pcext.StateInstruction 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;
}
Also used : LoopStartStateImpl(io.seata.saga.statelang.domain.impl.LoopStartStateImpl) StateInstruction(io.seata.saga.engine.pcext.StateInstruction) CompensateSubStateMachineState(io.seata.saga.statelang.domain.CompensateSubStateMachineState) State(io.seata.saga.statelang.domain.State) AbstractTaskState(io.seata.saga.statelang.domain.impl.AbstractTaskState) StateMachine(io.seata.saga.statelang.domain.StateMachine) SubStateMachine(io.seata.saga.statelang.domain.SubStateMachine) EngineExecutionException(io.seata.saga.engine.exception.EngineExecutionException)

Example 13 with StateInstruction

use of io.seata.saga.engine.pcext.StateInstruction 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;
}
Also used : AbstractTaskState(io.seata.saga.statelang.domain.impl.AbstractTaskState) StateInstruction(io.seata.saga.engine.pcext.StateInstruction) StateMachine(io.seata.saga.statelang.domain.StateMachine) SubStateMachine(io.seata.saga.statelang.domain.SubStateMachine) CompensateSubStateMachineState(io.seata.saga.statelang.domain.CompensateSubStateMachineState) State(io.seata.saga.statelang.domain.State) AbstractTaskState(io.seata.saga.statelang.domain.impl.AbstractTaskState) HierarchicalProcessContext(io.seata.saga.proctrl.HierarchicalProcessContext) CompensateSubStateMachineState(io.seata.saga.statelang.domain.CompensateSubStateMachineState) EngineExecutionException(io.seata.saga.engine.exception.EngineExecutionException) StateInstance(io.seata.saga.statelang.domain.StateInstance) SubStateMachine(io.seata.saga.statelang.domain.SubStateMachine)

Example 14 with StateInstruction

use of io.seata.saga.engine.pcext.StateInstruction in project seata by seata.

the class EngineUtils method endStateMachine.

/**
 * end StateMachine
 *
 * @param context
 */
public static void endStateMachine(ProcessContext context) {
    if (context.hasVariable(DomainConstants.VAR_NAME_IS_LOOP_STATE)) {
        if (context.hasVariable(DomainConstants.LOOP_SEMAPHORE)) {
            Semaphore semaphore = (Semaphore) context.getVariable(DomainConstants.LOOP_SEMAPHORE);
            semaphore.release();
        }
        return;
    }
    StateMachineInstance stateMachineInstance = (StateMachineInstance) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_INST);
    stateMachineInstance.setGmtEnd(new Date());
    Exception exp = (Exception) context.getVariable(DomainConstants.VAR_NAME_CURRENT_EXCEPTION);
    if (exp != null) {
        stateMachineInstance.setException(exp);
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Exception Occurred: " + exp);
        }
    }
    StateMachineConfig stateMachineConfig = (StateMachineConfig) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONFIG);
    stateMachineConfig.getStatusDecisionStrategy().decideOnEndState(context, stateMachineInstance, exp);
    stateMachineInstance.getEndParams().putAll((Map<String, Object>) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONTEXT));
    StateInstruction instruction = context.getInstruction(StateInstruction.class);
    instruction.setEnd(true);
    stateMachineInstance.setRunning(false);
    stateMachineInstance.setGmtEnd(new Date());
    if (stateMachineInstance.getStateMachine().isPersist() && stateMachineConfig.getStateLogStore() != null) {
        stateMachineConfig.getStateLogStore().recordStateMachineFinished(stateMachineInstance, context);
    }
    AsyncCallback callback = (AsyncCallback) context.getVariable(DomainConstants.VAR_NAME_ASYNC_CALLBACK);
    if (callback != null) {
        if (exp != null) {
            callback.onError(context, stateMachineInstance, exp);
        } else {
            callback.onFinished(context, stateMachineInstance);
        }
    }
}
Also used : StateInstruction(io.seata.saga.engine.pcext.StateInstruction) AsyncCallback(io.seata.saga.engine.AsyncCallback) StateMachineConfig(io.seata.saga.engine.StateMachineConfig) Semaphore(java.util.concurrent.Semaphore) Date(java.util.Date) StateMachineInstance(io.seata.saga.statelang.domain.StateMachineInstance)

Example 15 with StateInstruction

use of io.seata.saga.engine.pcext.StateInstruction in project seata by seata.

the class EngineUtils method failStateMachine.

/**
 * fail StateMachine
 *
 * @param context
 * @param exp
 */
public static void failStateMachine(ProcessContext context, Exception exp) {
    if (context.hasVariable(DomainConstants.VAR_NAME_IS_LOOP_STATE)) {
        return;
    }
    StateMachineInstance stateMachineInstance = (StateMachineInstance) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_INST);
    StateMachineConfig stateMachineConfig = (StateMachineConfig) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONFIG);
    stateMachineConfig.getStatusDecisionStrategy().decideOnTaskStateFail(context, stateMachineInstance, exp);
    stateMachineInstance.getEndParams().putAll((Map<String, Object>) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONTEXT));
    StateInstruction instruction = context.getInstruction(StateInstruction.class);
    instruction.setEnd(true);
    stateMachineInstance.setRunning(false);
    stateMachineInstance.setGmtEnd(new Date());
    stateMachineInstance.setException(exp);
    if (stateMachineInstance.getStateMachine().isPersist() && stateMachineConfig.getStateLogStore() != null) {
        stateMachineConfig.getStateLogStore().recordStateMachineFinished(stateMachineInstance, context);
    }
    AsyncCallback callback = (AsyncCallback) context.getVariable(DomainConstants.VAR_NAME_ASYNC_CALLBACK);
    if (callback != null) {
        callback.onError(context, stateMachineInstance, exp);
    }
}
Also used : StateInstruction(io.seata.saga.engine.pcext.StateInstruction) AsyncCallback(io.seata.saga.engine.AsyncCallback) StateMachineConfig(io.seata.saga.engine.StateMachineConfig) Date(java.util.Date) StateMachineInstance(io.seata.saga.statelang.domain.StateMachineInstance)

Aggregations

StateInstruction (io.seata.saga.engine.pcext.StateInstruction)23 EngineExecutionException (io.seata.saga.engine.exception.EngineExecutionException)15 StateMachineInstance (io.seata.saga.statelang.domain.StateMachineInstance)14 StateMachineConfig (io.seata.saga.engine.StateMachineConfig)11 StateInstance (io.seata.saga.statelang.domain.StateInstance)10 Map (java.util.Map)10 HierarchicalProcessContext (io.seata.saga.proctrl.HierarchicalProcessContext)7 AbstractTaskState (io.seata.saga.statelang.domain.impl.AbstractTaskState)5 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)5 ProcessContext (io.seata.saga.proctrl.ProcessContext)4 Loop (io.seata.saga.statelang.domain.TaskState.Loop)4 ServiceTaskStateImpl (io.seata.saga.statelang.domain.impl.ServiceTaskStateImpl)4 ArrayList (java.util.ArrayList)4 Date (java.util.Date)4 ForwardInvalidException (io.seata.saga.engine.exception.ForwardInvalidException)3 ProcessContextBuilder (io.seata.saga.engine.utils.ProcessContextBuilder)3 CompensateSubStateMachineState (io.seata.saga.statelang.domain.CompensateSubStateMachineState)3 ExecutionStatus (io.seata.saga.statelang.domain.ExecutionStatus)3 State (io.seata.saga.statelang.domain.State)3 StateMachine (io.seata.saga.statelang.domain.StateMachine)3