Search in sources :

Example 16 with StateMachineConfig

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

the class ServiceTaskStateHandler method compensateSubStateMachine.

private Object compensateSubStateMachine(ProcessContext context, ServiceTaskState state, Object input, StateInstance stateInstance, StateMachineEngine engine) {
    String subStateMachineParentId = (String) context.getVariable(state.getName() + DomainConstants.VAR_NAME_SUB_MACHINE_PARENT_ID);
    if (StringUtils.isEmpty(subStateMachineParentId)) {
        throw new EngineExecutionException("sub statemachine parentId is required", FrameworkErrorCode.ObjectNotExists);
    }
    StateMachineConfig stateMachineConfig = (StateMachineConfig) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONFIG);
    List<StateMachineInstance> subInst = stateMachineConfig.getStateLogStore().queryStateMachineInstanceByParentId(subStateMachineParentId);
    if (CollectionUtils.isEmpty(subInst)) {
        throw new EngineExecutionException("cannot find sub statemachine instance by parentId:" + subStateMachineParentId, FrameworkErrorCode.ObjectNotExists);
    }
    String subStateMachineInstId = subInst.get(0).getId();
    if (LOGGER.isDebugEnabled()) {
        LOGGER.debug(">>>>>>>>>>>>>>>>>>>>>> Start to compensate sub statemachine [id:{}]", subStateMachineInstId);
    }
    Map<String, Object> startParams = new HashMap<>(0);
    if (input instanceof List) {
        List<Object> listInputParams = (List<Object>) input;
        if (listInputParams.size() > 0) {
            startParams = (Map<String, Object>) listInputParams.get(0);
        }
    } else if (input instanceof Map) {
        startParams = (Map<String, Object>) input;
    }
    StateMachineInstance compensateInst = engine.compensate(subStateMachineInstId, startParams);
    stateInstance.setStatus(compensateInst.getCompensationStatus());
    if (LOGGER.isDebugEnabled()) {
        LOGGER.debug("<<<<<<<<<<<<<<<<<<<<<< Compensate sub statemachine [id:{}] finished with status[{}], " + "compensateState[{}]", subStateMachineInstId, compensateInst.getStatus(), compensateInst.getCompensationStatus());
    }
    return compensateInst.getEndParams();
}
Also used : HashMap(java.util.HashMap) StateMachineConfig(io.seata.saga.engine.StateMachineConfig) ArrayList(java.util.ArrayList) List(java.util.List) EngineExecutionException(io.seata.saga.engine.exception.EngineExecutionException) HashMap(java.util.HashMap) Map(java.util.Map) StateMachineInstance(io.seata.saga.statelang.domain.StateMachineInstance)

Example 17 with StateMachineConfig

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

the class DbAndReportTcStateLogStore method branchRegister.

protected void branchRegister(StateInstance stateInstance, ProcessContext context) {
    if (sagaTransactionalTemplate != null) {
        StateMachineConfig stateMachineConfig = (StateMachineConfig) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONFIG);
        if (stateMachineConfig instanceof DbStateMachineConfig && !((DbStateMachineConfig) stateMachineConfig).isSagaBranchRegisterEnable()) {
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("sagaBranchRegisterEnable = false, skip register branch. state[" + stateInstance.getName() + "]");
            }
            return;
        }
        // Register branch
        try {
            StateMachineInstance machineInstance = stateInstance.getStateMachineInstance();
            GlobalTransaction globalTransaction = getGlobalTransaction(machineInstance, context);
            if (globalTransaction == null) {
                throw new EngineExecutionException("Global transaction is not exists", FrameworkErrorCode.ObjectNotExists);
            }
            String resourceId = stateInstance.getStateMachineInstance().getStateMachine().getName() + "#" + stateInstance.getName();
            long branchId = sagaTransactionalTemplate.branchRegister(resourceId, null, globalTransaction.getXid(), null, null);
            stateInstance.setId(String.valueOf(branchId));
        } catch (TransactionException e) {
            throw new EngineExecutionException(e, "Branch transaction error: " + e.getCode() + ", StateMachine:" + stateInstance.getStateMachineInstance().getStateMachine().getName() + ", XID: " + stateInstance.getStateMachineInstance().getId() + ", State:" + stateInstance.getName() + ", stateId: " + stateInstance.getId() + ", Reason: " + e.getMessage(), FrameworkErrorCode.TransactionManagerError);
        } catch (ExecutionException e) {
            throw new EngineExecutionException(e, "Branch transaction error: " + e.getCode() + ", StateMachine:" + stateInstance.getStateMachineInstance().getStateMachine().getName() + ", XID: " + stateInstance.getStateMachineInstance().getId() + ", State:" + stateInstance.getName() + ", stateId: " + stateInstance.getId() + ", Reason: " + e.getMessage(), FrameworkErrorCode.TransactionManagerError);
        }
    }
}
Also used : TransactionException(io.seata.core.exception.TransactionException) GlobalTransaction(io.seata.tm.api.GlobalTransaction) DbStateMachineConfig(io.seata.saga.engine.config.DbStateMachineConfig) DefaultStateMachineConfig(io.seata.saga.engine.impl.DefaultStateMachineConfig) StateMachineConfig(io.seata.saga.engine.StateMachineConfig) EngineExecutionException(io.seata.saga.engine.exception.EngineExecutionException) ExecutionException(io.seata.tm.api.TransactionalExecutor.ExecutionException) EngineExecutionException(io.seata.saga.engine.exception.EngineExecutionException) DbStateMachineConfig(io.seata.saga.engine.config.DbStateMachineConfig) StateMachineInstance(io.seata.saga.statelang.domain.StateMachineInstance)

Example 18 with StateMachineConfig

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

the class DbAndReportTcStateLogStore method branchReport.

protected void branchReport(StateInstance stateInstance, ProcessContext context) {
    if (sagaTransactionalTemplate != null) {
        StateMachineConfig stateMachineConfig = (StateMachineConfig) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONFIG);
        if (stateMachineConfig instanceof DbStateMachineConfig && !((DbStateMachineConfig) stateMachineConfig).isSagaBranchRegisterEnable()) {
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("sagaBranchRegisterEnable = false, skip branch report. state[" + stateInstance.getName() + "]");
            }
            return;
        }
        BranchStatus branchStatus = null;
        // find out the original state instance, only the original state instance is registered on the server, and its status should
        // be reported.
        StateInstance originalStateInst = null;
        if (StringUtils.hasLength(stateInstance.getStateIdRetriedFor())) {
            if (isUpdateMode(stateInstance, context)) {
                originalStateInst = stateInstance;
            } else {
                originalStateInst = findOutOriginalStateInstanceOfRetryState(stateInstance);
            }
            if (ExecutionStatus.SU.equals(stateInstance.getStatus())) {
                branchStatus = BranchStatus.PhaseTwo_Committed;
            } else if (ExecutionStatus.FA.equals(stateInstance.getStatus()) || ExecutionStatus.UN.equals(stateInstance.getStatus())) {
                branchStatus = BranchStatus.PhaseOne_Failed;
            } else {
                branchStatus = BranchStatus.Unknown;
            }
        } else if (StringUtils.hasLength(stateInstance.getStateIdCompensatedFor())) {
            if (isUpdateMode(stateInstance, context)) {
                originalStateInst = stateInstance.getStateMachineInstance().getStateMap().get(stateInstance.getStateIdCompensatedFor());
            } else {
                originalStateInst = findOutOriginalStateInstanceOfCompensateState(stateInstance);
            }
        }
        if (originalStateInst == null) {
            originalStateInst = stateInstance;
        }
        if (branchStatus == null) {
            if (ExecutionStatus.SU.equals(originalStateInst.getStatus()) && originalStateInst.getCompensationStatus() == null) {
                branchStatus = BranchStatus.PhaseTwo_Committed;
            } else if (ExecutionStatus.SU.equals(originalStateInst.getCompensationStatus())) {
                branchStatus = BranchStatus.PhaseTwo_Rollbacked;
            } else if (ExecutionStatus.FA.equals(originalStateInst.getCompensationStatus()) || ExecutionStatus.UN.equals(originalStateInst.getCompensationStatus())) {
                branchStatus = BranchStatus.PhaseTwo_RollbackFailed_Retryable;
            } else if ((ExecutionStatus.FA.equals(originalStateInst.getStatus()) || ExecutionStatus.UN.equals(originalStateInst.getStatus())) && originalStateInst.getCompensationStatus() == null) {
                branchStatus = BranchStatus.PhaseOne_Failed;
            } else {
                branchStatus = BranchStatus.Unknown;
            }
        }
        try {
            StateMachineInstance machineInstance = stateInstance.getStateMachineInstance();
            GlobalTransaction globalTransaction = getGlobalTransaction(machineInstance, context);
            if (globalTransaction == null) {
                throw new EngineExecutionException("Global transaction is not exists", FrameworkErrorCode.ObjectNotExists);
            }
            sagaTransactionalTemplate.branchReport(globalTransaction.getXid(), Long.parseLong(originalStateInst.getId()), branchStatus, null);
        } catch (TransactionException e) {
            LOGGER.error("Report branch status to server error: {}, StateMachine:{}, StateName:{}, XID: {}, branchId: {}, branchStatus:{}," + " Reason:{} ", e.getCode(), originalStateInst.getStateMachineInstance().getStateMachine().getName(), originalStateInst.getName(), originalStateInst.getStateMachineInstance().getId(), originalStateInst.getId(), branchStatus, e.getMessage(), e);
        } catch (ExecutionException e) {
            LOGGER.error("Report branch status to server error: {}, StateMachine:{}, StateName:{}, XID: {}, branchId: {}, branchStatus:{}," + " Reason:{} ", e.getCode(), originalStateInst.getStateMachineInstance().getStateMachine().getName(), originalStateInst.getName(), originalStateInst.getStateMachineInstance().getId(), originalStateInst.getId(), branchStatus, e.getMessage(), e);
        }
    }
}
Also used : TransactionException(io.seata.core.exception.TransactionException) GlobalTransaction(io.seata.tm.api.GlobalTransaction) DbStateMachineConfig(io.seata.saga.engine.config.DbStateMachineConfig) DefaultStateMachineConfig(io.seata.saga.engine.impl.DefaultStateMachineConfig) StateMachineConfig(io.seata.saga.engine.StateMachineConfig) BranchStatus(io.seata.core.model.BranchStatus) EngineExecutionException(io.seata.saga.engine.exception.EngineExecutionException) ExecutionException(io.seata.tm.api.TransactionalExecutor.ExecutionException) EngineExecutionException(io.seata.saga.engine.exception.EngineExecutionException) DbStateMachineConfig(io.seata.saga.engine.config.DbStateMachineConfig) StateInstance(io.seata.saga.statelang.domain.StateInstance) StateMachineInstance(io.seata.saga.statelang.domain.StateMachineInstance)

Example 19 with StateMachineConfig

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

the class DbAndReportTcStateLogStore method recordStateMachineFinished.

@Override
public void recordStateMachineFinished(StateMachineInstance machineInstance, ProcessContext context) {
    if (machineInstance != null) {
        try {
            // save to db
            Map<String, Object> endParams = machineInstance.getEndParams();
            if (endParams != null) {
                endParams.remove(DomainConstants.VAR_NAME_GLOBAL_TX);
            }
            // if success, clear exception
            if (ExecutionStatus.SU.equals(machineInstance.getStatus()) && machineInstance.getException() != null) {
                machineInstance.setException(null);
            }
            machineInstance.setSerializedEndParams(paramsSerializer.serialize(machineInstance.getEndParams()));
            machineInstance.setSerializedException(exceptionSerializer.serialize(machineInstance.getException()));
            int effect = executeUpdate(stateLogStoreSqls.getRecordStateMachineFinishedSql(dbType), STATE_MACHINE_INSTANCE_TO_STATEMENT_FOR_UPDATE, machineInstance);
            if (effect < 1) {
                LOGGER.warn("StateMachineInstance[{}] is recovery by server, skip recordStateMachineFinished.", machineInstance.getId());
            } else {
                StateMachineConfig stateMachineConfig = (StateMachineConfig) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONFIG);
                if (EngineUtils.isTimeout(machineInstance.getGmtUpdated(), stateMachineConfig.getTransOperationTimeout())) {
                    LOGGER.warn("StateMachineInstance[{}] is execution timeout, skip report transaction finished to server.", machineInstance.getId());
                } else if (StringUtils.isEmpty(machineInstance.getParentId())) {
                    // if parentId is not null, machineInstance is a SubStateMachine, do not report global transaction.
                    reportTransactionFinished(machineInstance, context);
                }
            }
        } finally {
            RootContext.unbind();
            RootContext.unbindBranchType();
        }
    }
}
Also used : DbStateMachineConfig(io.seata.saga.engine.config.DbStateMachineConfig) DefaultStateMachineConfig(io.seata.saga.engine.impl.DefaultStateMachineConfig) StateMachineConfig(io.seata.saga.engine.StateMachineConfig)

Example 20 with StateMachineConfig

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

the class StateMachineProcessRouter method route.

@Override
public Instruction route(ProcessContext context) throws FrameworkException {
    StateInstruction stateInstruction = context.getInstruction(StateInstruction.class);
    State state;
    if (stateInstruction.getTemporaryState() != null) {
        state = stateInstruction.getTemporaryState();
        stateInstruction.setTemporaryState(null);
    } else {
        StateMachineConfig stateMachineConfig = (StateMachineConfig) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONFIG);
        StateMachine stateMachine = stateMachineConfig.getStateMachineRepository().getStateMachine(stateInstruction.getStateMachineName(), stateInstruction.getTenantId());
        state = stateMachine.getStates().get(stateInstruction.getStateName());
    }
    String stateType = state.getType();
    StateRouter router = stateRouters.get(stateType);
    Instruction instruction = null;
    List<StateRouterInterceptor> interceptors = null;
    if (router instanceof InterceptableStateRouter) {
        interceptors = ((InterceptableStateRouter) router).getInterceptors();
    }
    List<StateRouterInterceptor> executedInterceptors = null;
    Exception exception = null;
    try {
        if (CollectionUtils.isNotEmpty(interceptors)) {
            executedInterceptors = new ArrayList<>(interceptors.size());
            for (StateRouterInterceptor interceptor : interceptors) {
                executedInterceptors.add(interceptor);
                interceptor.preRoute(context, state);
            }
        }
        instruction = router.route(context, state);
    } catch (Exception e) {
        exception = e;
        throw e;
    } finally {
        if (CollectionUtils.isNotEmpty(executedInterceptors)) {
            for (int i = executedInterceptors.size() - 1; i >= 0; i--) {
                StateRouterInterceptor interceptor = executedInterceptors.get(i);
                interceptor.postRoute(context, state, instruction, exception);
            }
        }
        // if 'Succeed' or 'Fail' State did not configured, we must end the state machine
        if (instruction == null && !stateInstruction.isEnd()) {
            EngineUtils.endStateMachine(context);
        }
    }
    return instruction;
}
Also used : TaskStateRouter(io.seata.saga.engine.pcext.routers.TaskStateRouter) EndStateRouter(io.seata.saga.engine.pcext.routers.EndStateRouter) StateMachine(io.seata.saga.statelang.domain.StateMachine) Instruction(io.seata.saga.proctrl.Instruction) FrameworkException(io.seata.common.exception.FrameworkException) State(io.seata.saga.statelang.domain.State) StateMachineConfig(io.seata.saga.engine.StateMachineConfig)

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