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);
}
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();
}
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;
}
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;
}
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);
}
}
Aggregations