Search in sources :

Example 6 with StateMachineInstance

use of io.seata.saga.statelang.domain.StateMachineInstance in project seata by seata.

the class ProcessCtrlStateMachineEngine method compensateInternal.

public StateMachineInstance compensateInternal(String stateMachineInstId, Map<String, Object> replaceParams, boolean async, AsyncCallback callback) throws EngineExecutionException {
    StateMachineInstance stateMachineInstance = reloadStateMachineInstance(stateMachineInstId);
    if (stateMachineInstance == null) {
        throw new EngineExecutionException("StateMachineInstance is not exits", FrameworkErrorCode.StateMachineInstanceNotExists);
    }
    if (ExecutionStatus.SU.equals(stateMachineInstance.getCompensationStatus())) {
        return stateMachineInstance;
    }
    if (stateMachineInstance.getCompensationStatus() != null) {
        ExecutionStatus[] denyStatus = new ExecutionStatus[] { ExecutionStatus.SU };
        checkStatus(stateMachineInstance, null, denyStatus, null, stateMachineInstance.getCompensationStatus(), "compensate");
    }
    if (replaceParams != null) {
        stateMachineInstance.getEndParams().putAll(replaceParams);
    }
    ProcessContextBuilder contextBuilder = ProcessContextBuilder.create().withProcessType(ProcessType.STATE_LANG).withOperationName(DomainConstants.OPERATION_NAME_COMPENSATE).withAsyncCallback(callback).withStateMachineInstance(stateMachineInstance).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);
    CompensationTriggerStateImpl tempCompensationTriggerState = new CompensationTriggerStateImpl();
    tempCompensationTriggerState.setStateMachine(stateMachineInstance.getStateMachine());
    stateMachineInstance.setRunning(true);
    if (LOGGER.isInfoEnabled()) {
        LOGGER.info("Operation [compensate] start.  stateMachineInstance[id:" + stateMachineInstance.getId() + "]");
    }
    if (stateMachineInstance.getStateMachine().isPersist()) {
        stateMachineConfig.getStateLogStore().recordStateMachineRestarted(stateMachineInstance, context);
    }
    try {
        StateInstruction inst = new StateInstruction();
        inst.setTenantId(stateMachineInstance.getTenantId());
        inst.setStateMachineName(stateMachineInstance.getStateMachine().getName());
        inst.setTemporaryState(tempCompensationTriggerState);
        context.setInstruction(inst);
        if (async) {
            stateMachineConfig.getAsyncProcessCtrlEventPublisher().publish(context);
        } else {
            stateMachineConfig.getProcessCtrlEventPublisher().publish(context);
        }
    } catch (EngineExecutionException e) {
        LOGGER.error("Operation [compensate] failed", e);
        throw e;
    }
    return stateMachineInstance;
}
Also used : CompensationTriggerStateImpl(io.seata.saga.statelang.domain.impl.CompensationTriggerStateImpl) StateInstruction(io.seata.saga.engine.pcext.StateInstruction) EngineExecutionException(io.seata.saga.engine.exception.EngineExecutionException) ProcessContext(io.seata.saga.proctrl.ProcessContext) StateMachineInstance(io.seata.saga.statelang.domain.StateMachineInstance) ProcessContextBuilder(io.seata.saga.engine.utils.ProcessContextBuilder) ExecutionStatus(io.seata.saga.statelang.domain.ExecutionStatus) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap)

Example 7 with StateMachineInstance

use of io.seata.saga.statelang.domain.StateMachineInstance in project seata by seata.

the class ProcessCtrlStateMachineEngine method reloadStateMachineInstance.

/**
 * override state machine instance
 *
 * @param instId
 * @return
 */
@Override
public StateMachineInstance reloadStateMachineInstance(String instId) {
    StateMachineInstance inst = stateMachineConfig.getStateLogStore().getStateMachineInstance(instId);
    if (inst != null) {
        StateMachine stateMachine = inst.getStateMachine();
        if (stateMachine == null) {
            stateMachine = stateMachineConfig.getStateMachineRepository().getStateMachineById(inst.getMachineId());
            inst.setStateMachine(stateMachine);
        }
        if (stateMachine == null) {
            throw new EngineExecutionException("StateMachine[id:" + inst.getMachineId() + "] not exist.", FrameworkErrorCode.ObjectNotExists);
        }
        List<StateInstance> stateList = inst.getStateList();
        if (CollectionUtils.isEmpty(stateList)) {
            stateList = stateMachineConfig.getStateLogStore().queryStateInstanceListByMachineInstanceId(instId);
            if (CollectionUtils.isNotEmpty(stateList)) {
                for (StateInstance tmpStateInstance : stateList) {
                    inst.putStateInstance(tmpStateInstance.getId(), tmpStateInstance);
                }
            }
        }
        if (CollectionUtils.isEmpty(inst.getEndParams())) {
            inst.setEndParams(replayContextVariables(inst));
        }
    }
    return inst;
}
Also used : StateMachine(io.seata.saga.statelang.domain.StateMachine) EngineExecutionException(io.seata.saga.engine.exception.EngineExecutionException) StateMachineInstance(io.seata.saga.statelang.domain.StateMachineInstance) StateInstance(io.seata.saga.statelang.domain.StateInstance)

Example 8 with StateMachineInstance

use of io.seata.saga.statelang.domain.StateMachineInstance 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;
}
Also used : ForwardInvalidException(io.seata.saga.engine.exception.ForwardInvalidException) StateInstance(io.seata.saga.statelang.domain.StateInstance) StateMachineInstance(io.seata.saga.statelang.domain.StateMachineInstance)

Example 9 with StateMachineInstance

use of io.seata.saga.statelang.domain.StateMachineInstance 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);
    }
}
Also used : StateMachineEngine(io.seata.saga.engine.StateMachineEngine) StateInstruction(io.seata.saga.engine.pcext.StateInstruction) HashMap(java.util.HashMap) ForwardInvalidException(io.seata.saga.engine.exception.ForwardInvalidException) EngineExecutionException(io.seata.saga.engine.exception.EngineExecutionException) ForwardInvalidException(io.seata.saga.engine.exception.ForwardInvalidException) StateMachineInstance(io.seata.saga.statelang.domain.StateMachineInstance) ExecutionStatus(io.seata.saga.statelang.domain.ExecutionStatus) ArrayList(java.util.ArrayList) List(java.util.List) SubStateMachineImpl(io.seata.saga.statelang.domain.impl.SubStateMachineImpl) HashMap(java.util.HashMap) Map(java.util.Map) StateInstance(io.seata.saga.statelang.domain.StateInstance)

Example 10 with StateMachineInstance

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

Aggregations

StateMachineInstance (io.seata.saga.statelang.domain.StateMachineInstance)113 HashMap (java.util.HashMap)80 Test (org.junit.jupiter.api.Test)76 EngineExecutionException (io.seata.saga.engine.exception.EngineExecutionException)21 GlobalTransaction (io.seata.tm.api.GlobalTransaction)17 StateMachineConfig (io.seata.saga.engine.StateMachineConfig)16 StateInstance (io.seata.saga.statelang.domain.StateInstance)16 StateInstruction (io.seata.saga.engine.pcext.StateInstruction)15 ArrayList (java.util.ArrayList)12 Map (java.util.Map)12 ForwardInvalidException (io.seata.saga.engine.exception.ForwardInvalidException)7 ProcessContext (io.seata.saga.proctrl.ProcessContext)6 People (io.seata.saga.engine.mock.DemoService.People)5 ExecutionStatus (io.seata.saga.statelang.domain.ExecutionStatus)5 Loop (io.seata.saga.statelang.domain.TaskState.Loop)5 Date (java.util.Date)5 LinkedHashMap (java.util.LinkedHashMap)5 TransactionException (io.seata.core.exception.TransactionException)4 AbstractTaskState (io.seata.saga.statelang.domain.impl.AbstractTaskState)4 List (java.util.List)4