use of io.seata.saga.engine.StateMachineConfig 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.StateMachineConfig in project seata by seata.
the class DbAndReportTcStateLogStore method branchRegister.
protected void branchRegister(StateInstance stateInstance, ProcessContext context) {
if (sagaTransactionalTemplate != null) {
StateMachineConfig stateMachineConfig = (StateMachineConfig) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONFIG);
if (stateMachineConfig instanceof DbStateMachineConfig && !((DbStateMachineConfig) stateMachineConfig).isSagaBranchRegisterEnable()) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("sagaBranchRegisterEnable = false, skip register branch. state[" + stateInstance.getName() + "]");
}
return;
}
// Register branch
try {
StateMachineInstance machineInstance = stateInstance.getStateMachineInstance();
GlobalTransaction globalTransaction = getGlobalTransaction(machineInstance, context);
if (globalTransaction == null) {
throw new EngineExecutionException("Global transaction is not exists", FrameworkErrorCode.ObjectNotExists);
}
String resourceId = stateInstance.getStateMachineInstance().getStateMachine().getName() + "#" + stateInstance.getName();
long branchId = sagaTransactionalTemplate.branchRegister(resourceId, null, globalTransaction.getXid(), null, null);
stateInstance.setId(String.valueOf(branchId));
} catch (TransactionException e) {
throw new EngineExecutionException(e, "Branch transaction error: " + e.getCode() + ", StateMachine:" + stateInstance.getStateMachineInstance().getStateMachine().getName() + ", XID: " + stateInstance.getStateMachineInstance().getId() + ", State:" + stateInstance.getName() + ", stateId: " + stateInstance.getId() + ", Reason: " + e.getMessage(), FrameworkErrorCode.TransactionManagerError);
} catch (ExecutionException e) {
throw new EngineExecutionException(e, "Branch transaction error: " + e.getCode() + ", StateMachine:" + stateInstance.getStateMachineInstance().getStateMachine().getName() + ", XID: " + stateInstance.getStateMachineInstance().getId() + ", State:" + stateInstance.getName() + ", stateId: " + stateInstance.getId() + ", Reason: " + e.getMessage(), FrameworkErrorCode.TransactionManagerError);
}
}
}
use of io.seata.saga.engine.StateMachineConfig in project seata by seata.
the class DbAndReportTcStateLogStore method branchReport.
protected void branchReport(StateInstance stateInstance, ProcessContext context) {
if (sagaTransactionalTemplate != null) {
StateMachineConfig stateMachineConfig = (StateMachineConfig) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONFIG);
if (stateMachineConfig instanceof DbStateMachineConfig && !((DbStateMachineConfig) stateMachineConfig).isSagaBranchRegisterEnable()) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("sagaBranchRegisterEnable = false, skip branch report. state[" + stateInstance.getName() + "]");
}
return;
}
BranchStatus branchStatus = null;
// find out the original state instance, only the original state instance is registered on the server, and its status should
// be reported.
StateInstance originalStateInst = null;
if (StringUtils.hasLength(stateInstance.getStateIdRetriedFor())) {
if (isUpdateMode(stateInstance, context)) {
originalStateInst = stateInstance;
} else {
originalStateInst = findOutOriginalStateInstanceOfRetryState(stateInstance);
}
if (ExecutionStatus.SU.equals(stateInstance.getStatus())) {
branchStatus = BranchStatus.PhaseTwo_Committed;
} else if (ExecutionStatus.FA.equals(stateInstance.getStatus()) || ExecutionStatus.UN.equals(stateInstance.getStatus())) {
branchStatus = BranchStatus.PhaseOne_Failed;
} else {
branchStatus = BranchStatus.Unknown;
}
} else if (StringUtils.hasLength(stateInstance.getStateIdCompensatedFor())) {
if (isUpdateMode(stateInstance, context)) {
originalStateInst = stateInstance.getStateMachineInstance().getStateMap().get(stateInstance.getStateIdCompensatedFor());
} else {
originalStateInst = findOutOriginalStateInstanceOfCompensateState(stateInstance);
}
}
if (originalStateInst == null) {
originalStateInst = stateInstance;
}
if (branchStatus == null) {
if (ExecutionStatus.SU.equals(originalStateInst.getStatus()) && originalStateInst.getCompensationStatus() == null) {
branchStatus = BranchStatus.PhaseTwo_Committed;
} else if (ExecutionStatus.SU.equals(originalStateInst.getCompensationStatus())) {
branchStatus = BranchStatus.PhaseTwo_Rollbacked;
} else if (ExecutionStatus.FA.equals(originalStateInst.getCompensationStatus()) || ExecutionStatus.UN.equals(originalStateInst.getCompensationStatus())) {
branchStatus = BranchStatus.PhaseTwo_RollbackFailed_Retryable;
} else if ((ExecutionStatus.FA.equals(originalStateInst.getStatus()) || ExecutionStatus.UN.equals(originalStateInst.getStatus())) && originalStateInst.getCompensationStatus() == null) {
branchStatus = BranchStatus.PhaseOne_Failed;
} else {
branchStatus = BranchStatus.Unknown;
}
}
try {
StateMachineInstance machineInstance = stateInstance.getStateMachineInstance();
GlobalTransaction globalTransaction = getGlobalTransaction(machineInstance, context);
if (globalTransaction == null) {
throw new EngineExecutionException("Global transaction is not exists", FrameworkErrorCode.ObjectNotExists);
}
sagaTransactionalTemplate.branchReport(globalTransaction.getXid(), Long.parseLong(originalStateInst.getId()), branchStatus, null);
} catch (TransactionException e) {
LOGGER.error("Report branch status to server error: {}, StateMachine:{}, StateName:{}, XID: {}, branchId: {}, branchStatus:{}," + " Reason:{} ", e.getCode(), originalStateInst.getStateMachineInstance().getStateMachine().getName(), originalStateInst.getName(), originalStateInst.getStateMachineInstance().getId(), originalStateInst.getId(), branchStatus, e.getMessage(), e);
} catch (ExecutionException e) {
LOGGER.error("Report branch status to server error: {}, StateMachine:{}, StateName:{}, XID: {}, branchId: {}, branchStatus:{}," + " Reason:{} ", e.getCode(), originalStateInst.getStateMachineInstance().getStateMachine().getName(), originalStateInst.getName(), originalStateInst.getStateMachineInstance().getId(), originalStateInst.getId(), branchStatus, e.getMessage(), e);
}
}
}
use of io.seata.saga.engine.StateMachineConfig in project seata by seata.
the class DbAndReportTcStateLogStore method recordStateMachineFinished.
@Override
public void recordStateMachineFinished(StateMachineInstance machineInstance, ProcessContext context) {
if (machineInstance != null) {
try {
// save to db
Map<String, Object> endParams = machineInstance.getEndParams();
if (endParams != null) {
endParams.remove(DomainConstants.VAR_NAME_GLOBAL_TX);
}
// if success, clear exception
if (ExecutionStatus.SU.equals(machineInstance.getStatus()) && machineInstance.getException() != null) {
machineInstance.setException(null);
}
machineInstance.setSerializedEndParams(paramsSerializer.serialize(machineInstance.getEndParams()));
machineInstance.setSerializedException(exceptionSerializer.serialize(machineInstance.getException()));
int effect = executeUpdate(stateLogStoreSqls.getRecordStateMachineFinishedSql(dbType), STATE_MACHINE_INSTANCE_TO_STATEMENT_FOR_UPDATE, machineInstance);
if (effect < 1) {
LOGGER.warn("StateMachineInstance[{}] is recovery by server, skip recordStateMachineFinished.", machineInstance.getId());
} else {
StateMachineConfig stateMachineConfig = (StateMachineConfig) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONFIG);
if (EngineUtils.isTimeout(machineInstance.getGmtUpdated(), stateMachineConfig.getTransOperationTimeout())) {
LOGGER.warn("StateMachineInstance[{}] is execution timeout, skip report transaction finished to server.", machineInstance.getId());
} else if (StringUtils.isEmpty(machineInstance.getParentId())) {
// if parentId is not null, machineInstance is a SubStateMachine, do not report global transaction.
reportTransactionFinished(machineInstance, context);
}
}
} finally {
RootContext.unbind();
RootContext.unbindBranchType();
}
}
}
use of io.seata.saga.engine.StateMachineConfig in project seata by seata.
the class StateMachineProcessRouter method route.
@Override
public Instruction route(ProcessContext context) throws FrameworkException {
StateInstruction stateInstruction = context.getInstruction(StateInstruction.class);
State state;
if (stateInstruction.getTemporaryState() != null) {
state = stateInstruction.getTemporaryState();
stateInstruction.setTemporaryState(null);
} else {
StateMachineConfig stateMachineConfig = (StateMachineConfig) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONFIG);
StateMachine stateMachine = stateMachineConfig.getStateMachineRepository().getStateMachine(stateInstruction.getStateMachineName(), stateInstruction.getTenantId());
state = stateMachine.getStates().get(stateInstruction.getStateName());
}
String stateType = state.getType();
StateRouter router = stateRouters.get(stateType);
Instruction instruction = null;
List<StateRouterInterceptor> interceptors = null;
if (router instanceof InterceptableStateRouter) {
interceptors = ((InterceptableStateRouter) router).getInterceptors();
}
List<StateRouterInterceptor> executedInterceptors = null;
Exception exception = null;
try {
if (CollectionUtils.isNotEmpty(interceptors)) {
executedInterceptors = new ArrayList<>(interceptors.size());
for (StateRouterInterceptor interceptor : interceptors) {
executedInterceptors.add(interceptor);
interceptor.preRoute(context, state);
}
}
instruction = router.route(context, state);
} catch (Exception e) {
exception = e;
throw e;
} finally {
if (CollectionUtils.isNotEmpty(executedInterceptors)) {
for (int i = executedInterceptors.size() - 1; i >= 0; i--) {
StateRouterInterceptor interceptor = executedInterceptors.get(i);
interceptor.postRoute(context, state, instruction, exception);
}
}
// if 'Succeed' or 'Fail' State did not configured, we must end the state machine
if (instruction == null && !stateInstruction.isEnd()) {
EngineUtils.endStateMachine(context);
}
}
return instruction;
}
Aggregations