Search in sources :

Example 11 with StateMachineConfig

use of io.seata.saga.engine.StateMachineConfig 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 StateMachineConfig

use of io.seata.saga.engine.StateMachineConfig in project seata by seata.

the class ServiceTaskHandlerInterceptor method decideExecutionStatus.

private void decideExecutionStatus(ProcessContext context, StateInstance stateInstance, ServiceTaskStateImpl state, Exception exp) {
    Map<String, String> statusMatchList = state.getStatus();
    if (CollectionUtils.isNotEmpty(statusMatchList)) {
        if (state.isAsync()) {
            if (LOGGER.isWarnEnabled()) {
                LOGGER.warn("Service[{}.{}] is execute asynchronously, null return value collected, so user defined " + "Status Matching skipped. stateName: {}, branchId: {}", state.getServiceName(), state.getServiceMethod(), state.getName(), stateInstance.getId());
            }
        } else {
            StateMachineConfig stateMachineConfig = (StateMachineConfig) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONFIG);
            Map<Object, String> statusEvaluators = state.getStatusEvaluators();
            if (statusEvaluators == null) {
                synchronized (state) {
                    statusEvaluators = state.getStatusEvaluators();
                    if (statusEvaluators == null) {
                        statusEvaluators = new LinkedHashMap<>(statusMatchList.size());
                        String expressionStr, statusVal;
                        Evaluator evaluator;
                        for (Map.Entry<String, String> entry : statusMatchList.entrySet()) {
                            expressionStr = entry.getKey();
                            statusVal = entry.getValue();
                            evaluator = createEvaluator(stateMachineConfig.getEvaluatorFactoryManager(), expressionStr);
                            if (evaluator != null) {
                                statusEvaluators.put(evaluator, statusVal);
                            }
                        }
                    }
                    state.setStatusEvaluators(statusEvaluators);
                }
            }
            for (Object evaluatorObj : statusEvaluators.keySet()) {
                Evaluator evaluator = (Evaluator) evaluatorObj;
                String statusVal = statusEvaluators.get(evaluator);
                if (evaluator.evaluate(context.getVariables())) {
                    stateInstance.setStatus(ExecutionStatus.valueOf(statusVal));
                    break;
                }
            }
            if (exp == null && (stateInstance.getStatus() == null || ExecutionStatus.RU.equals(stateInstance.getStatus()))) {
                if (state.isForUpdate()) {
                    stateInstance.setStatus(ExecutionStatus.UN);
                } else {
                    stateInstance.setStatus(ExecutionStatus.FA);
                }
                stateInstance.setGmtEnd(new Date());
                StateMachineInstance stateMachineInstance = stateInstance.getStateMachineInstance();
                if (stateMachineInstance.getStateMachine().isPersist() && state.isPersist() && stateMachineConfig.getStateLogStore() != null) {
                    stateMachineConfig.getStateLogStore().recordStateFinished(stateInstance, context);
                }
                EngineExecutionException exception = new EngineExecutionException("State [" + state.getName() + "] execute finished, but cannot matching status, pls check its status manually", FrameworkErrorCode.NoMatchedStatus);
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug("State[{}] execute finish with status[{}]", state.getName(), stateInstance.getStatus());
                }
                EngineUtils.failStateMachine(context, exception);
                throw exception;
            }
        }
    }
    if (stateInstance.getStatus() == null || ExecutionStatus.RU.equals(stateInstance.getStatus())) {
        if (exp == null) {
            stateInstance.setStatus(ExecutionStatus.SU);
        } else {
            if (state.isForUpdate() || state.isForCompensation()) {
                stateInstance.setStatus(ExecutionStatus.UN);
                ExceptionUtils.NetExceptionType t = ExceptionUtils.getNetExceptionType(exp);
                if (t != null) {
                    if (t.equals(ExceptionUtils.NetExceptionType.CONNECT_EXCEPTION)) {
                        stateInstance.setStatus(ExecutionStatus.FA);
                    } else if (t.equals(ExceptionUtils.NetExceptionType.READ_TIMEOUT_EXCEPTION)) {
                        stateInstance.setStatus(ExecutionStatus.UN);
                    }
                } else {
                    stateInstance.setStatus(ExecutionStatus.UN);
                }
            } else {
                stateInstance.setStatus(ExecutionStatus.FA);
            }
        }
    }
    if (LOGGER.isInfoEnabled()) {
        LOGGER.info("State[{}] finish with status[{}]", state.getName(), stateInstance.getStatus());
    }
}
Also used : ExceptionUtils(io.seata.saga.engine.utils.ExceptionUtils) ExpressionEvaluator(io.seata.saga.engine.evaluation.expression.ExpressionEvaluator) Evaluator(io.seata.saga.engine.evaluation.Evaluator) EngineExecutionException(io.seata.saga.engine.exception.EngineExecutionException) Date(java.util.Date) StateMachineInstance(io.seata.saga.statelang.domain.StateMachineInstance) StateMachineConfig(io.seata.saga.engine.StateMachineConfig) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map)

Example 13 with StateMachineConfig

use of io.seata.saga.engine.StateMachineConfig 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 14 with StateMachineConfig

use of io.seata.saga.engine.StateMachineConfig 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)

Example 15 with StateMachineConfig

use of io.seata.saga.engine.StateMachineConfig 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)

Aggregations

StateMachineConfig (io.seata.saga.engine.StateMachineConfig)24 StateMachineInstance (io.seata.saga.statelang.domain.StateMachineInstance)15 EngineExecutionException (io.seata.saga.engine.exception.EngineExecutionException)14 StateInstruction (io.seata.saga.engine.pcext.StateInstruction)11 StateInstance (io.seata.saga.statelang.domain.StateInstance)8 Map (java.util.Map)8 DbStateMachineConfig (io.seata.saga.engine.config.DbStateMachineConfig)5 DefaultStateMachineConfig (io.seata.saga.engine.impl.DefaultStateMachineConfig)5 HierarchicalProcessContext (io.seata.saga.proctrl.HierarchicalProcessContext)5 ArrayList (java.util.ArrayList)5 Date (java.util.Date)5 ScriptTaskStateImpl (io.seata.saga.statelang.domain.impl.ScriptTaskStateImpl)3 ServiceTaskStateImpl (io.seata.saga.statelang.domain.impl.ServiceTaskStateImpl)3 GlobalTransaction (io.seata.tm.api.GlobalTransaction)3 ExecutionException (io.seata.tm.api.TransactionalExecutor.ExecutionException)3 LinkedHashMap (java.util.LinkedHashMap)3 List (java.util.List)3 TransactionException (io.seata.core.exception.TransactionException)2 AsyncCallback (io.seata.saga.engine.AsyncCallback)2 ExpressionEvaluator (io.seata.saga.engine.evaluation.expression.ExpressionEvaluator)2