use of io.seata.saga.engine.StateMachineConfig 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.engine.StateMachineConfig in project seata by seata.
the class ServiceTaskHandlerInterceptor method decideExecutionStatus.
private void decideExecutionStatus(ProcessContext context, StateInstance stateInstance, ServiceTaskStateImpl state, Exception exp) {
Map<String, String> statusMatchList = state.getStatus();
if (CollectionUtils.isNotEmpty(statusMatchList)) {
if (state.isAsync()) {
if (LOGGER.isWarnEnabled()) {
LOGGER.warn("Service[{}.{}] is execute asynchronously, null return value collected, so user defined " + "Status Matching skipped. stateName: {}, branchId: {}", state.getServiceName(), state.getServiceMethod(), state.getName(), stateInstance.getId());
}
} else {
StateMachineConfig stateMachineConfig = (StateMachineConfig) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONFIG);
Map<Object, String> statusEvaluators = state.getStatusEvaluators();
if (statusEvaluators == null) {
synchronized (state) {
statusEvaluators = state.getStatusEvaluators();
if (statusEvaluators == null) {
statusEvaluators = new LinkedHashMap<>(statusMatchList.size());
String expressionStr, statusVal;
Evaluator evaluator;
for (Map.Entry<String, String> entry : statusMatchList.entrySet()) {
expressionStr = entry.getKey();
statusVal = entry.getValue();
evaluator = createEvaluator(stateMachineConfig.getEvaluatorFactoryManager(), expressionStr);
if (evaluator != null) {
statusEvaluators.put(evaluator, statusVal);
}
}
}
state.setStatusEvaluators(statusEvaluators);
}
}
for (Object evaluatorObj : statusEvaluators.keySet()) {
Evaluator evaluator = (Evaluator) evaluatorObj;
String statusVal = statusEvaluators.get(evaluator);
if (evaluator.evaluate(context.getVariables())) {
stateInstance.setStatus(ExecutionStatus.valueOf(statusVal));
break;
}
}
if (exp == null && (stateInstance.getStatus() == null || ExecutionStatus.RU.equals(stateInstance.getStatus()))) {
if (state.isForUpdate()) {
stateInstance.setStatus(ExecutionStatus.UN);
} else {
stateInstance.setStatus(ExecutionStatus.FA);
}
stateInstance.setGmtEnd(new Date());
StateMachineInstance stateMachineInstance = stateInstance.getStateMachineInstance();
if (stateMachineInstance.getStateMachine().isPersist() && state.isPersist() && stateMachineConfig.getStateLogStore() != null) {
stateMachineConfig.getStateLogStore().recordStateFinished(stateInstance, context);
}
EngineExecutionException exception = new EngineExecutionException("State [" + state.getName() + "] execute finished, but cannot matching status, pls check its status manually", FrameworkErrorCode.NoMatchedStatus);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("State[{}] execute finish with status[{}]", state.getName(), stateInstance.getStatus());
}
EngineUtils.failStateMachine(context, exception);
throw exception;
}
}
}
if (stateInstance.getStatus() == null || ExecutionStatus.RU.equals(stateInstance.getStatus())) {
if (exp == null) {
stateInstance.setStatus(ExecutionStatus.SU);
} else {
if (state.isForUpdate() || state.isForCompensation()) {
stateInstance.setStatus(ExecutionStatus.UN);
ExceptionUtils.NetExceptionType t = ExceptionUtils.getNetExceptionType(exp);
if (t != null) {
if (t.equals(ExceptionUtils.NetExceptionType.CONNECT_EXCEPTION)) {
stateInstance.setStatus(ExecutionStatus.FA);
} else if (t.equals(ExceptionUtils.NetExceptionType.READ_TIMEOUT_EXCEPTION)) {
stateInstance.setStatus(ExecutionStatus.UN);
}
} else {
stateInstance.setStatus(ExecutionStatus.UN);
}
} else {
stateInstance.setStatus(ExecutionStatus.FA);
}
}
}
if (LOGGER.isInfoEnabled()) {
LOGGER.info("State[{}] finish with status[{}]", state.getName(), stateInstance.getStatus());
}
}
use of io.seata.saga.engine.StateMachineConfig in project seata by seata.
the class EngineUtils method endStateMachine.
/**
* end StateMachine
*
* @param context
*/
public static void endStateMachine(ProcessContext context) {
if (context.hasVariable(DomainConstants.VAR_NAME_IS_LOOP_STATE)) {
if (context.hasVariable(DomainConstants.LOOP_SEMAPHORE)) {
Semaphore semaphore = (Semaphore) context.getVariable(DomainConstants.LOOP_SEMAPHORE);
semaphore.release();
}
return;
}
StateMachineInstance stateMachineInstance = (StateMachineInstance) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_INST);
stateMachineInstance.setGmtEnd(new Date());
Exception exp = (Exception) context.getVariable(DomainConstants.VAR_NAME_CURRENT_EXCEPTION);
if (exp != null) {
stateMachineInstance.setException(exp);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Exception Occurred: " + exp);
}
}
StateMachineConfig stateMachineConfig = (StateMachineConfig) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONFIG);
stateMachineConfig.getStatusDecisionStrategy().decideOnEndState(context, stateMachineInstance, exp);
stateMachineInstance.getEndParams().putAll((Map<String, Object>) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONTEXT));
StateInstruction instruction = context.getInstruction(StateInstruction.class);
instruction.setEnd(true);
stateMachineInstance.setRunning(false);
stateMachineInstance.setGmtEnd(new Date());
if (stateMachineInstance.getStateMachine().isPersist() && stateMachineConfig.getStateLogStore() != null) {
stateMachineConfig.getStateLogStore().recordStateMachineFinished(stateMachineInstance, context);
}
AsyncCallback callback = (AsyncCallback) context.getVariable(DomainConstants.VAR_NAME_ASYNC_CALLBACK);
if (callback != null) {
if (exp != null) {
callback.onError(context, stateMachineInstance, exp);
} else {
callback.onFinished(context, stateMachineInstance);
}
}
}
use of io.seata.saga.engine.StateMachineConfig in project seata by seata.
the class EngineUtils method failStateMachine.
/**
* fail StateMachine
*
* @param context
* @param exp
*/
public static void failStateMachine(ProcessContext context, Exception exp) {
if (context.hasVariable(DomainConstants.VAR_NAME_IS_LOOP_STATE)) {
return;
}
StateMachineInstance stateMachineInstance = (StateMachineInstance) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_INST);
StateMachineConfig stateMachineConfig = (StateMachineConfig) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONFIG);
stateMachineConfig.getStatusDecisionStrategy().decideOnTaskStateFail(context, stateMachineInstance, exp);
stateMachineInstance.getEndParams().putAll((Map<String, Object>) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONTEXT));
StateInstruction instruction = context.getInstruction(StateInstruction.class);
instruction.setEnd(true);
stateMachineInstance.setRunning(false);
stateMachineInstance.setGmtEnd(new Date());
stateMachineInstance.setException(exp);
if (stateMachineInstance.getStateMachine().isPersist() && stateMachineConfig.getStateLogStore() != null) {
stateMachineConfig.getStateLogStore().recordStateMachineFinished(stateMachineInstance, context);
}
AsyncCallback callback = (AsyncCallback) context.getVariable(DomainConstants.VAR_NAME_ASYNC_CALLBACK);
if (callback != null) {
callback.onError(context, stateMachineInstance, exp);
}
}
use of io.seata.saga.engine.StateMachineConfig 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);
}
}
Aggregations