use of io.seata.saga.engine.pcext.StateInstruction 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.pcext.StateInstruction in project seata by seata.
the class TaskStateRouter method route.
@Override
public Instruction route(ProcessContext context, State state) throws EngineExecutionException {
StateInstruction stateInstruction = context.getInstruction(StateInstruction.class);
if (stateInstruction.isEnd()) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("StateInstruction is ended, Stop the StateMachine executing. StateMachine[{}] Current State[{}]", stateInstruction.getStateMachineName(), state.getName());
}
return null;
}
// check if in loop async condition
if (Boolean.TRUE.equals(context.getVariable(DomainConstants.VAR_NAME_IS_LOOP_STATE))) {
return null;
}
// The current CompensationTriggerState can mark the compensation process is started and perform compensation
// route processing.
State compensationTriggerState = (State) context.getVariable(DomainConstants.VAR_NAME_CURRENT_COMPEN_TRIGGER_STATE);
if (compensationTriggerState != null) {
return compensateRoute(context, compensationTriggerState);
}
// There is an exception route, indicating that an exception is thrown, and the exception route is prioritized.
String next = (String) context.getVariable(DomainConstants.VAR_NAME_CURRENT_EXCEPTION_ROUTE);
if (StringUtils.hasLength(next)) {
context.removeVariable(DomainConstants.VAR_NAME_CURRENT_EXCEPTION_ROUTE);
} else {
next = state.getNext();
}
// If next is empty, the state selected by the Choice state was taken.
if (!StringUtils.hasLength(next) && context.hasVariable(DomainConstants.VAR_NAME_CURRENT_CHOICE)) {
next = (String) context.getVariable(DomainConstants.VAR_NAME_CURRENT_CHOICE);
context.removeVariable(DomainConstants.VAR_NAME_CURRENT_CHOICE);
}
if (!StringUtils.hasLength(next)) {
return null;
}
StateMachine stateMachine = state.getStateMachine();
State nextState = stateMachine.getState(next);
if (nextState == null) {
throw new EngineExecutionException("Next state[" + next + "] is not exits", FrameworkErrorCode.ObjectNotExists);
}
stateInstruction.setStateName(next);
if (null != LoopTaskUtils.getLoopConfig(context, nextState)) {
stateInstruction.setTemporaryState(new LoopStartStateImpl());
}
return stateInstruction;
}
use of io.seata.saga.engine.pcext.StateInstruction 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.engine.pcext.StateInstruction 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.pcext.StateInstruction 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);
}
}
Aggregations