use of io.seata.saga.engine.exception.EngineExecutionException 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.exception.EngineExecutionException 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.engine.exception.EngineExecutionException in project seata by seata.
the class ServiceTaskStateHandler method compensateSubStateMachine.
private Object compensateSubStateMachine(ProcessContext context, ServiceTaskState state, Object input, StateInstance stateInstance, StateMachineEngine engine) {
String subStateMachineParentId = (String) context.getVariable(state.getName() + DomainConstants.VAR_NAME_SUB_MACHINE_PARENT_ID);
if (StringUtils.isEmpty(subStateMachineParentId)) {
throw new EngineExecutionException("sub statemachine parentId is required", FrameworkErrorCode.ObjectNotExists);
}
StateMachineConfig stateMachineConfig = (StateMachineConfig) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONFIG);
List<StateMachineInstance> subInst = stateMachineConfig.getStateLogStore().queryStateMachineInstanceByParentId(subStateMachineParentId);
if (CollectionUtils.isEmpty(subInst)) {
throw new EngineExecutionException("cannot find sub statemachine instance by parentId:" + subStateMachineParentId, FrameworkErrorCode.ObjectNotExists);
}
String subStateMachineInstId = subInst.get(0).getId();
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(">>>>>>>>>>>>>>>>>>>>>> Start to compensate sub statemachine [id:{}]", subStateMachineInstId);
}
Map<String, Object> startParams = new HashMap<>(0);
if (input instanceof List) {
List<Object> listInputParams = (List<Object>) input;
if (listInputParams.size() > 0) {
startParams = (Map<String, Object>) listInputParams.get(0);
}
} else if (input instanceof Map) {
startParams = (Map<String, Object>) input;
}
StateMachineInstance compensateInst = engine.compensate(subStateMachineInstId, startParams);
stateInstance.setStatus(compensateInst.getCompensationStatus());
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("<<<<<<<<<<<<<<<<<<<<<< Compensate sub statemachine [id:{}] finished with status[{}], " + "compensateState[{}]", subStateMachineInstId, compensateInst.getStatus(), compensateInst.getCompensationStatus());
}
return compensateInst.getEndParams();
}
use of io.seata.saga.engine.exception.EngineExecutionException 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.engine.exception.EngineExecutionException in project seata by seata.
the class SagaResourceManager method branchRollback.
/**
* SAGA branch rollback
*
* @param branchType the branch type
* @param xid Transaction id.
* @param branchId Branch id.
* @param resourceId Resource id.
* @param applicationData Application data bind with this branch.
* @return
* @throws TransactionException
*/
@Override
public BranchStatus branchRollback(BranchType branchType, String xid, long branchId, String resourceId, String applicationData) throws TransactionException {
try {
StateMachineInstance stateMachineInstance = StateMachineEngineHolder.getStateMachineEngine().reloadStateMachineInstance(xid);
if (stateMachineInstance == null) {
return BranchStatus.PhaseTwo_Rollbacked;
}
if (RecoverStrategy.Forward.equals(stateMachineInstance.getStateMachine().getRecoverStrategy()) && (GlobalStatus.TimeoutRollbacking.name().equals(applicationData) || GlobalStatus.TimeoutRollbackRetrying.name().equals(applicationData))) {
LOGGER.warn("Retry by custom recover strategy [Forward] on timeout, SAGA global[{}]", xid);
return BranchStatus.PhaseTwo_CommitFailed_Retryable;
}
stateMachineInstance = StateMachineEngineHolder.getStateMachineEngine().compensate(xid, null);
if (ExecutionStatus.SU.equals(stateMachineInstance.getCompensationStatus())) {
return BranchStatus.PhaseTwo_Rollbacked;
}
} catch (EngineExecutionException e) {
LOGGER.error("StateMachine compensate failed, xid: " + xid, e);
// if StateMachineInstanceNotExists stop retry
if (FrameworkErrorCode.StateMachineInstanceNotExists.equals(e.getErrcode())) {
return BranchStatus.PhaseTwo_Rollbacked;
}
} catch (Exception e) {
LOGGER.error("StateMachine compensate failed, xid: " + xid, e);
}
return BranchStatus.PhaseTwo_RollbackFailed_Retryable;
}
Aggregations