use of io.seata.saga.statelang.domain.TaskState.Loop 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.TaskState.Loop 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);
}
}
use of io.seata.saga.statelang.domain.TaskState.Loop in project seata by seata.
the class LoopTaskUtils method reloadLoopContext.
/**
* reload loop counter context while forward
*
* @param context
* @param forwardStateName
*/
public static void reloadLoopContext(ProcessContext context, String forwardStateName) {
StateMachineInstance stateMachineInstance = (StateMachineInstance) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_INST);
List<StateInstance> actList = stateMachineInstance.getStateList();
List<StateInstance> forwardStateList = actList.stream().filter(e -> forwardStateName.equals(EngineUtils.getOriginStateName(e))).collect(Collectors.toList());
LoopContextHolder loopContextHolder = LoopContextHolder.getCurrent(context, true);
Collection collection = loopContextHolder.getCollection();
LinkedList<Integer> list = new LinkedList<>();
for (int i = 0; i < collection.size(); i++) {
list.addFirst(i);
}
int executedNumber = 0;
LinkedList<Integer> failEndList = new LinkedList<>();
for (StateInstance stateInstance : forwardStateList) {
if (!stateInstance.isIgnoreStatus()) {
if (ExecutionStatus.SU.equals(stateInstance.getStatus())) {
executedNumber += 1;
} else {
stateInstance.setIgnoreStatus(true);
failEndList.addFirst(reloadLoopCounter(stateInstance.getName()));
}
list.remove(Integer.valueOf(reloadLoopCounter(stateInstance.getName())));
}
}
loopContextHolder.getLoopCounterStack().addAll(list);
loopContextHolder.getForwardCounterStack().addAll(failEndList);
loopContextHolder.getNrOfInstances().set(collection.size());
loopContextHolder.getNrOfCompletedInstances().set(executedNumber);
}
use of io.seata.saga.statelang.domain.TaskState.Loop in project seata by seata.
the class ProcessCtrlStateMachineEngine method forwardInternal.
protected StateMachineInstance forwardInternal(String stateMachineInstId, Map<String, Object> replaceParams, boolean skip, boolean async, AsyncCallback callback) throws EngineExecutionException {
StateMachineInstance stateMachineInstance = reloadStateMachineInstance(stateMachineInstId);
if (stateMachineInstance == null) {
throw new ForwardInvalidException("StateMachineInstance is not exits", FrameworkErrorCode.StateMachineInstanceNotExists);
}
if (ExecutionStatus.SU.equals(stateMachineInstance.getStatus()) && stateMachineInstance.getCompensationStatus() == null) {
return stateMachineInstance;
}
ExecutionStatus[] acceptStatus = new ExecutionStatus[] { ExecutionStatus.FA, ExecutionStatus.UN, ExecutionStatus.RU };
checkStatus(stateMachineInstance, acceptStatus, null, stateMachineInstance.getStatus(), null, "forward");
List<StateInstance> actList = stateMachineInstance.getStateList();
if (CollectionUtils.isEmpty(actList)) {
throw new ForwardInvalidException("StateMachineInstance[id:" + stateMachineInstId + "] has no stateInstance, pls start a new StateMachine execution instead", FrameworkErrorCode.OperationDenied);
}
StateInstance lastForwardState = findOutLastForwardStateInstance(actList);
if (lastForwardState == null) {
throw new ForwardInvalidException("StateMachineInstance[id:" + stateMachineInstId + "] Cannot find last forward execution stateInstance", FrameworkErrorCode.OperationDenied);
}
ProcessContextBuilder contextBuilder = ProcessContextBuilder.create().withProcessType(ProcessType.STATE_LANG).withOperationName(DomainConstants.OPERATION_NAME_FORWARD).withAsyncCallback(callback).withStateMachineInstance(stateMachineInstance).withStateInstance(lastForwardState).withStateMachineConfig(getStateMachineConfig()).withStateMachineEngine(this);
contextBuilder.withIsAsyncExecution(async);
ProcessContext context = contextBuilder.build();
Map<String, Object> contextVariables = getStateMachineContextVariables(stateMachineInstance);
if (replaceParams != null) {
contextVariables.putAll(replaceParams);
}
putBusinesskeyToContextariables(stateMachineInstance, contextVariables);
ConcurrentHashMap<String, Object> concurrentContextVariables = new ConcurrentHashMap<>(contextVariables.size());
nullSafeCopy(contextVariables, concurrentContextVariables);
context.setVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONTEXT, concurrentContextVariables);
stateMachineInstance.setContext(concurrentContextVariables);
String originStateName = EngineUtils.getOriginStateName(lastForwardState);
State lastState = stateMachineInstance.getStateMachine().getState(originStateName);
Loop loop = LoopTaskUtils.getLoopConfig(context, lastState);
if (null != loop && ExecutionStatus.SU.equals(lastForwardState.getStatus())) {
lastForwardState = LoopTaskUtils.findOutLastNeedForwardStateInstance(context);
}
context.setVariable(lastForwardState.getName() + DomainConstants.VAR_NAME_RETRIED_STATE_INST_ID, lastForwardState.getId());
if (DomainConstants.STATE_TYPE_SUB_STATE_MACHINE.equals(lastForwardState.getType()) && !ExecutionStatus.SU.equals(lastForwardState.getCompensationStatus())) {
context.setVariable(DomainConstants.VAR_NAME_IS_FOR_SUB_STATMACHINE_FORWARD, true);
}
if (!ExecutionStatus.SU.equals(lastForwardState.getStatus())) {
lastForwardState.setIgnoreStatus(true);
}
try {
StateInstruction inst = new StateInstruction();
inst.setTenantId(stateMachineInstance.getTenantId());
inst.setStateMachineName(stateMachineInstance.getStateMachine().getName());
if (skip || ExecutionStatus.SU.equals(lastForwardState.getStatus())) {
String next = null;
State state = stateMachineInstance.getStateMachine().getState(EngineUtils.getOriginStateName(lastForwardState));
if (state != null && state instanceof AbstractTaskState) {
next = ((AbstractTaskState) state).getNext();
}
if (StringUtils.isEmpty(next)) {
LOGGER.warn("Last Forward execution StateInstance was succeed, and it has not Next State , skip forward " + "operation");
return stateMachineInstance;
}
inst.setStateName(next);
} else {
if (ExecutionStatus.RU.equals(lastForwardState.getStatus()) && !EngineUtils.isTimeout(lastForwardState.getGmtStarted(), stateMachineConfig.getServiceInvokeTimeout())) {
throw new EngineExecutionException("State [" + lastForwardState.getName() + "] is running, operation[forward] denied", FrameworkErrorCode.OperationDenied);
}
inst.setStateName(EngineUtils.getOriginStateName(lastForwardState));
}
context.setInstruction(inst);
stateMachineInstance.setStatus(ExecutionStatus.RU);
stateMachineInstance.setRunning(true);
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Operation [forward] started stateMachineInstance[id:" + stateMachineInstance.getId() + "]");
}
if (stateMachineInstance.getStateMachine().isPersist()) {
stateMachineConfig.getStateLogStore().recordStateMachineRestarted(stateMachineInstance, context);
}
loop = LoopTaskUtils.getLoopConfig(context, inst.getState(context));
if (null != loop) {
inst.setTemporaryState(new LoopStartStateImpl());
}
if (async) {
stateMachineConfig.getAsyncProcessCtrlEventPublisher().publish(context);
} else {
stateMachineConfig.getProcessCtrlEventPublisher().publish(context);
}
} catch (EngineExecutionException e) {
LOGGER.error("Operation [forward] failed", e);
throw e;
}
return stateMachineInstance;
}
use of io.seata.saga.statelang.domain.TaskState.Loop in project seata by seata.
the class ProcessCtrlStateMachineEngine method startInternal.
private StateMachineInstance startInternal(String stateMachineName, String tenantId, String businessKey, Map<String, Object> startParams, boolean async, AsyncCallback callback) throws EngineExecutionException {
if (async && !stateMachineConfig.isEnableAsync()) {
throw new EngineExecutionException("Asynchronous start is disabled. please set StateMachineConfig.enableAsync=true first.", FrameworkErrorCode.AsynchronousStartDisabled);
}
if (StringUtils.isEmpty(tenantId)) {
tenantId = stateMachineConfig.getDefaultTenantId();
}
StateMachineInstance instance = createMachineInstance(stateMachineName, tenantId, businessKey, startParams);
ProcessContextBuilder contextBuilder = ProcessContextBuilder.create().withProcessType(ProcessType.STATE_LANG).withOperationName(DomainConstants.OPERATION_NAME_START).withAsyncCallback(callback).withInstruction(new StateInstruction(stateMachineName, tenantId)).withStateMachineInstance(instance).withStateMachineConfig(getStateMachineConfig()).withStateMachineEngine(this);
Map<String, Object> contextVariables;
if (startParams != null) {
contextVariables = new ConcurrentHashMap<>(startParams.size());
nullSafeCopy(startParams, contextVariables);
} else {
contextVariables = new ConcurrentHashMap<>();
}
instance.setContext(contextVariables);
contextBuilder.withStateMachineContextVariables(contextVariables);
contextBuilder.withIsAsyncExecution(async);
ProcessContext processContext = contextBuilder.build();
if (instance.getStateMachine().isPersist() && stateMachineConfig.getStateLogStore() != null) {
stateMachineConfig.getStateLogStore().recordStateMachineStarted(instance, processContext);
}
if (StringUtils.isEmpty(instance.getId())) {
instance.setId(stateMachineConfig.getSeqGenerator().generate(DomainConstants.SEQ_ENTITY_STATE_MACHINE_INST));
}
StateInstruction stateInstruction = processContext.getInstruction(StateInstruction.class);
Loop loop = LoopTaskUtils.getLoopConfig(processContext, stateInstruction.getState(processContext));
if (null != loop) {
stateInstruction.setTemporaryState(new LoopStartStateImpl());
}
if (async) {
stateMachineConfig.getAsyncProcessCtrlEventPublisher().publish(processContext);
} else {
stateMachineConfig.getProcessCtrlEventPublisher().publish(processContext);
}
return instance;
}
Aggregations