use of io.seata.saga.statelang.domain.StateInstance in project seata by seata.
the class TaskStateRouter method compensateRoute.
private Instruction compensateRoute(ProcessContext context, State compensationTriggerState) {
// and the compensation process is interrupted.
if (Boolean.TRUE.equals(context.getVariable(DomainConstants.VAR_NAME_FIRST_COMPENSATION_STATE_STARTED))) {
Exception exception = (Exception) context.getVariable(DomainConstants.VAR_NAME_CURRENT_EXCEPTION);
if (exception != null) {
EngineUtils.endStateMachine(context);
return null;
}
StateInstance stateInstance = (StateInstance) context.getVariable(DomainConstants.VAR_NAME_STATE_INST);
if (stateInstance != null && (!ExecutionStatus.SU.equals(stateInstance.getStatus()))) {
EngineUtils.endStateMachine(context);
return null;
}
}
Stack<StateInstance> stateStackToBeCompensated = CompensationHolder.getCurrent(context, true).getStateStackNeedCompensation();
if (!stateStackToBeCompensated.isEmpty()) {
StateInstance stateToBeCompensated = stateStackToBeCompensated.pop();
StateMachine stateMachine = (StateMachine) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE);
State state = stateMachine.getState(EngineUtils.getOriginStateName(stateToBeCompensated));
if (state != null && state instanceof AbstractTaskState) {
AbstractTaskState taskState = (AbstractTaskState) state;
StateInstruction instruction = context.getInstruction(StateInstruction.class);
State compensateState = null;
String compensateStateName = taskState.getCompensateState();
if (StringUtils.hasLength(compensateStateName)) {
compensateState = stateMachine.getState(compensateStateName);
}
if (compensateState == null && (taskState instanceof SubStateMachine)) {
compensateState = ((SubStateMachine) taskState).getCompensateStateObject();
instruction.setTemporaryState(compensateState);
}
if (compensateState == null) {
EngineUtils.endStateMachine(context);
return null;
}
instruction.setStateName(compensateState.getName());
CompensationHolder.getCurrent(context, true).addToBeCompensatedState(compensateState.getName(), stateToBeCompensated);
((HierarchicalProcessContext) context).setVariableLocally(DomainConstants.VAR_NAME_FIRST_COMPENSATION_STATE_STARTED, true);
if (compensateState instanceof CompensateSubStateMachineState) {
((HierarchicalProcessContext) context).setVariableLocally(compensateState.getName() + DomainConstants.VAR_NAME_SUB_MACHINE_PARENT_ID, EngineUtils.generateParentId(stateToBeCompensated));
}
return instruction;
}
}
context.removeVariable(DomainConstants.VAR_NAME_CURRENT_COMPEN_TRIGGER_STATE);
String compensationTriggerStateNext = compensationTriggerState.getNext();
if (StringUtils.isEmpty(compensationTriggerStateNext)) {
EngineUtils.endStateMachine(context);
return null;
}
StateInstruction instruction = context.getInstruction(StateInstruction.class);
instruction.setStateName(compensationTriggerStateNext);
return instruction;
}
use of io.seata.saga.statelang.domain.StateInstance 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.StateInstance 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);
}
}
use of io.seata.saga.statelang.domain.StateInstance in project seata by seata.
the class LoopTaskHandlerInterceptor method postProcess.
@Override
public void postProcess(ProcessContext context, Exception e) throws EngineExecutionException {
if (context.hasVariable(DomainConstants.VAR_NAME_IS_LOOP_STATE)) {
StateInstance stateInstance = (StateInstance) context.getVariable(DomainConstants.VAR_NAME_STATE_INST);
if (null != stateInstance && !LoopContextHolder.getCurrent(context, true).isFailEnd()) {
if (!ExecutionStatus.SU.equals(stateInstance.getStatus())) {
LoopContextHolder.getCurrent(context, true).setFailEnd(true);
}
}
Exception exp = (Exception) ((HierarchicalProcessContext) context).getVariableLocally(DomainConstants.VAR_NAME_CURRENT_EXCEPTION);
if (exp == null) {
exp = e;
}
if (null != e) {
if (context.hasVariable(DomainConstants.LOOP_SEMAPHORE)) {
Semaphore semaphore = (Semaphore) context.getVariable(DomainConstants.LOOP_SEMAPHORE);
semaphore.release();
}
}
if (null != exp) {
LoopContextHolder.getCurrent(context, true).setFailEnd(true);
} else {
LoopContextHolder.getCurrent(context, true).getNrOfCompletedInstances().incrementAndGet();
}
LoopContextHolder.getCurrent(context, true).getNrOfActiveInstances().decrementAndGet();
}
}
use of io.seata.saga.statelang.domain.StateInstance in project seata by seata.
the class DesignerJsonTransformer method generateTracingGraphJson.
/**
* Generate tracing graph json
* @param stateMachineInstance
* @return
*/
public static String generateTracingGraphJson(StateMachineInstance stateMachineInstance, JsonParser jsonParser) {
if (stateMachineInstance == null) {
throw new FrameworkException("StateMachineInstance is not exits", FrameworkErrorCode.StateMachineInstanceNotExists);
}
String stateMachineJson = stateMachineInstance.getStateMachine().getContent();
if (StringUtils.isEmpty(stateMachineJson)) {
throw new FrameworkException("Cannot get StateMachine Json", FrameworkErrorCode.ObjectNotExists);
}
Map<String, Object> stateMachineJsonObj = jsonParser.parse(stateMachineJson, Map.class, true);
if (!DesignerJsonTransformer.isDesignerJson(stateMachineJsonObj)) {
throw new FrameworkException("StateMachine Json is not generated by Designer", FrameworkErrorCode.InvalidConfiguration);
}
Map<String, List<StateInstance>> stateInstanceMapGroupByName = new HashMap<>(stateMachineInstance.getStateMap().size());
for (StateInstance stateInstance : stateMachineInstance.getStateMap().values()) {
CollectionUtils.computeIfAbsent(stateInstanceMapGroupByName, stateInstance.getName(), key -> new ArrayList<>()).add(stateInstance);
}
List<Object> nodesArray = (List<Object>) stateMachineJsonObj.get("nodes");
for (Object nodeObj : nodesArray) {
Map<String, Object> node = (Map<String, Object>) nodeObj;
String stateId = (String) node.get("stateId");
String stateType = (String) node.get("stateType");
if ("ServiceTask".equals(stateType) || "SubStateMachine".equals(stateType) || "Compensation".equals(stateType)) {
node.remove("color");
}
List<StateInstance> stateInstanceList = stateInstanceMapGroupByName.get(stateId);
if (CollectionUtils.isNotEmpty(stateInstanceList)) {
StateInstance stateInstance = null;
if (stateInstanceList.size() == 1) {
stateInstance = stateInstanceList.get(0);
} else {
// find out latest stateInstance
for (StateInstance stateInst : stateInstanceList) {
if (stateInstance == null || stateInst.getGmtStarted().after(stateInstance.getGmtStarted())) {
stateInstance = stateInst;
}
}
}
node.put("stateInstanceId", stateInstance.getId());
node.put("stateInstanceStatus", stateInstance.getStatus());
if (ExecutionStatus.SU.equals(stateInstance.getStatus())) {
node.put("color", "green");
Map<String, Object> style = new LinkedHashMap<>();
style.put("fill", "#00D73E");
style.put("lineWidth", 2);
node.put("style", style);
} else {
node.put("color", "red");
Map<String, Object> style = new LinkedHashMap<>();
style.put("fill", "#FF7777");
style.put("lineWidth", 2);
node.put("style", style);
}
}
}
if (stateMachineJsonObj != null) {
return jsonParser.toJsonString(stateMachineJsonObj, true);
}
return "";
}
Aggregations