use of io.seata.saga.statelang.domain.impl.ServiceTaskStateImpl in project seata by seata.
the class ServiceTaskHandlerInterceptor method preProcess.
@Override
public void preProcess(ProcessContext context) throws EngineExecutionException {
StateInstruction instruction = context.getInstruction(StateInstruction.class);
StateMachineInstance stateMachineInstance = (StateMachineInstance) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_INST);
StateMachineConfig stateMachineConfig = (StateMachineConfig) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONFIG);
if (EngineUtils.isTimeout(stateMachineInstance.getGmtUpdated(), stateMachineConfig.getTransOperationTimeout())) {
String message = "Saga Transaction [stateMachineInstanceId:" + stateMachineInstance.getId() + "] has timed out, stop execution now.";
LOGGER.error(message);
EngineExecutionException exception = ExceptionUtils.createEngineExecutionException(null, FrameworkErrorCode.StateMachineExecutionTimeout, message, stateMachineInstance, instruction.getStateName());
EngineUtils.failStateMachine(context, exception);
throw exception;
}
StateInstanceImpl stateInstance = new StateInstanceImpl();
Map<String, Object> contextVariables = (Map<String, Object>) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONTEXT);
ServiceTaskStateImpl state = (ServiceTaskStateImpl) instruction.getState(context);
List<Object> serviceInputParams = null;
if (contextVariables != null) {
try {
serviceInputParams = ParameterUtils.createInputParams(stateMachineConfig.getExpressionFactoryManager(), stateInstance, state, contextVariables);
} catch (Exception e) {
String message = "Task [" + state.getName() + "] input parameters assign failed, please check 'Input' expression:" + e.getMessage();
EngineExecutionException exception = ExceptionUtils.createEngineExecutionException(e, FrameworkErrorCode.VariablesAssignError, message, stateMachineInstance, state.getName());
EngineUtils.failStateMachine(context, exception);
throw exception;
}
}
((HierarchicalProcessContext) context).setVariableLocally(DomainConstants.VAR_NAME_INPUT_PARAMS, serviceInputParams);
stateInstance.setMachineInstanceId(stateMachineInstance.getId());
stateInstance.setStateMachineInstance(stateMachineInstance);
Object isForCompensation = state.isForCompensation();
if (context.hasVariable(DomainConstants.VAR_NAME_IS_LOOP_STATE) && !Boolean.TRUE.equals(isForCompensation)) {
stateInstance.setName(LoopTaskUtils.generateLoopStateName(context, state.getName()));
StateInstance lastRetriedStateInstance = LoopTaskUtils.findOutLastRetriedStateInstance(stateMachineInstance, stateInstance.getName());
stateInstance.setStateIdRetriedFor(lastRetriedStateInstance == null ? null : lastRetriedStateInstance.getId());
} else {
stateInstance.setName(state.getName());
stateInstance.setStateIdRetriedFor((String) context.getVariable(state.getName() + DomainConstants.VAR_NAME_RETRIED_STATE_INST_ID));
}
stateInstance.setGmtStarted(new Date());
stateInstance.setGmtUpdated(stateInstance.getGmtStarted());
stateInstance.setStatus(ExecutionStatus.RU);
if (StringUtils.hasLength(stateInstance.getBusinessKey())) {
((Map<String, Object>) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONTEXT)).put(state.getName() + DomainConstants.VAR_NAME_BUSINESSKEY, stateInstance.getBusinessKey());
}
stateInstance.setType(state.getType());
stateInstance.setForUpdate(state.isForUpdate());
stateInstance.setServiceName(state.getServiceName());
stateInstance.setServiceMethod(state.getServiceMethod());
stateInstance.setServiceType(state.getServiceType());
if (isForCompensation != null && (Boolean) isForCompensation) {
CompensationHolder compensationHolder = CompensationHolder.getCurrent(context, true);
StateInstance stateToBeCompensated = compensationHolder.getStatesNeedCompensation().get(state.getName());
if (stateToBeCompensated != null) {
stateToBeCompensated.setCompensationState(stateInstance);
stateInstance.setStateIdCompensatedFor(stateToBeCompensated.getId());
} else {
LOGGER.error("Compensation State[{}] has no state to compensate, maybe this is a bug.", state.getName());
}
CompensationHolder.getCurrent(context, true).addForCompensationState(stateInstance.getName(), stateInstance);
}
if (DomainConstants.OPERATION_NAME_FORWARD.equals(context.getVariable(DomainConstants.VAR_NAME_OPERATION_NAME)) && StringUtils.isEmpty(stateInstance.getStateIdRetriedFor()) && !state.isForCompensation()) {
List<StateInstance> stateList = stateMachineInstance.getStateList();
if (CollectionUtils.isNotEmpty(stateList)) {
for (int i = stateList.size() - 1; i >= 0; i--) {
StateInstance executedState = stateList.get(i);
if (stateInstance.getName().equals(executedState.getName())) {
stateInstance.setStateIdRetriedFor(executedState.getId());
executedState.setIgnoreStatus(true);
break;
}
}
}
}
stateInstance.setInputParams(serviceInputParams);
if (stateMachineInstance.getStateMachine().isPersist() && state.isPersist() && stateMachineConfig.getStateLogStore() != null) {
try {
stateMachineConfig.getStateLogStore().recordStateStarted(stateInstance, context);
} catch (Exception e) {
String message = "Record state[" + state.getName() + "] started failed, stateMachineInstance[" + stateMachineInstance.getId() + "], Reason: " + e.getMessage();
EngineExecutionException exception = ExceptionUtils.createEngineExecutionException(e, FrameworkErrorCode.ExceptionCaught, message, stateMachineInstance, state.getName());
EngineUtils.failStateMachine(context, exception);
throw exception;
}
}
if (StringUtils.isEmpty(stateInstance.getId())) {
stateInstance.setId(stateMachineConfig.getSeqGenerator().generate(DomainConstants.SEQ_ENTITY_STATE_INST));
}
stateMachineInstance.putStateInstance(stateInstance.getId(), stateInstance);
((HierarchicalProcessContext) context).setVariableLocally(DomainConstants.VAR_NAME_STATE_INST, stateInstance);
}
use of io.seata.saga.statelang.domain.impl.ServiceTaskStateImpl in project seata by seata.
the class ServiceTaskStateParser method parse.
@Override
public ServiceTaskState parse(Object node) {
ServiceTaskStateImpl serviceTaskState = new ServiceTaskStateImpl();
parseTaskAttributes(serviceTaskState, node);
Map<String, Object> nodeMap = (Map<String, Object>) node;
serviceTaskState.setServiceName((String) nodeMap.get("ServiceName"));
serviceTaskState.setServiceMethod((String) nodeMap.get("ServiceMethod"));
serviceTaskState.setServiceType((String) nodeMap.get("ServiceType"));
serviceTaskState.setParameterTypes((List<String>) nodeMap.get("ParameterTypes"));
Object isAsync = nodeMap.get("IsAsync");
if (Boolean.TRUE.equals(isAsync)) {
serviceTaskState.setAsync(true);
}
return serviceTaskState;
}
use of io.seata.saga.statelang.domain.impl.ServiceTaskStateImpl in project seata by seata.
the class ServiceTaskHandlerInterceptor method postProcess.
@Override
public void postProcess(ProcessContext context, Exception exp) throws EngineExecutionException {
StateInstruction instruction = context.getInstruction(StateInstruction.class);
ServiceTaskStateImpl state = (ServiceTaskStateImpl) instruction.getState(context);
StateMachineInstance stateMachineInstance = (StateMachineInstance) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_INST);
StateInstance stateInstance = (StateInstance) context.getVariable(DomainConstants.VAR_NAME_STATE_INST);
if (stateInstance == null || !stateMachineInstance.isRunning()) {
LOGGER.warn("StateMachineInstance[id:" + stateMachineInstance.getId() + "] is end. stop running");
return;
}
StateMachineConfig stateMachineConfig = (StateMachineConfig) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONFIG);
if (exp == null) {
exp = (Exception) context.getVariable(DomainConstants.VAR_NAME_CURRENT_EXCEPTION);
}
stateInstance.setException(exp);
decideExecutionStatus(context, stateInstance, state, exp);
if (ExecutionStatus.SU.equals(stateInstance.getStatus()) && exp != null) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Although an exception occurs, the execution status map to SU, and the exception is ignored when " + "the execution status decision.");
}
context.removeVariable(DomainConstants.VAR_NAME_CURRENT_EXCEPTION);
}
Map<String, Object> contextVariables = (Map<String, Object>) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONTEXT);
Object serviceOutputParams = context.getVariable(DomainConstants.VAR_NAME_OUTPUT_PARAMS);
if (serviceOutputParams != null) {
try {
Map<String, Object> outputVariablesToContext = ParameterUtils.createOutputParams(stateMachineConfig.getExpressionFactoryManager(), state, serviceOutputParams);
if (CollectionUtils.isNotEmpty(outputVariablesToContext)) {
contextVariables.putAll(outputVariablesToContext);
}
} catch (Exception e) {
String message = "Task [" + state.getName() + "] output parameters assign failed, please check 'Output' expression:" + e.getMessage();
EngineExecutionException exception = ExceptionUtils.createEngineExecutionException(e, FrameworkErrorCode.VariablesAssignError, message, stateMachineInstance, stateInstance);
if (stateMachineInstance.getStateMachine().isPersist() && state.isPersist() && stateMachineConfig.getStateLogStore() != null) {
stateMachineConfig.getStateLogStore().recordStateFinished(stateInstance, context);
}
EngineUtils.failStateMachine(context, exception);
throw exception;
}
}
context.removeVariable(DomainConstants.VAR_NAME_OUTPUT_PARAMS);
context.removeVariable(DomainConstants.VAR_NAME_INPUT_PARAMS);
stateInstance.setGmtEnd(new Date());
if (stateMachineInstance.getStateMachine().isPersist() && state.isPersist() && stateMachineConfig.getStateLogStore() != null) {
stateMachineConfig.getStateLogStore().recordStateFinished(stateInstance, context);
}
if (exp != null && context.getVariable(DomainConstants.VAR_NAME_IS_EXCEPTION_NOT_CATCH) != null && (Boolean) context.getVariable(DomainConstants.VAR_NAME_IS_EXCEPTION_NOT_CATCH)) {
// If there is an exception and there is no catch, need to exit the state machine to execute.
context.removeVariable(DomainConstants.VAR_NAME_IS_EXCEPTION_NOT_CATCH);
EngineUtils.failStateMachine(context, exp);
}
}
use of io.seata.saga.statelang.domain.impl.ServiceTaskStateImpl 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.impl.ServiceTaskStateImpl in project seata by seata.
the class DbAndReportTcStateLogStore method isUpdateMode.
private boolean isUpdateMode(StateInstance stateInstance, ProcessContext context) {
DefaultStateMachineConfig stateMachineConfig = (DefaultStateMachineConfig) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONFIG);
StateInstruction instruction = context.getInstruction(StateInstruction.class);
ServiceTaskStateImpl state = (ServiceTaskStateImpl) instruction.getState(context);
StateMachine stateMachine = stateInstance.getStateMachineInstance().getStateMachine();
if (StringUtils.hasLength(stateInstance.getStateIdRetriedFor())) {
if (null != state.isRetryPersistModeUpdate()) {
return state.isRetryPersistModeUpdate();
} else if (null != stateMachine.isRetryPersistModeUpdate()) {
return stateMachine.isRetryPersistModeUpdate();
}
return stateMachineConfig.isSagaRetryPersistModeUpdate();
} else if (StringUtils.hasLength(stateInstance.getStateIdCompensatedFor())) {
// find if this compensate has been executed
for (int i = 0; i < stateInstance.getStateMachineInstance().getStateList().size(); i++) {
StateInstance aStateInstance = stateInstance.getStateMachineInstance().getStateList().get(i);
if (aStateInstance.isForCompensation() && aStateInstance.getName().equals(stateInstance.getName())) {
if (null != state.isCompensatePersistModeUpdate()) {
return state.isCompensatePersistModeUpdate();
} else if (null != stateMachine.isCompensatePersistModeUpdate()) {
return stateMachine.isCompensatePersistModeUpdate();
}
return stateMachineConfig.isSagaCompensatePersistModeUpdate();
}
}
return false;
}
return false;
}
Aggregations