Search in sources :

Example 1 with ExecutionStatus

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

the class ProcessCtrlStateMachineEngine method buildExceptionMessage.

private String buildExceptionMessage(StateMachineInstance stateMachineInstance, ExecutionStatus[] acceptStatus, ExecutionStatus[] denyStatus, ExecutionStatus status, ExecutionStatus compenStatus, String operation) {
    StringBuilder stringBuilder = new StringBuilder();
    stringBuilder.append("StateMachineInstance[id:").append(stateMachineInstance.getId()).append("]");
    if (acceptStatus != null) {
        stringBuilder.append(",acceptable status :");
        for (ExecutionStatus tempStatus : acceptStatus) {
            stringBuilder.append(tempStatus.toString());
            stringBuilder.append(" ");
        }
    }
    if (denyStatus != null) {
        stringBuilder.append(",deny status:");
        for (ExecutionStatus tempStatus : denyStatus) {
            stringBuilder.append(tempStatus.toString());
            stringBuilder.append(" ");
        }
    }
    if (status != null) {
        stringBuilder.append(",current status:");
        stringBuilder.append(status.toString());
    }
    if (compenStatus != null) {
        stringBuilder.append(",current compensation status:");
        stringBuilder.append(compenStatus.toString());
    }
    stringBuilder.append(",so operation [").append(operation).append("] denied");
    return stringBuilder.toString();
}
Also used : ExecutionStatus(io.seata.saga.statelang.domain.ExecutionStatus)

Example 2 with ExecutionStatus

use of io.seata.saga.statelang.domain.ExecutionStatus 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 3 with ExecutionStatus

use of io.seata.saga.statelang.domain.ExecutionStatus 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 4 with ExecutionStatus

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

the class ProcessCtrlStateMachineEngine method checkStatus.

/**
 * Check if the status is legal
 *
 * @param stateMachineInstance
 * @param acceptStatus
 * @param denyStatus
 * @param status
 * @param compenStatus
 * @param operation
 * @return
 */
protected boolean checkStatus(StateMachineInstance stateMachineInstance, ExecutionStatus[] acceptStatus, ExecutionStatus[] denyStatus, ExecutionStatus status, ExecutionStatus compenStatus, String operation) {
    if (status != null && compenStatus != null) {
        throw new EngineExecutionException("status and compensationStatus are not supported at the same time", FrameworkErrorCode.InvalidParameter);
    }
    if (status == null && compenStatus == null) {
        throw new EngineExecutionException("status and compensationStatus must input at least one", FrameworkErrorCode.InvalidParameter);
    }
    if (ExecutionStatus.SU.equals(compenStatus)) {
        String message = buildExceptionMessage(stateMachineInstance, null, null, null, ExecutionStatus.SU, operation);
        throw new EngineExecutionException(message, FrameworkErrorCode.OperationDenied);
    }
    if (stateMachineInstance.isRunning() && !EngineUtils.isTimeout(stateMachineInstance.getGmtUpdated(), stateMachineConfig.getTransOperationTimeout())) {
        throw new EngineExecutionException("StateMachineInstance [id:" + stateMachineInstance.getId() + "] is running, operation[" + operation + "] denied", FrameworkErrorCode.OperationDenied);
    }
    if ((denyStatus == null || denyStatus.length == 0) && (acceptStatus == null || acceptStatus.length == 0)) {
        throw new EngineExecutionException("StateMachineInstance[id:" + stateMachineInstance.getId() + "], acceptable status and deny status must input at least one", FrameworkErrorCode.InvalidParameter);
    }
    ExecutionStatus currentStatus = (status != null) ? status : compenStatus;
    if (!(denyStatus == null || denyStatus.length == 0)) {
        for (ExecutionStatus tempDenyStatus : denyStatus) {
            if (tempDenyStatus.compareTo(currentStatus) == 0) {
                String message = buildExceptionMessage(stateMachineInstance, acceptStatus, denyStatus, status, compenStatus, operation);
                throw new EngineExecutionException(message, FrameworkErrorCode.OperationDenied);
            }
        }
    }
    if (acceptStatus == null || acceptStatus.length == 0) {
        return true;
    } else {
        for (ExecutionStatus tempStatus : acceptStatus) {
            if (tempStatus.compareTo(currentStatus) == 0) {
                return true;
            }
        }
    }
    String message = buildExceptionMessage(stateMachineInstance, acceptStatus, denyStatus, status, compenStatus, operation);
    throw new EngineExecutionException(message, FrameworkErrorCode.OperationDenied);
}
Also used : ExecutionStatus(io.seata.saga.statelang.domain.ExecutionStatus) EngineExecutionException(io.seata.saga.engine.exception.EngineExecutionException)

Example 5 with ExecutionStatus

use of io.seata.saga.statelang.domain.ExecutionStatus 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;
}
Also used : Loop(io.seata.saga.statelang.domain.TaskState.Loop) StateInstruction(io.seata.saga.engine.pcext.StateInstruction) ForwardInvalidException(io.seata.saga.engine.exception.ForwardInvalidException) EngineExecutionException(io.seata.saga.engine.exception.EngineExecutionException) ProcessContext(io.seata.saga.proctrl.ProcessContext) StateMachineInstance(io.seata.saga.statelang.domain.StateMachineInstance) AbstractTaskState(io.seata.saga.statelang.domain.impl.AbstractTaskState) LoopStartStateImpl(io.seata.saga.statelang.domain.impl.LoopStartStateImpl) ProcessContextBuilder(io.seata.saga.engine.utils.ProcessContextBuilder) ExecutionStatus(io.seata.saga.statelang.domain.ExecutionStatus) State(io.seata.saga.statelang.domain.State) AbstractTaskState(io.seata.saga.statelang.domain.impl.AbstractTaskState) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) StateInstance(io.seata.saga.statelang.domain.StateInstance)

Aggregations

ExecutionStatus (io.seata.saga.statelang.domain.ExecutionStatus)5 EngineExecutionException (io.seata.saga.engine.exception.EngineExecutionException)4 StateInstruction (io.seata.saga.engine.pcext.StateInstruction)3 StateMachineInstance (io.seata.saga.statelang.domain.StateMachineInstance)3 ForwardInvalidException (io.seata.saga.engine.exception.ForwardInvalidException)2 ProcessContextBuilder (io.seata.saga.engine.utils.ProcessContextBuilder)2 ProcessContext (io.seata.saga.proctrl.ProcessContext)2 StateInstance (io.seata.saga.statelang.domain.StateInstance)2 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)2 StateMachineEngine (io.seata.saga.engine.StateMachineEngine)1 State (io.seata.saga.statelang.domain.State)1 Loop (io.seata.saga.statelang.domain.TaskState.Loop)1 AbstractTaskState (io.seata.saga.statelang.domain.impl.AbstractTaskState)1 CompensationTriggerStateImpl (io.seata.saga.statelang.domain.impl.CompensationTriggerStateImpl)1 LoopStartStateImpl (io.seata.saga.statelang.domain.impl.LoopStartStateImpl)1 SubStateMachineImpl (io.seata.saga.statelang.domain.impl.SubStateMachineImpl)1 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 List (java.util.List)1 Map (java.util.Map)1