use of io.seata.saga.statelang.domain.StateInstance in project seata by seata.
the class ProcessCtrlStateMachineEngine method reloadStateMachineInstance.
/**
* override state machine instance
*
* @param instId
* @return
*/
@Override
public StateMachineInstance reloadStateMachineInstance(String instId) {
StateMachineInstance inst = stateMachineConfig.getStateLogStore().getStateMachineInstance(instId);
if (inst != null) {
StateMachine stateMachine = inst.getStateMachine();
if (stateMachine == null) {
stateMachine = stateMachineConfig.getStateMachineRepository().getStateMachineById(inst.getMachineId());
inst.setStateMachine(stateMachine);
}
if (stateMachine == null) {
throw new EngineExecutionException("StateMachine[id:" + inst.getMachineId() + "] not exist.", FrameworkErrorCode.ObjectNotExists);
}
List<StateInstance> stateList = inst.getStateList();
if (CollectionUtils.isEmpty(stateList)) {
stateList = stateMachineConfig.getStateLogStore().queryStateInstanceListByMachineInstanceId(instId);
if (CollectionUtils.isNotEmpty(stateList)) {
for (StateInstance tmpStateInstance : stateList) {
inst.putStateInstance(tmpStateInstance.getId(), tmpStateInstance);
}
}
}
if (CollectionUtils.isEmpty(inst.getEndParams())) {
inst.setEndParams(replayContextVariables(inst));
}
}
return inst;
}
use of io.seata.saga.statelang.domain.StateInstance in project seata by seata.
the class ProcessCtrlStateMachineEngine method findOutLastForwardStateInstance.
/**
* Find the last instance of the forward execution state
*
* @param stateInstanceList
* @return
*/
public StateInstance findOutLastForwardStateInstance(List<StateInstance> stateInstanceList) {
StateInstance lastForwardStateInstance = null;
for (int i = stateInstanceList.size() - 1; i >= 0; i--) {
StateInstance stateInstance = stateInstanceList.get(i);
if (!stateInstance.isForCompensation()) {
if (ExecutionStatus.SU.equals(stateInstance.getCompensationStatus())) {
continue;
}
if (DomainConstants.STATE_TYPE_SUB_STATE_MACHINE.equals(stateInstance.getType())) {
StateInstance finalState = stateInstance;
while (StringUtils.hasText(finalState.getStateIdRetriedFor())) {
finalState = stateMachineConfig.getStateLogStore().getStateInstance(finalState.getStateIdRetriedFor(), finalState.getMachineInstanceId());
}
List<StateMachineInstance> subInst = stateMachineConfig.getStateLogStore().queryStateMachineInstanceByParentId(EngineUtils.generateParentId(finalState));
if (CollectionUtils.isNotEmpty(subInst)) {
if (ExecutionStatus.SU.equals(subInst.get(0).getCompensationStatus())) {
continue;
}
if (ExecutionStatus.UN.equals(subInst.get(0).getCompensationStatus())) {
throw new ForwardInvalidException("Last forward execution state instance is SubStateMachine and compensation status is " + "[UN], Operation[forward] denied, stateInstanceId:" + stateInstance.getId(), FrameworkErrorCode.OperationDenied);
}
}
} else if (ExecutionStatus.UN.equals(stateInstance.getCompensationStatus())) {
throw new ForwardInvalidException("Last forward execution state instance compensation status is [UN], Operation[forward] " + "denied, stateInstanceId:" + stateInstance.getId(), FrameworkErrorCode.OperationDenied);
}
lastForwardStateInstance = stateInstance;
break;
}
}
return lastForwardStateInstance;
}
use of io.seata.saga.statelang.domain.StateInstance in project seata by seata.
the class SubStateMachineHandler method process.
@Override
public void process(ProcessContext context) throws EngineExecutionException {
StateInstruction instruction = context.getInstruction(StateInstruction.class);
SubStateMachineImpl subStateMachine = (SubStateMachineImpl) instruction.getState(context);
StateMachineEngine engine = (StateMachineEngine) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_ENGINE);
StateMachineInstance stateMachineInstance = (StateMachineInstance) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_INST);
StateInstance stateInstance = (StateInstance) context.getVariable(DomainConstants.VAR_NAME_STATE_INST);
Object inputParamsObj = context.getVariable(DomainConstants.VAR_NAME_INPUT_PARAMS);
Map<String, Object> startParams = new HashMap<>(0);
if (inputParamsObj instanceof List) {
List<Object> listInputParams = (List<Object>) inputParamsObj;
if (listInputParams.size() > 0) {
startParams = (Map<String, Object>) listInputParams.get(0);
}
} else if (inputParamsObj instanceof Map) {
startParams = (Map<String, Object>) inputParamsObj;
}
startParams.put(DomainConstants.VAR_NAME_PARENT_ID, EngineUtils.generateParentId(stateInstance));
try {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(">>>>>>>>>>>>>>>>>>>>>> Start to execute SubStateMachine [{}] by state[{}]", subStateMachine.getStateMachineName(), subStateMachine.getName());
}
StateMachineInstance subStateMachineInstance = callSubStateMachine(startParams, engine, context, stateInstance, subStateMachine);
Map<String, Object> outputParams = subStateMachineInstance.getEndParams();
boolean isForward = DomainConstants.OPERATION_NAME_FORWARD.equals(context.getVariable(DomainConstants.VAR_NAME_OPERATION_NAME));
ExecutionStatus callSubMachineStatus = decideStatus(subStateMachineInstance, isForward);
stateInstance.setStatus(callSubMachineStatus);
outputParams.put(DomainConstants.VAR_NAME_SUB_STATEMACHINE_EXEC_STATUE, callSubMachineStatus.toString());
context.setVariable(DomainConstants.VAR_NAME_OUTPUT_PARAMS, outputParams);
stateInstance.setOutputParams(outputParams);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("<<<<<<<<<<<<<<<<<<<<<< SubStateMachine[{}] execute finish with status[{}], compensateStatus[{}]", subStateMachine.getStateMachineName(), subStateMachineInstance.getStatus(), subStateMachineInstance.getCompensationStatus());
}
} catch (Exception e) {
LOGGER.error("SubStateMachine[{}] execute failed by state[name:{}]", subStateMachine.getStateMachineName(), subStateMachine.getName(), e);
if (e instanceof ForwardInvalidException) {
String retriedId = stateInstance.getStateIdRetriedFor();
StateInstance stateToBeRetried = null;
for (StateInstance stateInst : stateMachineInstance.getStateList()) {
if (retriedId.equals(stateInst.getId())) {
stateToBeRetried = stateInst;
break;
}
}
if (stateToBeRetried != null) {
stateInstance.setStatus(stateToBeRetried.getStatus());
}
}
context.setVariable(DomainConstants.VAR_NAME_CURRENT_EXCEPTION, e);
EngineUtils.handleException(context, subStateMachine, e);
}
}
use of io.seata.saga.statelang.domain.StateInstance 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.StateInstance 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