Search in sources :

Example 1 with ServiceTaskStateImpl

use of io.seata.saga.statelang.domain.impl.ServiceTaskStateImpl in project seata by seata.

the class ServiceTaskHandlerInterceptor method preProcess.

@Override
public void preProcess(ProcessContext context) throws EngineExecutionException {
    StateInstruction instruction = context.getInstruction(StateInstruction.class);
    StateMachineInstance stateMachineInstance = (StateMachineInstance) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_INST);
    StateMachineConfig stateMachineConfig = (StateMachineConfig) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONFIG);
    if (EngineUtils.isTimeout(stateMachineInstance.getGmtUpdated(), stateMachineConfig.getTransOperationTimeout())) {
        String message = "Saga Transaction [stateMachineInstanceId:" + stateMachineInstance.getId() + "] has timed out, stop execution now.";
        LOGGER.error(message);
        EngineExecutionException exception = ExceptionUtils.createEngineExecutionException(null, FrameworkErrorCode.StateMachineExecutionTimeout, message, stateMachineInstance, instruction.getStateName());
        EngineUtils.failStateMachine(context, exception);
        throw exception;
    }
    StateInstanceImpl stateInstance = new StateInstanceImpl();
    Map<String, Object> contextVariables = (Map<String, Object>) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONTEXT);
    ServiceTaskStateImpl state = (ServiceTaskStateImpl) instruction.getState(context);
    List<Object> serviceInputParams = null;
    if (contextVariables != null) {
        try {
            serviceInputParams = ParameterUtils.createInputParams(stateMachineConfig.getExpressionFactoryManager(), stateInstance, state, contextVariables);
        } catch (Exception e) {
            String message = "Task [" + state.getName() + "] input parameters assign failed, please check 'Input' expression:" + e.getMessage();
            EngineExecutionException exception = ExceptionUtils.createEngineExecutionException(e, FrameworkErrorCode.VariablesAssignError, message, stateMachineInstance, state.getName());
            EngineUtils.failStateMachine(context, exception);
            throw exception;
        }
    }
    ((HierarchicalProcessContext) context).setVariableLocally(DomainConstants.VAR_NAME_INPUT_PARAMS, serviceInputParams);
    stateInstance.setMachineInstanceId(stateMachineInstance.getId());
    stateInstance.setStateMachineInstance(stateMachineInstance);
    Object isForCompensation = state.isForCompensation();
    if (context.hasVariable(DomainConstants.VAR_NAME_IS_LOOP_STATE) && !Boolean.TRUE.equals(isForCompensation)) {
        stateInstance.setName(LoopTaskUtils.generateLoopStateName(context, state.getName()));
        StateInstance lastRetriedStateInstance = LoopTaskUtils.findOutLastRetriedStateInstance(stateMachineInstance, stateInstance.getName());
        stateInstance.setStateIdRetriedFor(lastRetriedStateInstance == null ? null : lastRetriedStateInstance.getId());
    } else {
        stateInstance.setName(state.getName());
        stateInstance.setStateIdRetriedFor((String) context.getVariable(state.getName() + DomainConstants.VAR_NAME_RETRIED_STATE_INST_ID));
    }
    stateInstance.setGmtStarted(new Date());
    stateInstance.setGmtUpdated(stateInstance.getGmtStarted());
    stateInstance.setStatus(ExecutionStatus.RU);
    if (StringUtils.hasLength(stateInstance.getBusinessKey())) {
        ((Map<String, Object>) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONTEXT)).put(state.getName() + DomainConstants.VAR_NAME_BUSINESSKEY, stateInstance.getBusinessKey());
    }
    stateInstance.setType(state.getType());
    stateInstance.setForUpdate(state.isForUpdate());
    stateInstance.setServiceName(state.getServiceName());
    stateInstance.setServiceMethod(state.getServiceMethod());
    stateInstance.setServiceType(state.getServiceType());
    if (isForCompensation != null && (Boolean) isForCompensation) {
        CompensationHolder compensationHolder = CompensationHolder.getCurrent(context, true);
        StateInstance stateToBeCompensated = compensationHolder.getStatesNeedCompensation().get(state.getName());
        if (stateToBeCompensated != null) {
            stateToBeCompensated.setCompensationState(stateInstance);
            stateInstance.setStateIdCompensatedFor(stateToBeCompensated.getId());
        } else {
            LOGGER.error("Compensation State[{}] has no state to compensate, maybe this is a bug.", state.getName());
        }
        CompensationHolder.getCurrent(context, true).addForCompensationState(stateInstance.getName(), stateInstance);
    }
    if (DomainConstants.OPERATION_NAME_FORWARD.equals(context.getVariable(DomainConstants.VAR_NAME_OPERATION_NAME)) && StringUtils.isEmpty(stateInstance.getStateIdRetriedFor()) && !state.isForCompensation()) {
        List<StateInstance> stateList = stateMachineInstance.getStateList();
        if (CollectionUtils.isNotEmpty(stateList)) {
            for (int i = stateList.size() - 1; i >= 0; i--) {
                StateInstance executedState = stateList.get(i);
                if (stateInstance.getName().equals(executedState.getName())) {
                    stateInstance.setStateIdRetriedFor(executedState.getId());
                    executedState.setIgnoreStatus(true);
                    break;
                }
            }
        }
    }
    stateInstance.setInputParams(serviceInputParams);
    if (stateMachineInstance.getStateMachine().isPersist() && state.isPersist() && stateMachineConfig.getStateLogStore() != null) {
        try {
            stateMachineConfig.getStateLogStore().recordStateStarted(stateInstance, context);
        } catch (Exception e) {
            String message = "Record state[" + state.getName() + "] started failed, stateMachineInstance[" + stateMachineInstance.getId() + "], Reason: " + e.getMessage();
            EngineExecutionException exception = ExceptionUtils.createEngineExecutionException(e, FrameworkErrorCode.ExceptionCaught, message, stateMachineInstance, state.getName());
            EngineUtils.failStateMachine(context, exception);
            throw exception;
        }
    }
    if (StringUtils.isEmpty(stateInstance.getId())) {
        stateInstance.setId(stateMachineConfig.getSeqGenerator().generate(DomainConstants.SEQ_ENTITY_STATE_INST));
    }
    stateMachineInstance.putStateInstance(stateInstance.getId(), stateInstance);
    ((HierarchicalProcessContext) context).setVariableLocally(DomainConstants.VAR_NAME_STATE_INST, stateInstance);
}
Also used : CompensationHolder(io.seata.saga.engine.pcext.utils.CompensationHolder) StateInstruction(io.seata.saga.engine.pcext.StateInstruction) StateInstanceImpl(io.seata.saga.statelang.domain.impl.StateInstanceImpl) HierarchicalProcessContext(io.seata.saga.proctrl.HierarchicalProcessContext) EngineExecutionException(io.seata.saga.engine.exception.EngineExecutionException) EngineExecutionException(io.seata.saga.engine.exception.EngineExecutionException) Date(java.util.Date) StateMachineInstance(io.seata.saga.statelang.domain.StateMachineInstance) ServiceTaskStateImpl(io.seata.saga.statelang.domain.impl.ServiceTaskStateImpl) StateMachineConfig(io.seata.saga.engine.StateMachineConfig) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map) StateInstance(io.seata.saga.statelang.domain.StateInstance)

Example 2 with ServiceTaskStateImpl

use of io.seata.saga.statelang.domain.impl.ServiceTaskStateImpl in project seata by seata.

the class ServiceTaskStateParser method parse.

@Override
public ServiceTaskState parse(Object node) {
    ServiceTaskStateImpl serviceTaskState = new ServiceTaskStateImpl();
    parseTaskAttributes(serviceTaskState, node);
    Map<String, Object> nodeMap = (Map<String, Object>) node;
    serviceTaskState.setServiceName((String) nodeMap.get("ServiceName"));
    serviceTaskState.setServiceMethod((String) nodeMap.get("ServiceMethod"));
    serviceTaskState.setServiceType((String) nodeMap.get("ServiceType"));
    serviceTaskState.setParameterTypes((List<String>) nodeMap.get("ParameterTypes"));
    Object isAsync = nodeMap.get("IsAsync");
    if (Boolean.TRUE.equals(isAsync)) {
        serviceTaskState.setAsync(true);
    }
    return serviceTaskState;
}
Also used : Map(java.util.Map) ServiceTaskStateImpl(io.seata.saga.statelang.domain.impl.ServiceTaskStateImpl)

Example 3 with ServiceTaskStateImpl

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

use of io.seata.saga.statelang.domain.impl.ServiceTaskStateImpl in project seata by seata.

the class ServiceTaskStateHandler method process.

@Override
public void process(ProcessContext context) throws EngineExecutionException {
    StateInstruction instruction = context.getInstruction(StateInstruction.class);
    ServiceTaskStateImpl state = (ServiceTaskStateImpl) instruction.getState(context);
    String serviceName = state.getServiceName();
    String methodName = state.getServiceMethod();
    StateInstance stateInstance = (StateInstance) context.getVariable(DomainConstants.VAR_NAME_STATE_INST);
    Object result;
    try {
        List<Object> input = (List<Object>) context.getVariable(DomainConstants.VAR_NAME_INPUT_PARAMS);
        // Set the current task execution status to RU (Running)
        stateInstance.setStatus(ExecutionStatus.RU);
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug(">>>>>>>>>>>>>>>>>>>>>> Start to execute State[{}], ServiceName[{}], Method[{}], Input:{}", state.getName(), serviceName, methodName, input);
        }
        if (state instanceof CompensateSubStateMachineState) {
            // If it is the compensation of the substate machine,
            // directly call the state machine's compensate method
            result = compensateSubStateMachine(context, state, input, stateInstance, (StateMachineEngine) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_ENGINE));
        } else {
            StateMachineConfig stateMachineConfig = (StateMachineConfig) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONFIG);
            ServiceInvoker serviceInvoker = stateMachineConfig.getServiceInvokerManager().getServiceInvoker(state.getServiceType());
            if (serviceInvoker == null) {
                throw new EngineExecutionException("No such ServiceInvoker[" + state.getServiceType() + "]", FrameworkErrorCode.ObjectNotExists);
            }
            if (serviceInvoker instanceof ApplicationContextAware) {
                ((ApplicationContextAware) serviceInvoker).setApplicationContext(stateMachineConfig.getApplicationContext());
            }
            result = serviceInvoker.invoke(state, input.toArray());
        }
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("<<<<<<<<<<<<<<<<<<<<<< State[{}], ServiceName[{}], Method[{}] Execute finish. result: {}", state.getName(), serviceName, methodName, result);
        }
        if (result != null) {
            stateInstance.setOutputParams(result);
            ((HierarchicalProcessContext) context).setVariableLocally(DomainConstants.VAR_NAME_OUTPUT_PARAMS, result);
        }
    } catch (Throwable e) {
        LOGGER.error("<<<<<<<<<<<<<<<<<<<<<< State[{}], ServiceName[{}], Method[{}] Execute failed.", state.getName(), serviceName, methodName, e);
        ((HierarchicalProcessContext) context).setVariableLocally(DomainConstants.VAR_NAME_CURRENT_EXCEPTION, e);
        EngineUtils.handleException(context, state, e);
    }
}
Also used : StateMachineEngine(io.seata.saga.engine.StateMachineEngine) ApplicationContextAware(org.springframework.context.ApplicationContextAware) StateInstruction(io.seata.saga.engine.pcext.StateInstruction) HierarchicalProcessContext(io.seata.saga.proctrl.HierarchicalProcessContext) CompensateSubStateMachineState(io.seata.saga.statelang.domain.CompensateSubStateMachineState) EngineExecutionException(io.seata.saga.engine.exception.EngineExecutionException) ServiceTaskStateImpl(io.seata.saga.statelang.domain.impl.ServiceTaskStateImpl) ArrayList(java.util.ArrayList) List(java.util.List) StateMachineConfig(io.seata.saga.engine.StateMachineConfig) ServiceInvoker(io.seata.saga.engine.invoker.ServiceInvoker) StateInstance(io.seata.saga.statelang.domain.StateInstance)

Example 5 with ServiceTaskStateImpl

use of io.seata.saga.statelang.domain.impl.ServiceTaskStateImpl in project seata by seata.

the class DbAndReportTcStateLogStore method isUpdateMode.

private boolean isUpdateMode(StateInstance stateInstance, ProcessContext context) {
    DefaultStateMachineConfig stateMachineConfig = (DefaultStateMachineConfig) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONFIG);
    StateInstruction instruction = context.getInstruction(StateInstruction.class);
    ServiceTaskStateImpl state = (ServiceTaskStateImpl) instruction.getState(context);
    StateMachine stateMachine = stateInstance.getStateMachineInstance().getStateMachine();
    if (StringUtils.hasLength(stateInstance.getStateIdRetriedFor())) {
        if (null != state.isRetryPersistModeUpdate()) {
            return state.isRetryPersistModeUpdate();
        } else if (null != stateMachine.isRetryPersistModeUpdate()) {
            return stateMachine.isRetryPersistModeUpdate();
        }
        return stateMachineConfig.isSagaRetryPersistModeUpdate();
    } else if (StringUtils.hasLength(stateInstance.getStateIdCompensatedFor())) {
        // find if this compensate has been executed
        for (int i = 0; i < stateInstance.getStateMachineInstance().getStateList().size(); i++) {
            StateInstance aStateInstance = stateInstance.getStateMachineInstance().getStateList().get(i);
            if (aStateInstance.isForCompensation() && aStateInstance.getName().equals(stateInstance.getName())) {
                if (null != state.isCompensatePersistModeUpdate()) {
                    return state.isCompensatePersistModeUpdate();
                } else if (null != stateMachine.isCompensatePersistModeUpdate()) {
                    return stateMachine.isCompensatePersistModeUpdate();
                }
                return stateMachineConfig.isSagaCompensatePersistModeUpdate();
            }
        }
        return false;
    }
    return false;
}
Also used : StateInstruction(io.seata.saga.engine.pcext.StateInstruction) StateMachine(io.seata.saga.statelang.domain.StateMachine) DefaultStateMachineConfig(io.seata.saga.engine.impl.DefaultStateMachineConfig) ServiceTaskStateImpl(io.seata.saga.statelang.domain.impl.ServiceTaskStateImpl) StateInstance(io.seata.saga.statelang.domain.StateInstance)

Aggregations

ServiceTaskStateImpl (io.seata.saga.statelang.domain.impl.ServiceTaskStateImpl)7 EngineExecutionException (io.seata.saga.engine.exception.EngineExecutionException)5 StateInstance (io.seata.saga.statelang.domain.StateInstance)5 StateInstruction (io.seata.saga.engine.pcext.StateInstruction)4 Map (java.util.Map)4 StateMachineConfig (io.seata.saga.engine.StateMachineConfig)3 ServiceInvoker (io.seata.saga.engine.invoker.ServiceInvoker)2 HierarchicalProcessContext (io.seata.saga.proctrl.HierarchicalProcessContext)2 StateMachineInstance (io.seata.saga.statelang.domain.StateMachineInstance)2 ArrayList (java.util.ArrayList)2 Date (java.util.Date)2 HashMap (java.util.HashMap)2 LinkedHashMap (java.util.LinkedHashMap)2 List (java.util.List)2 ApplicationContextAware (org.springframework.context.ApplicationContextAware)2 FrameworkErrorCode (io.seata.common.exception.FrameworkErrorCode)1 CollectionUtils (io.seata.common.util.CollectionUtils)1 StateMachineEngine (io.seata.saga.engine.StateMachineEngine)1 ForwardInvalidException (io.seata.saga.engine.exception.ForwardInvalidException)1 DefaultStateMachineConfig (io.seata.saga.engine.impl.DefaultStateMachineConfig)1