Search in sources :

Example 1 with AbstractTaskState

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

the class EngineUtils method handleException.

/**
 * Handle exceptions while ServiceTask or ScriptTask Executing
 *
 * @param context
 * @param state
 * @param e
 */
public static void handleException(ProcessContext context, AbstractTaskState state, Throwable e) {
    List<ExceptionMatch> catches = state.getCatches();
    if (CollectionUtils.isNotEmpty(catches)) {
        for (TaskState.ExceptionMatch exceptionMatch : catches) {
            List<String> exceptions = exceptionMatch.getExceptions();
            List<Class<? extends Exception>> exceptionClasses = exceptionMatch.getExceptionClasses();
            if (CollectionUtils.isNotEmpty(exceptions)) {
                if (exceptionClasses == null) {
                    synchronized (exceptionMatch) {
                        exceptionClasses = exceptionMatch.getExceptionClasses();
                        if (exceptionClasses == null) {
                            exceptionClasses = new ArrayList<>(exceptions.size());
                            for (String expStr : exceptions) {
                                Class<? extends Exception> expClass = null;
                                try {
                                    expClass = (Class<? extends Exception>) ScriptTaskStateHandler.class.getClassLoader().loadClass(expStr);
                                } catch (Exception e1) {
                                    LOGGER.warn("Cannot Load Exception Class by getClass().getClassLoader()", e1);
                                    try {
                                        expClass = (Class<? extends Exception>) Thread.currentThread().getContextClassLoader().loadClass(expStr);
                                    } catch (Exception e2) {
                                        LOGGER.warn("Cannot Load Exception Class by Thread.currentThread()" + ".getContextClassLoader()", e2);
                                    }
                                }
                                if (expClass != null) {
                                    exceptionClasses.add(expClass);
                                }
                            }
                            exceptionMatch.setExceptionClasses(exceptionClasses);
                        }
                    }
                }
                for (Class<? extends Exception> expClass : exceptionClasses) {
                    if (expClass.isAssignableFrom(e.getClass())) {
                        ((HierarchicalProcessContext) context).setVariableLocally(DomainConstants.VAR_NAME_CURRENT_EXCEPTION_ROUTE, exceptionMatch.getNext());
                        return;
                    }
                }
            }
        }
    }
    LOGGER.error("Task execution failed and no catches configured");
    ((HierarchicalProcessContext) context).setVariableLocally(DomainConstants.VAR_NAME_IS_EXCEPTION_NOT_CATCH, true);
}
Also used : ExceptionMatch(io.seata.saga.statelang.domain.TaskState.ExceptionMatch) HierarchicalProcessContext(io.seata.saga.proctrl.HierarchicalProcessContext) ScriptTaskStateHandler(io.seata.saga.engine.pcext.handlers.ScriptTaskStateHandler) TaskState(io.seata.saga.statelang.domain.TaskState) AbstractTaskState(io.seata.saga.statelang.domain.impl.AbstractTaskState) ExceptionMatch(io.seata.saga.statelang.domain.TaskState.ExceptionMatch)

Example 2 with AbstractTaskState

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

the class LoopTaskUtils method isCompletionConditionSatisfied.

/**
 * check if satisfied completion condition
 *
 * @param context
 * @return
 */
public static boolean isCompletionConditionSatisfied(ProcessContext context) {
    StateInstruction instruction = context.getInstruction(StateInstruction.class);
    AbstractTaskState currentState = (AbstractTaskState) instruction.getState(context);
    LoopContextHolder currentLoopContext = LoopContextHolder.getCurrent(context, true);
    if (currentLoopContext.isCompletionConditionSatisfied()) {
        return true;
    }
    int nrOfInstances = currentLoopContext.getNrOfInstances().get();
    int nrOfActiveInstances = currentLoopContext.getNrOfActiveInstances().get();
    int nrOfCompletedInstances = currentLoopContext.getNrOfCompletedInstances().get();
    if (!currentLoopContext.isCompletionConditionSatisfied()) {
        synchronized (currentLoopContext) {
            if (!currentLoopContext.isCompletionConditionSatisfied()) {
                Map<String, Object> stateMachineContext = (Map<String, Object>) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONTEXT);
                // multi-instance variables should be double/float while evaluate
                stateMachineContext.put(DomainConstants.NUMBER_OF_INSTANCES, (double) nrOfInstances);
                stateMachineContext.put(DomainConstants.NUMBER_OF_ACTIVE_INSTANCES, (double) nrOfActiveInstances);
                stateMachineContext.put(DomainConstants.NUMBER_OF_COMPLETED_INSTANCES, (double) nrOfCompletedInstances);
                if (nrOfCompletedInstances >= nrOfInstances || getEvaluator(context, currentState.getLoop().getCompletionCondition()).evaluate(stateMachineContext)) {
                    currentLoopContext.setCompletionConditionSatisfied(true);
                }
            }
        }
    }
    return currentLoopContext.isCompletionConditionSatisfied();
}
Also used : AbstractTaskState(io.seata.saga.statelang.domain.impl.AbstractTaskState) StateInstruction(io.seata.saga.engine.pcext.StateInstruction) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap)

Example 3 with AbstractTaskState

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

the class LoopTaskUtils method getLoopConfig.

/**
 * get Loop Config from State
 *
 * @param context
 * @param currentState
 * @return currentState loop config if satisfied, else {@literal null}
 */
public static Loop getLoopConfig(ProcessContext context, State currentState) {
    if (matchLoop(currentState)) {
        AbstractTaskState taskState = (AbstractTaskState) currentState;
        StateMachineInstance stateMachineInstance = (StateMachineInstance) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_INST);
        StateMachineConfig stateMachineConfig = (StateMachineConfig) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONFIG);
        if (null != taskState.getLoop()) {
            Loop loop = taskState.getLoop();
            String collectionName = loop.getCollection();
            if (StringUtils.isNotBlank(collectionName)) {
                Object expression = ParameterUtils.createValueExpression(stateMachineConfig.getExpressionFactoryManager(), collectionName);
                Object collection = ParameterUtils.getValue(expression, stateMachineInstance.getContext(), null);
                if (collection instanceof Collection && ((Collection) collection).size() > 0) {
                    LoopContextHolder.getCurrent(context, true).setCollection((Collection) collection);
                    return loop;
                }
            }
            LOGGER.warn("State [{}] loop collection param [{}] invalid", currentState.getName(), collectionName);
        }
    }
    return null;
}
Also used : AbstractTaskState(io.seata.saga.statelang.domain.impl.AbstractTaskState) Loop(io.seata.saga.statelang.domain.TaskState.Loop) Collection(java.util.Collection) StateMachineConfig(io.seata.saga.engine.StateMachineConfig) StateMachineInstance(io.seata.saga.statelang.domain.StateMachineInstance)

Example 4 with AbstractTaskState

use of io.seata.saga.statelang.domain.impl.AbstractTaskState 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)

Example 5 with AbstractTaskState

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

the class LoopTaskHandlerInterceptor method preProcess.

@Override
public void preProcess(ProcessContext context) throws EngineExecutionException {
    if (context.hasVariable(DomainConstants.VAR_NAME_IS_LOOP_STATE)) {
        StateInstruction instruction = context.getInstruction(StateInstruction.class);
        AbstractTaskState currentState = (AbstractTaskState) instruction.getState(context);
        int loopCounter;
        Loop loop;
        // get loop config
        if (context.hasVariable(DomainConstants.VAR_NAME_CURRENT_COMPEN_TRIGGER_STATE)) {
            // compensate condition should get stateToBeCompensated 's config
            CompensationHolder compensationHolder = CompensationHolder.getCurrent(context, true);
            StateInstance stateToBeCompensated = compensationHolder.getStatesNeedCompensation().get(currentState.getName());
            AbstractTaskState compensateState = (AbstractTaskState) stateToBeCompensated.getStateMachineInstance().getStateMachine().getState(EngineUtils.getOriginStateName(stateToBeCompensated));
            loop = compensateState.getLoop();
            loopCounter = LoopTaskUtils.reloadLoopCounter(stateToBeCompensated.getName());
        } else {
            loop = currentState.getLoop();
            loopCounter = (int) context.getVariable(DomainConstants.LOOP_COUNTER);
        }
        Collection collection = LoopContextHolder.getCurrent(context, true).getCollection();
        Map<String, Object> contextVariables = (Map<String, Object>) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONTEXT);
        Map<String, Object> copyContextVariables = new ConcurrentHashMap<>(contextVariables);
        copyContextVariables.put(loop.getElementIndexName(), loopCounter);
        copyContextVariables.put(loop.getElementVariableName(), iterator(collection, loopCounter));
        ((HierarchicalProcessContext) context).setVariableLocally(DomainConstants.VAR_NAME_STATEMACHINE_CONTEXT, copyContextVariables);
    }
}
Also used : Loop(io.seata.saga.statelang.domain.TaskState.Loop) CompensationHolder(io.seata.saga.engine.pcext.utils.CompensationHolder) StateInstruction(io.seata.saga.engine.pcext.StateInstruction) HierarchicalProcessContext(io.seata.saga.proctrl.HierarchicalProcessContext) AbstractTaskState(io.seata.saga.statelang.domain.impl.AbstractTaskState) Collection(java.util.Collection) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) Map(java.util.Map) StateInstance(io.seata.saga.statelang.domain.StateInstance)

Aggregations

AbstractTaskState (io.seata.saga.statelang.domain.impl.AbstractTaskState)8 StateInstruction (io.seata.saga.engine.pcext.StateInstruction)4 State (io.seata.saga.statelang.domain.State)4 StateInstance (io.seata.saga.statelang.domain.StateInstance)4 EngineExecutionException (io.seata.saga.engine.exception.EngineExecutionException)3 HierarchicalProcessContext (io.seata.saga.proctrl.HierarchicalProcessContext)3 StateMachineInstance (io.seata.saga.statelang.domain.StateMachineInstance)3 Loop (io.seata.saga.statelang.domain.TaskState.Loop)3 Map (java.util.Map)3 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)3 StateMachine (io.seata.saga.statelang.domain.StateMachine)2 Collection (java.util.Collection)2 StateMachineConfig (io.seata.saga.engine.StateMachineConfig)1 ForwardInvalidException (io.seata.saga.engine.exception.ForwardInvalidException)1 ScriptTaskStateHandler (io.seata.saga.engine.pcext.handlers.ScriptTaskStateHandler)1 CompensationHolder (io.seata.saga.engine.pcext.utils.CompensationHolder)1 ProcessContextBuilder (io.seata.saga.engine.utils.ProcessContextBuilder)1 ProcessContext (io.seata.saga.proctrl.ProcessContext)1 CompensateSubStateMachineState (io.seata.saga.statelang.domain.CompensateSubStateMachineState)1 ExecutionStatus (io.seata.saga.statelang.domain.ExecutionStatus)1