chore(project): 添加项目配置文件和忽略规则
- 添加 Babel 配置文件支持 ES6+ 语法转换 - 添加 ESLint 忽略规则和配置文件 - 添加 Git 忽略规则文件 - 添加 Travis CI 配置文件 - 添加 1.4.2 版本变更日志文件 - 添加 Helm 图表辅助模板文件 - 添加 Helm 忽略规则文件
This commit is contained in:
52
saga/seata-saga-engine-store/pom.xml
Normal file
52
saga/seata-saga-engine-store/pom.xml
Normal file
@@ -0,0 +1,52 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 1999-2019 Seata.io Group.
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>seata-saga</artifactId>
|
||||
<groupId>io.seata</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<name>seata-saga-engine-store ${project.version}</name>
|
||||
<artifactId>seata-saga-engine-store</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>seata-saga-engine</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>seata-saga-rm</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>seata-saga-tm</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>seata-serializer-all</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.seata.saga.engine.config;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import io.seata.config.Configuration;
|
||||
import io.seata.config.ConfigurationFactory;
|
||||
import io.seata.core.constants.ConfigurationKeys;
|
||||
import io.seata.saga.engine.impl.DefaultStateMachineConfig;
|
||||
import io.seata.saga.engine.serializer.impl.ParamsSerializer;
|
||||
import io.seata.saga.engine.store.db.DbAndReportTcStateLogStore;
|
||||
import io.seata.saga.engine.store.db.DbStateLangStore;
|
||||
import io.seata.saga.tm.DefaultSagaTransactionalTemplate;
|
||||
import io.seata.saga.tm.SagaTransactionalTemplate;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static io.seata.common.DefaultValues.DEFAULT_CLIENT_REPORT_SUCCESS_ENABLE;
|
||||
import static io.seata.common.DefaultValues.DEFAULT_CLIENT_SAGA_BRANCH_REGISTER_ENABLE;
|
||||
import static io.seata.common.DefaultValues.DEFAULT_CLIENT_SAGA_COMPENSATE_PERSIST_MODE_UPDATE;
|
||||
import static io.seata.common.DefaultValues.DEFAULT_CLIENT_SAGA_RETRY_PERSIST_MODE_UPDATE;
|
||||
import static io.seata.common.DefaultValues.DEFAULT_SAGA_JSON_PARSER;
|
||||
|
||||
/**
|
||||
* DbStateMachineConfig
|
||||
*
|
||||
* @author lorne.cl
|
||||
*/
|
||||
public class DbStateMachineConfig extends DefaultStateMachineConfig implements DisposableBean {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(DbStateMachineConfig.class);
|
||||
|
||||
private DataSource dataSource;
|
||||
private String applicationId;
|
||||
private String txServiceGroup;
|
||||
private String tablePrefix = "seata_";
|
||||
private String dbType;
|
||||
private SagaTransactionalTemplate sagaTransactionalTemplate;
|
||||
private boolean rmReportSuccessEnable = DEFAULT_CLIENT_REPORT_SUCCESS_ENABLE;
|
||||
private boolean sagaBranchRegisterEnable = DEFAULT_CLIENT_SAGA_BRANCH_REGISTER_ENABLE;
|
||||
|
||||
|
||||
public DbStateMachineConfig() {
|
||||
try {
|
||||
Configuration configuration = ConfigurationFactory.getInstance();
|
||||
if (configuration != null) {
|
||||
this.rmReportSuccessEnable = configuration.getBoolean(ConfigurationKeys.CLIENT_REPORT_SUCCESS_ENABLE, DEFAULT_CLIENT_REPORT_SUCCESS_ENABLE);
|
||||
this.sagaBranchRegisterEnable = configuration.getBoolean(ConfigurationKeys.CLIENT_SAGA_BRANCH_REGISTER_ENABLE, DEFAULT_CLIENT_SAGA_BRANCH_REGISTER_ENABLE);
|
||||
setSagaJsonParser(configuration.getConfig(ConfigurationKeys.CLIENT_SAGA_JSON_PARSER, DEFAULT_SAGA_JSON_PARSER));
|
||||
this.applicationId = configuration.getConfig(ConfigurationKeys.APPLICATION_ID);
|
||||
this.txServiceGroup = configuration.getConfig(ConfigurationKeys.TX_SERVICE_GROUP);
|
||||
setSagaRetryPersistModeUpdate(configuration.getBoolean(ConfigurationKeys.CLIENT_SAGA_RETRY_PERSIST_MODE_UPDATE,
|
||||
DEFAULT_CLIENT_SAGA_RETRY_PERSIST_MODE_UPDATE));
|
||||
setSagaCompensatePersistModeUpdate(configuration.getBoolean(ConfigurationKeys.CLIENT_SAGA_COMPENSATE_PERSIST_MODE_UPDATE,
|
||||
DEFAULT_CLIENT_SAGA_COMPENSATE_PERSIST_MODE_UPDATE));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.warn("Load SEATA configuration failed, use default configuration instead.", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static String getDbTypeFromDataSource(DataSource dataSource) throws SQLException {
|
||||
try (Connection con = dataSource.getConnection()) {
|
||||
DatabaseMetaData metaData = con.getMetaData();
|
||||
return metaData.getDatabaseProductName();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
|
||||
dbType = getDbTypeFromDataSource(dataSource);
|
||||
|
||||
if (getStateLogStore() == null) {
|
||||
DbAndReportTcStateLogStore dbStateLogStore = new DbAndReportTcStateLogStore();
|
||||
dbStateLogStore.setDataSource(dataSource);
|
||||
dbStateLogStore.setTablePrefix(tablePrefix);
|
||||
dbStateLogStore.setDbType(dbType);
|
||||
dbStateLogStore.setDefaultTenantId(getDefaultTenantId());
|
||||
dbStateLogStore.setSeqGenerator(getSeqGenerator());
|
||||
|
||||
if (StringUtils.hasLength(getSagaJsonParser())) {
|
||||
ParamsSerializer paramsSerializer = new ParamsSerializer();
|
||||
paramsSerializer.setJsonParserName(getSagaJsonParser());
|
||||
dbStateLogStore.setParamsSerializer(paramsSerializer);
|
||||
}
|
||||
|
||||
if (sagaTransactionalTemplate == null) {
|
||||
DefaultSagaTransactionalTemplate defaultSagaTransactionalTemplate
|
||||
= new DefaultSagaTransactionalTemplate();
|
||||
defaultSagaTransactionalTemplate.setApplicationContext(getApplicationContext());
|
||||
defaultSagaTransactionalTemplate.setApplicationId(applicationId);
|
||||
defaultSagaTransactionalTemplate.setTxServiceGroup(txServiceGroup);
|
||||
defaultSagaTransactionalTemplate.afterPropertiesSet();
|
||||
sagaTransactionalTemplate = defaultSagaTransactionalTemplate;
|
||||
}
|
||||
|
||||
dbStateLogStore.setSagaTransactionalTemplate(sagaTransactionalTemplate);
|
||||
|
||||
setStateLogStore(dbStateLogStore);
|
||||
}
|
||||
|
||||
if (getStateLangStore() == null) {
|
||||
DbStateLangStore dbStateLangStore = new DbStateLangStore();
|
||||
dbStateLangStore.setDataSource(dataSource);
|
||||
dbStateLangStore.setTablePrefix(tablePrefix);
|
||||
dbStateLangStore.setDbType(dbType);
|
||||
|
||||
setStateLangStore(dbStateLangStore);
|
||||
}
|
||||
|
||||
super.afterPropertiesSet();//must execute after StateLangStore initialized
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
if ((sagaTransactionalTemplate != null) && (sagaTransactionalTemplate instanceof DisposableBean)) {
|
||||
((DisposableBean) sagaTransactionalTemplate).destroy();
|
||||
}
|
||||
}
|
||||
|
||||
public DataSource getDataSource() {
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
public void setDataSource(DataSource dataSource) {
|
||||
this.dataSource = dataSource;
|
||||
}
|
||||
|
||||
public String getApplicationId() {
|
||||
return applicationId;
|
||||
}
|
||||
|
||||
public void setApplicationId(String applicationId) {
|
||||
this.applicationId = applicationId;
|
||||
}
|
||||
|
||||
public String getTxServiceGroup() {
|
||||
return txServiceGroup;
|
||||
}
|
||||
|
||||
public void setTxServiceGroup(String txServiceGroup) {
|
||||
this.txServiceGroup = txServiceGroup;
|
||||
}
|
||||
|
||||
public void setSagaTransactionalTemplate(SagaTransactionalTemplate sagaTransactionalTemplate) {
|
||||
this.sagaTransactionalTemplate = sagaTransactionalTemplate;
|
||||
}
|
||||
|
||||
public String getTablePrefix() {
|
||||
return tablePrefix;
|
||||
}
|
||||
|
||||
public void setTablePrefix(String tablePrefix) {
|
||||
this.tablePrefix = tablePrefix;
|
||||
}
|
||||
|
||||
public String getDbType() {
|
||||
return dbType;
|
||||
}
|
||||
|
||||
public void setDbType(String dbType) {
|
||||
this.dbType = dbType;
|
||||
}
|
||||
|
||||
public boolean isRmReportSuccessEnable() {
|
||||
return rmReportSuccessEnable;
|
||||
}
|
||||
|
||||
public boolean isSagaBranchRegisterEnable() {
|
||||
return sagaBranchRegisterEnable;
|
||||
}
|
||||
|
||||
public void setSagaBranchRegisterEnable(boolean sagaBranchRegisterEnable) {
|
||||
this.sagaBranchRegisterEnable = sagaBranchRegisterEnable;
|
||||
}
|
||||
|
||||
public void setRmReportSuccessEnable(boolean rmReportSuccessEnable) {
|
||||
this.rmReportSuccessEnable = rmReportSuccessEnable;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.seata.saga.engine.pcext.interceptors;
|
||||
|
||||
import io.seata.common.loader.LoadLevel;
|
||||
import io.seata.common.util.StringUtils;
|
||||
import io.seata.core.context.RootContext;
|
||||
import io.seata.core.model.BranchType;
|
||||
import io.seata.saga.engine.exception.EngineExecutionException;
|
||||
import io.seata.saga.engine.pcext.InterceptableStateHandler;
|
||||
import io.seata.saga.engine.pcext.StateHandlerInterceptor;
|
||||
import io.seata.saga.proctrl.ProcessContext;
|
||||
import io.seata.saga.statelang.domain.DomainConstants;
|
||||
import io.seata.saga.statelang.domain.StateMachineInstance;
|
||||
import io.seata.tm.api.GlobalTransaction;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* InSagaBranchHandler Interceptor
|
||||
*
|
||||
* @author wang.liang
|
||||
*/
|
||||
@LoadLevel(name = "InSagaBranch", order = 50)
|
||||
public class InSagaBranchHandlerInterceptor implements StateHandlerInterceptor {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(InSagaBranchHandlerInterceptor.class);
|
||||
|
||||
@Override
|
||||
public boolean match(Class<? extends InterceptableStateHandler> clazz) {
|
||||
// This interceptor will intercept all types of InterceptableStateHandler
|
||||
return clazz != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preProcess(ProcessContext context) throws EngineExecutionException {
|
||||
// get xid
|
||||
String xid = this.getXidFromProcessContext(context);
|
||||
if (StringUtils.isBlank(xid)) {
|
||||
LOGGER.warn("There is no xid in the process context.");
|
||||
return;
|
||||
}
|
||||
|
||||
// logger.warn if previousXid is not equals to xid
|
||||
if (LOGGER.isWarnEnabled()) {
|
||||
String previousXid = RootContext.getXID();
|
||||
if (previousXid != null) {
|
||||
if (!StringUtils.equalsIgnoreCase(previousXid, xid)) {
|
||||
LOGGER.warn("xid in change from {} to {}, Please don't use state machine engine in other global transaction.",
|
||||
previousXid, xid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// bind xid and branchType
|
||||
RootContext.bind(xid);
|
||||
RootContext.bindBranchType(BranchType.SAGA);
|
||||
if (LOGGER.isInfoEnabled()) {
|
||||
LOGGER.info("[{}] Begin process the state instance in the saga branch.", xid);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postProcess(ProcessContext context, Exception exp) throws EngineExecutionException {
|
||||
// unbind xid and branchType
|
||||
String xid = RootContext.unbind();
|
||||
RootContext.unbindBranchType();
|
||||
if (LOGGER.isInfoEnabled()) {
|
||||
LOGGER.info("[{}] Finish process the state instance in the saga branch.", xid);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets xid from saga process context.
|
||||
*
|
||||
* @return the xid
|
||||
*/
|
||||
protected String getXidFromProcessContext(ProcessContext context) {
|
||||
String xid = null;
|
||||
Map<String, Object> contextVariable = (Map<String, Object>) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_CONTEXT);
|
||||
if (contextVariable != null && contextVariable.containsKey(DomainConstants.VAR_NAME_GLOBAL_TX)) {
|
||||
GlobalTransaction globalTransaction = (GlobalTransaction) contextVariable.get(DomainConstants.VAR_NAME_GLOBAL_TX);
|
||||
xid = globalTransaction.getXid();
|
||||
} else {
|
||||
StateMachineInstance stateMachineInstance = (StateMachineInstance) context.getVariable(DomainConstants.VAR_NAME_STATEMACHINE_INST);
|
||||
if (stateMachineInstance != null) {
|
||||
xid = stateMachineInstance.getId();
|
||||
}
|
||||
}
|
||||
return xid;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.seata.saga.engine.serializer;
|
||||
|
||||
/**
|
||||
* Object serializer
|
||||
*
|
||||
* @author lorne.cl
|
||||
*/
|
||||
public interface Serializer<S, T> {
|
||||
|
||||
/**
|
||||
* serialize
|
||||
*
|
||||
* @param object
|
||||
* @return
|
||||
*/
|
||||
T serialize(S object);
|
||||
|
||||
/**
|
||||
* deserialize
|
||||
*
|
||||
* @param obj
|
||||
* @return
|
||||
*/
|
||||
S deserialize(T obj);
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.seata.saga.engine.serializer.impl;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
|
||||
import io.seata.saga.engine.serializer.Serializer;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Exception serializer
|
||||
*
|
||||
* @author lorne.cl
|
||||
*/
|
||||
public class ExceptionSerializer implements Serializer<Exception, byte[]> {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionSerializer.class);
|
||||
|
||||
public static byte[] serializeByObjectOutput(Object o) {
|
||||
|
||||
byte[] result = null;
|
||||
if (o != null) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
|
||||
oos.writeObject(o);
|
||||
oos.flush();
|
||||
result = baos.toByteArray();
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("serializer failed: {}", o.getClass(), e);
|
||||
throw new RuntimeException("IO Create Error", e);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static <T> T deserializeByObjectInputStream(byte[] bytes, Class<T> valueType) {
|
||||
|
||||
if (bytes == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Object result = deserializeByObjectInputStream(bytes);
|
||||
return valueType.cast(result);
|
||||
}
|
||||
|
||||
public static Object deserializeByObjectInputStream(byte[] bytes) {
|
||||
|
||||
Object result = null;
|
||||
if (bytes != null) {
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
|
||||
try (ObjectInputStream ois = new ObjectInputStream(bais)) {
|
||||
result = ois.readObject();
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("deserialize failed:", e);
|
||||
throw new RuntimeException("IO Create Error", e);
|
||||
} catch (ClassNotFoundException e) {
|
||||
LOGGER.error("deserialize failed:", e);
|
||||
throw new RuntimeException("Cannot find specified class", e);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] serialize(Exception object) {
|
||||
|
||||
return serializeByObjectOutput(object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Exception deserialize(byte[] bytes) {
|
||||
return deserializeByObjectInputStream(bytes, Exception.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.seata.saga.engine.serializer.impl;
|
||||
|
||||
import io.seata.saga.engine.serializer.Serializer;
|
||||
import io.seata.saga.statelang.domain.DomainConstants;
|
||||
import io.seata.saga.statelang.parser.JsonParser;
|
||||
import io.seata.saga.statelang.parser.JsonParserFactory;
|
||||
|
||||
/**
|
||||
* Parameter serializer based on Fastjson
|
||||
*
|
||||
* @author lorne.cl
|
||||
*/
|
||||
public class ParamsSerializer implements Serializer<Object, String> {
|
||||
|
||||
private String jsonParserName = DomainConstants.DEFAULT_JSON_PARSER;
|
||||
|
||||
@Override
|
||||
public String serialize(Object params) {
|
||||
if (params != null) {
|
||||
JsonParser jsonParser = JsonParserFactory.getJsonParser(jsonParserName);
|
||||
if (jsonParser == null) {
|
||||
throw new RuntimeException("Cannot find JsonParer by name: " + jsonParserName);
|
||||
}
|
||||
return jsonParser.toJsonString(params, false);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object deserialize(String json) {
|
||||
if (json != null) {
|
||||
JsonParser jsonParser = JsonParserFactory.getJsonParser(jsonParserName);
|
||||
if (jsonParser == null) {
|
||||
throw new RuntimeException("Cannot find JsonParer by name: " + jsonParserName);
|
||||
}
|
||||
return jsonParser.parse(json, Object.class, false);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getJsonParserName() {
|
||||
return jsonParserName;
|
||||
}
|
||||
|
||||
public void setJsonParserName(String jsonParserName) {
|
||||
this.jsonParserName = jsonParserName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.seata.saga.engine.store.db;
|
||||
|
||||
import io.seata.common.util.BeanUtils;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import io.seata.common.exception.StoreException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Abstract store
|
||||
*
|
||||
* @author lorne.cl
|
||||
*/
|
||||
public class AbstractStore {
|
||||
|
||||
protected static final Logger LOGGER = LoggerFactory.getLogger(AbstractStore.class);
|
||||
|
||||
protected DataSource dataSource;
|
||||
|
||||
protected String dbType;
|
||||
|
||||
protected String tablePrefix;
|
||||
|
||||
public static void closeSilent(AutoCloseable closeable) {
|
||||
if (closeable != null) {
|
||||
try {
|
||||
closeable.close();
|
||||
} catch (Exception e) {
|
||||
LOGGER.info(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected <T> T selectOne(String sql, ResultSetToObject<T> resultSetToObject, Object... args) {
|
||||
Connection connection = null;
|
||||
PreparedStatement stmt = null;
|
||||
ResultSet resultSet = null;
|
||||
try {
|
||||
connection = dataSource.getConnection();
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Preparing SQL statement: {}", sql);
|
||||
}
|
||||
|
||||
stmt = connection.prepareStatement(sql);
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("setting params to PreparedStatement: {}", Arrays.toString(args));
|
||||
}
|
||||
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
stmt.setObject(i + 1, args[i]);
|
||||
}
|
||||
resultSet = stmt.executeQuery();
|
||||
if (resultSet.next()) {
|
||||
return resultSetToObject.toObject(resultSet);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new StoreException(e);
|
||||
} finally {
|
||||
closeSilent(resultSet);
|
||||
closeSilent(stmt);
|
||||
closeSilent(connection);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected <T> List<T> selectList(String sql, ResultSetToObject<T> resultSetToObject, Object... args) {
|
||||
Connection connection = null;
|
||||
PreparedStatement stmt = null;
|
||||
ResultSet resultSet = null;
|
||||
try {
|
||||
connection = dataSource.getConnection();
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Preparing SQL: {}", sql);
|
||||
}
|
||||
|
||||
stmt = connection.prepareStatement(sql);
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("setting params to PreparedStatement: {}", Arrays.toString(args));
|
||||
}
|
||||
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
stmt.setObject(i + 1, args[i]);
|
||||
}
|
||||
resultSet = stmt.executeQuery();
|
||||
List<T> list = new ArrayList<>();
|
||||
while (resultSet.next()) {
|
||||
list.add(resultSetToObject.toObject(resultSet));
|
||||
}
|
||||
return list;
|
||||
} catch (SQLException e) {
|
||||
throw new StoreException(e);
|
||||
} finally {
|
||||
closeSilent(resultSet);
|
||||
closeSilent(stmt);
|
||||
closeSilent(connection);
|
||||
}
|
||||
}
|
||||
|
||||
protected <T> int executeUpdate(String sql, ObjectToStatement<T> objectToStatement, T o) {
|
||||
Connection connection = null;
|
||||
PreparedStatement stmt = null;
|
||||
try {
|
||||
connection = dataSource.getConnection();
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Preparing SQL: {}", sql);
|
||||
}
|
||||
|
||||
stmt = connection.prepareStatement(sql);
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("setting params to PreparedStatement: {}", BeanUtils.beanToString(o));
|
||||
}
|
||||
|
||||
objectToStatement.toStatement(o, stmt);
|
||||
int count = stmt.executeUpdate();
|
||||
if (!connection.getAutoCommit()) {
|
||||
connection.commit();
|
||||
}
|
||||
return count;
|
||||
} catch (SQLException e) {
|
||||
throw new StoreException(e);
|
||||
} finally {
|
||||
closeSilent(stmt);
|
||||
closeSilent(connection);
|
||||
}
|
||||
}
|
||||
|
||||
protected int executeUpdate(String sql, Object... args) {
|
||||
Connection connection = null;
|
||||
PreparedStatement stmt = null;
|
||||
try {
|
||||
connection = dataSource.getConnection();
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Preparing SQL: {}", sql);
|
||||
}
|
||||
|
||||
stmt = connection.prepareStatement(sql);
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("setting params to PreparedStatement: {}", Arrays.toString(args));
|
||||
}
|
||||
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
stmt.setObject(i + 1, args[i]);
|
||||
}
|
||||
int count = stmt.executeUpdate();
|
||||
if (!connection.getAutoCommit()) {
|
||||
connection.commit();
|
||||
}
|
||||
return count;
|
||||
} catch (SQLException e) {
|
||||
throw new StoreException(e);
|
||||
} finally {
|
||||
closeSilent(stmt);
|
||||
closeSilent(connection);
|
||||
}
|
||||
}
|
||||
|
||||
public void setDataSource(DataSource dataSource) {
|
||||
this.dataSource = dataSource;
|
||||
}
|
||||
|
||||
public void setDbType(String dbType) {
|
||||
this.dbType = dbType;
|
||||
}
|
||||
|
||||
public void setTablePrefix(String tablePrefix) {
|
||||
this.tablePrefix = tablePrefix;
|
||||
}
|
||||
|
||||
protected interface ResultSetToObject<T> {
|
||||
|
||||
T toObject(ResultSet resultSet) throws SQLException;
|
||||
}
|
||||
|
||||
protected interface ObjectToStatement<T> {
|
||||
|
||||
void toStatement(T o, PreparedStatement statement) throws SQLException;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,912 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.seata.saga.engine.store.db;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.seata.common.Constants;
|
||||
import io.seata.common.exception.FrameworkErrorCode;
|
||||
import io.seata.common.exception.StoreException;
|
||||
import io.seata.common.util.CollectionUtils;
|
||||
import io.seata.core.context.RootContext;
|
||||
import io.seata.core.exception.TransactionException;
|
||||
import io.seata.core.model.BranchStatus;
|
||||
import io.seata.core.model.BranchType;
|
||||
import io.seata.core.model.GlobalStatus;
|
||||
import io.seata.saga.engine.StateMachineConfig;
|
||||
import io.seata.saga.engine.config.DbStateMachineConfig;
|
||||
import io.seata.saga.engine.exception.EngineExecutionException;
|
||||
import io.seata.saga.engine.impl.DefaultStateMachineConfig;
|
||||
import io.seata.saga.engine.pcext.StateInstruction;
|
||||
import io.seata.saga.engine.pcext.utils.EngineUtils;
|
||||
import io.seata.saga.engine.sequence.SeqGenerator;
|
||||
import io.seata.saga.engine.serializer.Serializer;
|
||||
import io.seata.saga.engine.serializer.impl.ExceptionSerializer;
|
||||
import io.seata.saga.engine.serializer.impl.ParamsSerializer;
|
||||
import io.seata.saga.engine.store.StateLogStore;
|
||||
import io.seata.saga.proctrl.ProcessContext;
|
||||
import io.seata.saga.statelang.domain.DomainConstants;
|
||||
import io.seata.saga.statelang.domain.ExecutionStatus;
|
||||
import io.seata.saga.statelang.domain.StateInstance;
|
||||
import io.seata.saga.statelang.domain.StateMachine;
|
||||
import io.seata.saga.statelang.domain.StateMachineInstance;
|
||||
import io.seata.saga.statelang.domain.impl.ServiceTaskStateImpl;
|
||||
import io.seata.saga.statelang.domain.impl.StateInstanceImpl;
|
||||
import io.seata.saga.statelang.domain.impl.StateMachineInstanceImpl;
|
||||
import io.seata.saga.tm.SagaTransactionalTemplate;
|
||||
import io.seata.tm.api.GlobalTransaction;
|
||||
import io.seata.tm.api.TransactionalExecutor.ExecutionException;
|
||||
import io.seata.tm.api.transaction.TransactionInfo;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* State machine logs and definitions persist to database and report status to TC (Transaction Coordinator)
|
||||
*
|
||||
* @author lorne.cl
|
||||
*/
|
||||
public class DbAndReportTcStateLogStore extends AbstractStore implements StateLogStore {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(
|
||||
DbAndReportTcStateLogStore.class);
|
||||
private static final StateMachineInstanceToStatementForInsert STATE_MACHINE_INSTANCE_TO_STATEMENT_FOR_INSERT
|
||||
= new StateMachineInstanceToStatementForInsert();
|
||||
private static final StateMachineInstanceToStatementForUpdate STATE_MACHINE_INSTANCE_TO_STATEMENT_FOR_UPDATE
|
||||
= new StateMachineInstanceToStatementForUpdate();
|
||||
private static final ResultSetToStateMachineInstance RESULT_SET_TO_STATE_MACHINE_INSTANCE
|
||||
= new ResultSetToStateMachineInstance();
|
||||
private static final StateInstanceToStatementForInsert STATE_INSTANCE_TO_STATEMENT_FOR_INSERT
|
||||
= new StateInstanceToStatementForInsert();
|
||||
private static final StateInstanceToStatementForUpdate STATE_INSTANCE_TO_STATEMENT_FOR_UPDATE
|
||||
= new StateInstanceToStatementForUpdate();
|
||||
private static final ResultSetToStateInstance RESULT_SET_TO_STATE_INSTANCE = new ResultSetToStateInstance();
|
||||
private SagaTransactionalTemplate sagaTransactionalTemplate;
|
||||
private Serializer<Object, String> paramsSerializer = new ParamsSerializer();
|
||||
private Serializer<Exception, byte[]> exceptionSerializer = new ExceptionSerializer();
|
||||
private StateLogStoreSqls stateLogStoreSqls;
|
||||
private String defaultTenantId;
|
||||
private SeqGenerator seqGenerator;
|
||||
|
||||
@Override
|
||||
public void recordStateMachineStarted(StateMachineInstance machineInstance, ProcessContext context) {
|
||||
if (machineInstance != null) {
|
||||
//if parentId is not null, machineInstance is a SubStateMachine, do not start a new global transaction,
|
||||
//use parent transaction instead.
|
||||
String parentId = machineInstance.getParentId();
|
||||
if (StringUtils.isEmpty(parentId)) {
|
||||
beginTransaction(machineInstance, context);
|
||||
}
|
||||
|
||||
try {
|
||||
if (StringUtils.isEmpty(machineInstance.getId()) && seqGenerator != null) {
|
||||
machineInstance.setId(seqGenerator.generate(DomainConstants.SEQ_ENTITY_STATE_MACHINE_INST));
|
||||
}
|
||||
|
||||
// bind SAGA branch type
|
||||
RootContext.bindBranchType(BranchType.SAGA);
|
||||
|
||||
// save to db
|
||||
machineInstance.setSerializedStartParams(paramsSerializer.serialize(machineInstance.getStartParams()));
|
||||
int effect = executeUpdate(stateLogStoreSqls.getRecordStateMachineStartedSql(dbType),
|
||||
STATE_MACHINE_INSTANCE_TO_STATEMENT_FOR_INSERT, machineInstance);
|
||||
if (effect < 1) {
|
||||
throw new StoreException("StateMachineInstance record start error, Xid: " + machineInstance.getId(),
|
||||
FrameworkErrorCode.OperationDenied);
|
||||
}
|
||||
} catch (StoreException e) {
|
||||
LOGGER.error("Record statemachine start error: {}, StateMachine: {}, XID: {}, Reason: {}",
|
||||
e.getErrcode(), machineInstance.getStateMachine().getName(), machineInstance.getId(), e.getMessage(), e);
|
||||
// clear
|
||||
RootContext.unbind();
|
||||
RootContext.unbindBranchType();
|
||||
if (sagaTransactionalTemplate != null) {
|
||||
sagaTransactionalTemplate.cleanUp();
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void beginTransaction(StateMachineInstance machineInstance, ProcessContext context) {
|
||||
if (sagaTransactionalTemplate != null) {
|
||||
|
||||
StateMachineConfig stateMachineConfig = (StateMachineConfig) context.getVariable(
|
||||
DomainConstants.VAR_NAME_STATEMACHINE_CONFIG);
|
||||
TransactionInfo transactionInfo = new TransactionInfo();
|
||||
transactionInfo.setTimeOut(stateMachineConfig.getTransOperationTimeout());
|
||||
transactionInfo.setName(Constants.SAGA_TRANS_NAME_PREFIX + machineInstance.getStateMachine().getName());
|
||||
try {
|
||||
GlobalTransaction globalTransaction = sagaTransactionalTemplate.beginTransaction(transactionInfo);
|
||||
machineInstance.setId(globalTransaction.getXid());
|
||||
|
||||
context.setVariable(DomainConstants.VAR_NAME_GLOBAL_TX, globalTransaction);
|
||||
Map<String, Object> machineContext = machineInstance.getContext();
|
||||
if (machineContext != null) {
|
||||
machineContext.put(DomainConstants.VAR_NAME_GLOBAL_TX, globalTransaction);
|
||||
}
|
||||
} catch (ExecutionException e) {
|
||||
String xid = null;
|
||||
if (e.getTransaction() != null) {
|
||||
xid = e.getTransaction().getXid();
|
||||
}
|
||||
throw new EngineExecutionException(e,
|
||||
e.getCode() + ", TransName:" + transactionInfo.getName() + ", XID: " + xid + ", Reason: " + e
|
||||
.getMessage(), FrameworkErrorCode.TransactionManagerError);
|
||||
}
|
||||
finally {
|
||||
if (Boolean.TRUE.equals(context.getVariable(DomainConstants.VAR_NAME_IS_ASYNC_EXECUTION))) {
|
||||
RootContext.unbind();
|
||||
RootContext.unbindBranchType();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void reportTransactionFinished(StateMachineInstance machineInstance, ProcessContext context) {
|
||||
if (sagaTransactionalTemplate != null) {
|
||||
try {
|
||||
GlobalTransaction globalTransaction = getGlobalTransaction(machineInstance, context);
|
||||
if (globalTransaction == null) {
|
||||
|
||||
throw new EngineExecutionException("Global transaction is not exists",
|
||||
FrameworkErrorCode.ObjectNotExists);
|
||||
}
|
||||
|
||||
GlobalStatus globalStatus;
|
||||
if (ExecutionStatus.SU.equals(machineInstance.getStatus())
|
||||
&& machineInstance.getCompensationStatus() == null) {
|
||||
globalStatus = GlobalStatus.Committed;
|
||||
} else if (ExecutionStatus.SU.equals(machineInstance.getCompensationStatus())) {
|
||||
globalStatus = GlobalStatus.Rollbacked;
|
||||
} else if (ExecutionStatus.FA.equals(machineInstance.getCompensationStatus()) || ExecutionStatus.UN
|
||||
.equals(machineInstance.getCompensationStatus())) {
|
||||
globalStatus = GlobalStatus.RollbackRetrying;
|
||||
} else if (ExecutionStatus.FA.equals(machineInstance.getStatus())
|
||||
&& machineInstance.getCompensationStatus() == null) {
|
||||
globalStatus = GlobalStatus.Finished;
|
||||
} else if (ExecutionStatus.UN.equals(machineInstance.getStatus())
|
||||
&& machineInstance.getCompensationStatus() == null) {
|
||||
globalStatus = GlobalStatus.CommitRetrying;
|
||||
} else {
|
||||
globalStatus = GlobalStatus.UnKnown;
|
||||
}
|
||||
sagaTransactionalTemplate.reportTransaction(globalTransaction, globalStatus);
|
||||
} catch (ExecutionException e) {
|
||||
LOGGER.error("Report transaction finish to server error: {}, StateMachine: {}, XID: {}, Reason: {}",
|
||||
e.getCode(), machineInstance.getStateMachine().getName(), machineInstance.getId(), e.getMessage(), e);
|
||||
} catch (TransactionException e) {
|
||||
LOGGER.error("Report transaction finish to server error: {}, StateMachine: {}, XID: {}, Reason: {}",
|
||||
e.getCode(), machineInstance.getStateMachine().getName(), machineInstance.getId(), e.getMessage(), e);
|
||||
} finally {
|
||||
// clear
|
||||
RootContext.unbind();
|
||||
RootContext.unbindBranchType();
|
||||
sagaTransactionalTemplate.triggerAfterCompletion();
|
||||
sagaTransactionalTemplate.cleanUp();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recordStateMachineRestarted(StateMachineInstance machineInstance, ProcessContext context) {
|
||||
|
||||
if (machineInstance != null) {
|
||||
//save to db
|
||||
Date gmtUpdated = new Date();
|
||||
int effect = executeUpdate(stateLogStoreSqls.getUpdateStateMachineRunningStatusSql(dbType), machineInstance.isRunning(), new Timestamp(gmtUpdated.getTime()),
|
||||
machineInstance.getId(), new Timestamp(machineInstance.getGmtUpdated().getTime()));
|
||||
if (effect < 1) {
|
||||
throw new EngineExecutionException(
|
||||
"StateMachineInstance [id:" + machineInstance.getId() + "] is recovered by an other execution, restart denied", FrameworkErrorCode.OperationDenied);
|
||||
}
|
||||
machineInstance.setGmtUpdated(gmtUpdated);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recordStateStarted(StateInstance stateInstance, ProcessContext context) {
|
||||
if (stateInstance != null) {
|
||||
|
||||
boolean isUpdateMode = isUpdateMode(stateInstance, context);
|
||||
|
||||
// if this state is for retry, do not register branch
|
||||
if (StringUtils.hasLength(stateInstance.getStateIdRetriedFor())) {
|
||||
if (isUpdateMode) {
|
||||
stateInstance.setId(stateInstance.getStateIdRetriedFor());
|
||||
} else {
|
||||
// generate id by default
|
||||
stateInstance.setId(generateRetryStateInstanceId(stateInstance));
|
||||
}
|
||||
}
|
||||
// if this state is for compensation, do not register branch
|
||||
else if (StringUtils.hasLength(stateInstance.getStateIdCompensatedFor())) {
|
||||
stateInstance.setId(generateCompensateStateInstanceId(stateInstance, isUpdateMode));
|
||||
} else {
|
||||
branchRegister(stateInstance, context);
|
||||
}
|
||||
|
||||
if (StringUtils.isEmpty(stateInstance.getId()) && seqGenerator != null) {
|
||||
stateInstance.setId(seqGenerator.generate(DomainConstants.SEQ_ENTITY_STATE_INST));
|
||||
}
|
||||
|
||||
stateInstance.setSerializedInputParams(paramsSerializer.serialize(stateInstance.getInputParams()));
|
||||
if (!isUpdateMode) {
|
||||
executeUpdate(stateLogStoreSqls.getRecordStateStartedSql(dbType),
|
||||
STATE_INSTANCE_TO_STATEMENT_FOR_INSERT, stateInstance);
|
||||
} else {
|
||||
// if this retry/compensate state do not need persist, just update last inst
|
||||
executeUpdate(stateLogStoreSqls.getUpdateStateExecutionStatusSql(dbType),
|
||||
stateInstance.getStatus().name(), new Timestamp(System.currentTimeMillis()),
|
||||
stateInstance.getMachineInstanceId(), stateInstance.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected GlobalTransaction getGlobalTransaction(StateMachineInstance machineInstance, ProcessContext context)
|
||||
throws ExecutionException, TransactionException {
|
||||
GlobalTransaction globalTransaction = (GlobalTransaction) context.getVariable(DomainConstants.VAR_NAME_GLOBAL_TX);
|
||||
if (globalTransaction == null) {
|
||||
String xid;
|
||||
String parentId = machineInstance.getParentId();
|
||||
if (StringUtils.isEmpty(parentId)) {
|
||||
xid = machineInstance.getId();
|
||||
} else {
|
||||
xid = parentId.substring(0, parentId.lastIndexOf(DomainConstants.SEPERATOR_PARENT_ID));
|
||||
}
|
||||
globalTransaction = sagaTransactionalTemplate.reloadTransaction(xid);
|
||||
if (globalTransaction != null) {
|
||||
context.setVariable(DomainConstants.VAR_NAME_GLOBAL_TX, globalTransaction);
|
||||
}
|
||||
}
|
||||
return globalTransaction;
|
||||
}
|
||||
|
||||
/**
|
||||
* generate retry state instance id based on original state instance id
|
||||
* ${originalStateInstanceId}.${retryCount}
|
||||
* @param stateInstance
|
||||
* @return
|
||||
*/
|
||||
private String generateRetryStateInstanceId(StateInstance stateInstance) {
|
||||
String originalStateInstId = stateInstance.getStateIdRetriedFor();
|
||||
int maxIndex = 1;
|
||||
Map<String, StateInstance> stateInstanceMap = stateInstance.getStateMachineInstance().getStateMap();
|
||||
StateInstance originalStateInst = stateInstanceMap.get(stateInstance.getStateIdRetriedFor());
|
||||
while (StringUtils.hasLength(originalStateInst.getStateIdRetriedFor())) {
|
||||
originalStateInst = stateInstanceMap.get(originalStateInst.getStateIdRetriedFor());
|
||||
int idIndex = getIdIndex(originalStateInst.getId(), ".");
|
||||
maxIndex = idIndex > maxIndex ? idIndex : maxIndex;
|
||||
maxIndex++;
|
||||
}
|
||||
if (originalStateInst != null) {
|
||||
originalStateInstId = originalStateInst.getId();
|
||||
}
|
||||
return originalStateInstId + "." + maxIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* generate compensate state instance id based on original state instance id
|
||||
* ${originalStateInstanceId}-${retryCount}
|
||||
* @param stateInstance
|
||||
* @return
|
||||
*/
|
||||
private String generateCompensateStateInstanceId(StateInstance stateInstance, boolean isUpdateMode) {
|
||||
String originalCompensateStateInstId = stateInstance.getStateIdCompensatedFor();
|
||||
int maxIndex = 1;
|
||||
// if update mode, means update last compensate inst
|
||||
if (isUpdateMode) {
|
||||
return originalCompensateStateInstId + "-" + maxIndex;
|
||||
}
|
||||
|
||||
for (int i = 0; i < stateInstance.getStateMachineInstance().getStateList().size(); i++) {
|
||||
StateInstance aStateInstance = stateInstance.getStateMachineInstance().getStateList().get(i);
|
||||
if (aStateInstance != stateInstance
|
||||
&& originalCompensateStateInstId.equals(aStateInstance.getStateIdCompensatedFor())) {
|
||||
int idIndex = getIdIndex(aStateInstance.getId(), "-");
|
||||
maxIndex = idIndex > maxIndex ? idIndex : maxIndex;
|
||||
maxIndex++;
|
||||
}
|
||||
}
|
||||
return originalCompensateStateInstId + "-" + maxIndex;
|
||||
}
|
||||
|
||||
private int getIdIndex(String stateInstanceId, String separator) {
|
||||
if (StringUtils.hasLength(stateInstanceId)) {
|
||||
int start = stateInstanceId.lastIndexOf(separator);
|
||||
if (start > 0) {
|
||||
String indexStr = stateInstanceId.substring(start + 1, stateInstanceId.length());
|
||||
try {
|
||||
return Integer.parseInt(indexStr);
|
||||
} catch (NumberFormatException e) {
|
||||
LOGGER.warn("get stateInstance id index failed", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recordStateFinished(StateInstance stateInstance, ProcessContext context) {
|
||||
if (stateInstance != null) {
|
||||
|
||||
stateInstance.setSerializedOutputParams(paramsSerializer.serialize(stateInstance.getOutputParams()));
|
||||
stateInstance.setSerializedException(exceptionSerializer.serialize(stateInstance.getException()));
|
||||
executeUpdate(stateLogStoreSqls.getRecordStateFinishedSql(dbType), STATE_INSTANCE_TO_STATEMENT_FOR_UPDATE,
|
||||
stateInstance);
|
||||
|
||||
//A switch to skip branch report on branch success, in order to optimize performance
|
||||
StateMachineConfig stateMachineConfig = (StateMachineConfig) context.getVariable(
|
||||
DomainConstants.VAR_NAME_STATEMACHINE_CONFIG);
|
||||
if (!(stateMachineConfig instanceof DbStateMachineConfig
|
||||
&& !((DbStateMachineConfig)stateMachineConfig).isRmReportSuccessEnable()
|
||||
&& ExecutionStatus.SU.equals(stateInstance.getStatus()))) {
|
||||
branchReport(stateInstance, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private StateInstance findOutOriginalStateInstanceOfRetryState(StateInstance stateInstance) {
|
||||
StateInstance originalStateInst;
|
||||
Map<String, StateInstance> stateInstanceMap = stateInstance.getStateMachineInstance().getStateMap();
|
||||
originalStateInst = stateInstanceMap.get(stateInstance.getStateIdRetriedFor());
|
||||
while (StringUtils.hasLength(originalStateInst.getStateIdRetriedFor())) {
|
||||
originalStateInst = stateInstanceMap.get(originalStateInst.getStateIdRetriedFor());
|
||||
}
|
||||
return originalStateInst;
|
||||
}
|
||||
|
||||
private StateInstance findOutOriginalStateInstanceOfCompensateState(StateInstance stateInstance) {
|
||||
StateInstance originalStateInst;
|
||||
Map<String, StateInstance> stateInstanceMap = stateInstance.getStateMachineInstance().getStateMap();
|
||||
originalStateInst = stateInstance.getStateMachineInstance().getStateMap().get(stateInstance.getStateIdCompensatedFor());
|
||||
while (StringUtils.hasLength(originalStateInst.getStateIdRetriedFor())) {
|
||||
originalStateInst = stateInstanceMap.get(originalStateInst.getStateIdRetriedFor());
|
||||
}
|
||||
return originalStateInst;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateMachineInstance getStateMachineInstance(String stateMachineInstanceId) {
|
||||
StateMachineInstance stateMachineInstance = selectOne(stateLogStoreSqls.getGetStateMachineInstanceByIdSql(dbType),
|
||||
RESULT_SET_TO_STATE_MACHINE_INSTANCE, stateMachineInstanceId);
|
||||
if (stateMachineInstance == null) {
|
||||
return null;
|
||||
}
|
||||
List<StateInstance> stateInstanceList = queryStateInstanceListByMachineInstanceId(stateMachineInstanceId);
|
||||
for (StateInstance stateInstance : stateInstanceList) {
|
||||
stateMachineInstance.putStateInstance(stateInstance.getId(), stateInstance);
|
||||
}
|
||||
deserializeParamsAndException(stateMachineInstance);
|
||||
|
||||
return stateMachineInstance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateMachineInstance getStateMachineInstanceByBusinessKey(String businessKey, String tenantId) {
|
||||
if (StringUtils.isEmpty(tenantId)) {
|
||||
tenantId = defaultTenantId;
|
||||
}
|
||||
StateMachineInstance stateMachineInstance = selectOne(
|
||||
stateLogStoreSqls.getGetStateMachineInstanceByBusinessKeySql(dbType), RESULT_SET_TO_STATE_MACHINE_INSTANCE,
|
||||
businessKey, tenantId);
|
||||
if (stateMachineInstance == null) {
|
||||
return null;
|
||||
}
|
||||
List<StateInstance> stateInstanceList = queryStateInstanceListByMachineInstanceId(stateMachineInstance.getId());
|
||||
for (StateInstance stateInstance : stateInstanceList) {
|
||||
stateMachineInstance.putStateInstance(stateInstance.getId(), stateInstance);
|
||||
}
|
||||
deserializeParamsAndException(stateMachineInstance);
|
||||
|
||||
return stateMachineInstance;
|
||||
}
|
||||
|
||||
private void deserializeParamsAndException(StateMachineInstance stateMachineInstance) {
|
||||
byte[] serializedException = (byte[]) stateMachineInstance.getSerializedException();
|
||||
if (serializedException != null) {
|
||||
stateMachineInstance.setException((Exception) exceptionSerializer.deserialize(serializedException));
|
||||
}
|
||||
|
||||
String serializedStartParams = (String) stateMachineInstance.getSerializedStartParams();
|
||||
if (StringUtils.hasLength(serializedStartParams)) {
|
||||
stateMachineInstance.setStartParams(
|
||||
(Map<String, Object>) paramsSerializer.deserialize(serializedStartParams));
|
||||
}
|
||||
|
||||
String serializedEndParams = (String) stateMachineInstance.getSerializedEndParams();
|
||||
if (StringUtils.hasLength(serializedEndParams)) {
|
||||
stateMachineInstance.setEndParams((Map<String, Object>) paramsSerializer.deserialize(serializedEndParams));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StateMachineInstance> queryStateMachineInstanceByParentId(String parentId) {
|
||||
return selectList(stateLogStoreSqls.getQueryStateMachineInstancesByParentIdSql(dbType),
|
||||
RESULT_SET_TO_STATE_MACHINE_INSTANCE, parentId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateInstance getStateInstance(String stateInstanceId, String machineInstId) {
|
||||
StateInstance stateInstance = selectOne(
|
||||
stateLogStoreSqls.getGetStateInstanceByIdAndMachineInstanceIdSql(dbType), RESULT_SET_TO_STATE_INSTANCE,
|
||||
machineInstId, stateInstanceId);
|
||||
deserializeParamsAndException(stateInstance);
|
||||
return stateInstance;
|
||||
}
|
||||
|
||||
private void deserializeParamsAndException(StateInstance stateInstance) {
|
||||
if (stateInstance != null) {
|
||||
String inputParams = (String) stateInstance.getSerializedInputParams();
|
||||
if (StringUtils.hasLength(inputParams)) {
|
||||
stateInstance.setInputParams(paramsSerializer.deserialize(inputParams));
|
||||
}
|
||||
String outputParams = (String) stateInstance.getSerializedOutputParams();
|
||||
if (StringUtils.hasLength(outputParams)) {
|
||||
stateInstance.setOutputParams(paramsSerializer.deserialize(outputParams));
|
||||
}
|
||||
byte[] serializedException = (byte[]) stateInstance.getSerializedException();
|
||||
if (serializedException != null) {
|
||||
stateInstance.setException((Exception) exceptionSerializer.deserialize(serializedException));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StateInstance> queryStateInstanceListByMachineInstanceId(String stateMachineInstanceId) {
|
||||
List<StateInstance> stateInstanceList = selectList(
|
||||
stateLogStoreSqls.getQueryStateInstancesByMachineInstanceIdSql(dbType), RESULT_SET_TO_STATE_INSTANCE,
|
||||
stateMachineInstanceId);
|
||||
|
||||
if (CollectionUtils.isEmpty(stateInstanceList)) {
|
||||
return stateInstanceList;
|
||||
}
|
||||
StateInstance lastStateInstance = CollectionUtils.getLast(stateInstanceList);
|
||||
if (lastStateInstance.getGmtEnd() == null) {
|
||||
lastStateInstance.setStatus(ExecutionStatus.RU);
|
||||
}
|
||||
Map<String, StateInstance> originStateMap = new HashMap<>();
|
||||
Map<String/* originStateId */, StateInstance/* compensatedState */> compensatedStateMap = new HashMap<>();
|
||||
Map<String/* originStateId */, StateInstance/* retriedState */> retriedStateMap = new HashMap<>();
|
||||
for (StateInstance tempStateInstance : stateInstanceList) {
|
||||
deserializeParamsAndException(tempStateInstance);
|
||||
|
||||
if (StringUtils.hasText(tempStateInstance.getStateIdCompensatedFor())) {
|
||||
putLastStateToMap(compensatedStateMap, tempStateInstance, tempStateInstance.getStateIdCompensatedFor());
|
||||
} else {
|
||||
if (StringUtils.hasText(tempStateInstance.getStateIdRetriedFor())) {
|
||||
putLastStateToMap(retriedStateMap, tempStateInstance, tempStateInstance.getStateIdRetriedFor());
|
||||
}
|
||||
originStateMap.put(tempStateInstance.getId(), tempStateInstance);
|
||||
}
|
||||
}
|
||||
|
||||
if (compensatedStateMap.size() != 0) {
|
||||
for (StateInstance origState : originStateMap.values()) {
|
||||
origState.setCompensationState(compensatedStateMap.get(origState.getId()));
|
||||
}
|
||||
}
|
||||
|
||||
if (retriedStateMap.size() != 0) {
|
||||
for (StateInstance origState : originStateMap.values()) {
|
||||
if (retriedStateMap.containsKey(origState.getId())) {
|
||||
origState.setIgnoreStatus(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
return stateInstanceList;
|
||||
}
|
||||
|
||||
private void putLastStateToMap(Map<String, StateInstance> resultMap, StateInstance newState, String key) {
|
||||
if (!resultMap.containsKey(key)) {
|
||||
resultMap.put(key, newState);
|
||||
} else if (newState.getGmtEnd().after(resultMap.get(key).getGmtEnd())) {
|
||||
StateInstance oldState = resultMap.remove(key);
|
||||
oldState.setIgnoreStatus(true);
|
||||
|
||||
resultMap.put(key, newState);
|
||||
} else {
|
||||
newState.setIgnoreStatus(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void setExceptionSerializer(Serializer<Exception, byte[]> exceptionSerializer) {
|
||||
this.exceptionSerializer = exceptionSerializer;
|
||||
}
|
||||
|
||||
public SagaTransactionalTemplate getSagaTransactionalTemplate() {
|
||||
return sagaTransactionalTemplate;
|
||||
}
|
||||
|
||||
public void setSagaTransactionalTemplate(SagaTransactionalTemplate sagaTransactionalTemplate) {
|
||||
this.sagaTransactionalTemplate = sagaTransactionalTemplate;
|
||||
}
|
||||
|
||||
public Serializer<Object, String> getParamsSerializer() {
|
||||
return paramsSerializer;
|
||||
}
|
||||
|
||||
public void setParamsSerializer(Serializer<Object, String> paramsSerializer) {
|
||||
this.paramsSerializer = paramsSerializer;
|
||||
}
|
||||
|
||||
public String getDefaultTenantId() {
|
||||
return defaultTenantId;
|
||||
}
|
||||
|
||||
public void setDefaultTenantId(String defaultTenantId) {
|
||||
this.defaultTenantId = defaultTenantId;
|
||||
}
|
||||
|
||||
public void setSeqGenerator(SeqGenerator seqGenerator) {
|
||||
this.seqGenerator = seqGenerator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTablePrefix(String tablePrefix) {
|
||||
super.setTablePrefix(tablePrefix);
|
||||
this.stateLogStoreSqls = new StateLogStoreSqls(tablePrefix);
|
||||
}
|
||||
|
||||
private static class StateMachineInstanceToStatementForInsert implements ObjectToStatement<StateMachineInstance> {
|
||||
@Override
|
||||
public void toStatement(StateMachineInstance stateMachineInstance, PreparedStatement statement)
|
||||
throws SQLException {
|
||||
statement.setString(1, stateMachineInstance.getId());
|
||||
statement.setString(2, stateMachineInstance.getMachineId());
|
||||
statement.setString(3, stateMachineInstance.getTenantId());
|
||||
statement.setString(4, stateMachineInstance.getParentId());
|
||||
statement.setTimestamp(5, new Timestamp(stateMachineInstance.getGmtStarted().getTime()));
|
||||
statement.setString(6, stateMachineInstance.getBusinessKey());
|
||||
statement.setObject(7, stateMachineInstance.getSerializedStartParams());
|
||||
statement.setBoolean(8, stateMachineInstance.isRunning());
|
||||
statement.setString(9, stateMachineInstance.getStatus().name());
|
||||
statement.setTimestamp(10, new Timestamp(stateMachineInstance.getGmtUpdated().getTime()));
|
||||
}
|
||||
}
|
||||
|
||||
private static class StateMachineInstanceToStatementForUpdate implements ObjectToStatement<StateMachineInstance> {
|
||||
@Override
|
||||
public void toStatement(StateMachineInstance stateMachineInstance, PreparedStatement statement)
|
||||
throws SQLException {
|
||||
statement.setTimestamp(1, new Timestamp(stateMachineInstance.getGmtEnd().getTime()));
|
||||
statement.setBytes(2, stateMachineInstance.getSerializedException() != null ? (byte[]) stateMachineInstance
|
||||
.getSerializedException() : null);
|
||||
statement.setObject(3, stateMachineInstance.getSerializedEndParams());
|
||||
statement.setString(4, stateMachineInstance.getStatus().name());
|
||||
statement.setString(5,
|
||||
stateMachineInstance.getCompensationStatus() != null ? stateMachineInstance.getCompensationStatus()
|
||||
.name() : null);
|
||||
statement.setBoolean(6, stateMachineInstance.isRunning());
|
||||
statement.setTimestamp(7, new Timestamp(System.currentTimeMillis()));
|
||||
statement.setString(8, stateMachineInstance.getId());
|
||||
statement.setTimestamp(9, new Timestamp(stateMachineInstance.getGmtUpdated().getTime()));
|
||||
}
|
||||
}
|
||||
|
||||
private static class StateInstanceToStatementForInsert implements ObjectToStatement<StateInstance> {
|
||||
@Override
|
||||
public void toStatement(StateInstance stateInstance, PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, stateInstance.getId());
|
||||
statement.setString(2, stateInstance.getMachineInstanceId());
|
||||
statement.setString(3, stateInstance.getName());
|
||||
statement.setString(4, stateInstance.getType());
|
||||
statement.setTimestamp(5, new Timestamp(stateInstance.getGmtStarted().getTime()));
|
||||
statement.setString(6, stateInstance.getServiceName());
|
||||
statement.setString(7, stateInstance.getServiceMethod());
|
||||
statement.setString(8, stateInstance.getServiceType());
|
||||
statement.setBoolean(9, stateInstance.isForUpdate());
|
||||
statement.setObject(10, stateInstance.getSerializedInputParams());
|
||||
statement.setString(11, stateInstance.getStatus().name());
|
||||
statement.setString(12, stateInstance.getBusinessKey());
|
||||
statement.setString(13, stateInstance.getStateIdCompensatedFor());
|
||||
statement.setString(14, stateInstance.getStateIdRetriedFor());
|
||||
statement.setTimestamp(15, new Timestamp(stateInstance.getGmtUpdated().getTime()));
|
||||
}
|
||||
}
|
||||
|
||||
private static class StateInstanceToStatementForUpdate implements ObjectToStatement<StateInstance> {
|
||||
@Override
|
||||
public void toStatement(StateInstance stateInstance, PreparedStatement statement) throws SQLException {
|
||||
statement.setTimestamp(1, new Timestamp(stateInstance.getGmtEnd().getTime()));
|
||||
statement.setBytes(2,
|
||||
stateInstance.getException() != null ? (byte[]) stateInstance.getSerializedException() : null);
|
||||
statement.setString(3, stateInstance.getStatus().name());
|
||||
statement.setObject(4, stateInstance.getSerializedOutputParams());
|
||||
statement.setTimestamp(5, new Timestamp(stateInstance.getGmtEnd().getTime()));
|
||||
statement.setString(6, stateInstance.getId());
|
||||
statement.setString(7, stateInstance.getMachineInstanceId());
|
||||
}
|
||||
}
|
||||
|
||||
private static class ResultSetToStateMachineInstance implements ResultSetToObject<StateMachineInstance> {
|
||||
@Override
|
||||
public StateMachineInstance toObject(ResultSet resultSet) throws SQLException {
|
||||
StateMachineInstanceImpl stateMachineInstance = new StateMachineInstanceImpl();
|
||||
stateMachineInstance.setId(resultSet.getString("id"));
|
||||
stateMachineInstance.setMachineId(resultSet.getString("machine_id"));
|
||||
stateMachineInstance.setTenantId(resultSet.getString("tenant_id"));
|
||||
stateMachineInstance.setParentId(resultSet.getString("parent_id"));
|
||||
stateMachineInstance.setBusinessKey(resultSet.getString("business_key"));
|
||||
stateMachineInstance.setGmtStarted(resultSet.getTimestamp("gmt_started"));
|
||||
stateMachineInstance.setGmtEnd(resultSet.getTimestamp("gmt_end"));
|
||||
stateMachineInstance.setStatus(ExecutionStatus.valueOf(resultSet.getString("status")));
|
||||
|
||||
String compensationStatusName = resultSet.getString("compensation_status");
|
||||
if (StringUtils.hasLength(compensationStatusName)) {
|
||||
stateMachineInstance.setCompensationStatus(ExecutionStatus.valueOf(compensationStatusName));
|
||||
}
|
||||
stateMachineInstance.setRunning(resultSet.getBoolean("is_running"));
|
||||
stateMachineInstance.setGmtUpdated(resultSet.getTimestamp("gmt_updated"));
|
||||
|
||||
if (resultSet.getMetaData().getColumnCount() > 11) {
|
||||
stateMachineInstance.setSerializedStartParams(resultSet.getString("start_params"));
|
||||
stateMachineInstance.setSerializedEndParams(resultSet.getString("end_params"));
|
||||
stateMachineInstance.setSerializedException(resultSet.getBytes("excep"));
|
||||
}
|
||||
return stateMachineInstance;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ResultSetToStateInstance implements ResultSetToObject<StateInstance> {
|
||||
@Override
|
||||
public StateInstance toObject(ResultSet resultSet) throws SQLException {
|
||||
StateInstanceImpl stateInstance = new StateInstanceImpl();
|
||||
stateInstance.setId(resultSet.getString("id"));
|
||||
stateInstance.setMachineInstanceId(resultSet.getString("machine_inst_id"));
|
||||
stateInstance.setName(resultSet.getString("name"));
|
||||
stateInstance.setType(resultSet.getString("type"));
|
||||
stateInstance.setBusinessKey(resultSet.getString("business_key"));
|
||||
stateInstance.setStatus(ExecutionStatus.valueOf(resultSet.getString("status")));
|
||||
stateInstance.setGmtStarted(resultSet.getTimestamp("gmt_started"));
|
||||
stateInstance.setGmtEnd(resultSet.getTimestamp("gmt_end"));
|
||||
stateInstance.setServiceName(resultSet.getString("service_name"));
|
||||
stateInstance.setServiceMethod(resultSet.getString("service_method"));
|
||||
stateInstance.setServiceType(resultSet.getString("service_type"));
|
||||
stateInstance.setForUpdate(resultSet.getBoolean("is_for_update"));
|
||||
stateInstance.setStateIdCompensatedFor(resultSet.getString("state_id_compensated_for"));
|
||||
stateInstance.setStateIdRetriedFor(resultSet.getString("state_id_retried_for"));
|
||||
stateInstance.setSerializedInputParams(resultSet.getString("input_params"));
|
||||
stateInstance.setSerializedOutputParams(resultSet.getString("output_params"));
|
||||
stateInstance.setSerializedException(resultSet.getBytes("excep"));
|
||||
|
||||
return stateInstance;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.seata.saga.engine.store.db;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.List;
|
||||
|
||||
import io.seata.common.util.CollectionUtils;
|
||||
import io.seata.common.util.StringUtils;
|
||||
import io.seata.saga.engine.store.StateLangStore;
|
||||
import io.seata.saga.statelang.domain.RecoverStrategy;
|
||||
import io.seata.saga.statelang.domain.StateMachine;
|
||||
import io.seata.saga.statelang.domain.StateMachine.Status;
|
||||
import io.seata.saga.statelang.domain.impl.StateMachineImpl;
|
||||
|
||||
/**
|
||||
* State language definition store in DB
|
||||
*
|
||||
* @author lorne.cl
|
||||
*/
|
||||
public class DbStateLangStore extends AbstractStore implements StateLangStore {
|
||||
|
||||
private static final ResultSetToStateMachine RESULT_SET_TO_STATE_MACHINE = new ResultSetToStateMachine();
|
||||
|
||||
private static final StateMachineToStatement STATE_MACHINE_TO_STATEMENT = new StateMachineToStatement();
|
||||
|
||||
private StateLangStoreSqls stateLangStoreSqls;
|
||||
|
||||
@Override
|
||||
public StateMachine getStateMachineById(String stateMachineId) {
|
||||
return selectOne(stateLangStoreSqls.getGetStateMachineByIdSql(dbType), RESULT_SET_TO_STATE_MACHINE,
|
||||
stateMachineId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateMachine getLastVersionStateMachine(String stateMachineName, String tenantId) {
|
||||
List<StateMachine> list = selectList(stateLangStoreSqls.getQueryStateMachinesByNameAndTenantSql(dbType),
|
||||
RESULT_SET_TO_STATE_MACHINE, stateMachineName, tenantId);
|
||||
if (CollectionUtils.isNotEmpty(list)) {
|
||||
return list.get(0);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean storeStateMachine(StateMachine stateMachine) {
|
||||
return executeUpdate(stateLangStoreSqls.getInsertStateMachineSql(dbType), STATE_MACHINE_TO_STATEMENT,
|
||||
stateMachine) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTablePrefix(String tablePrefix) {
|
||||
super.setTablePrefix(tablePrefix);
|
||||
this.stateLangStoreSqls = new StateLangStoreSqls(tablePrefix);
|
||||
}
|
||||
|
||||
private static class ResultSetToStateMachine implements ResultSetToObject<StateMachine> {
|
||||
@Override
|
||||
public StateMachine toObject(ResultSet resultSet) throws SQLException {
|
||||
StateMachineImpl stateMachine = new StateMachineImpl();
|
||||
stateMachine.setId(resultSet.getString("id"));
|
||||
stateMachine.setName(resultSet.getString("name"));
|
||||
stateMachine.setComment(resultSet.getString("comment_"));
|
||||
stateMachine.setVersion(resultSet.getString("ver"));
|
||||
stateMachine.setAppName(resultSet.getString("app_name"));
|
||||
stateMachine.setContent(resultSet.getString("content"));
|
||||
stateMachine.setGmtCreate(resultSet.getTimestamp("gmt_create"));
|
||||
stateMachine.setType(resultSet.getString("type"));
|
||||
String recoverStrategy = resultSet.getString("recover_strategy");
|
||||
if (StringUtils.isNotBlank(recoverStrategy)) {
|
||||
stateMachine.setRecoverStrategy(RecoverStrategy.valueOf(recoverStrategy));
|
||||
}
|
||||
stateMachine.setTenantId(resultSet.getString("tenant_id"));
|
||||
stateMachine.setStatus(Status.valueOf(resultSet.getString("status")));
|
||||
return stateMachine;
|
||||
}
|
||||
}
|
||||
|
||||
private static class StateMachineToStatement implements ObjectToStatement<StateMachine> {
|
||||
@Override
|
||||
public void toStatement(StateMachine stateMachine, PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, stateMachine.getId());
|
||||
statement.setString(2, stateMachine.getTenantId());
|
||||
statement.setString(3, stateMachine.getAppName());
|
||||
statement.setString(4, stateMachine.getName());
|
||||
statement.setString(5, stateMachine.getStatus().name());
|
||||
statement.setTimestamp(6, new Timestamp(stateMachine.getGmtCreate().getTime()));
|
||||
statement.setString(7, stateMachine.getVersion());
|
||||
statement.setString(8, stateMachine.getType());
|
||||
statement.setString(9, stateMachine.getContent());
|
||||
statement.setString(10, stateMachine.getRecoverStrategy() != null ? stateMachine.getRecoverStrategy().name() : null);
|
||||
statement.setString(11, stateMachine.getComment());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.seata.saga.engine.store.db;
|
||||
|
||||
/**
|
||||
* StateLang store sqls
|
||||
*
|
||||
* @author lorne.cl
|
||||
*/
|
||||
public class StateLangStoreSqls {
|
||||
|
||||
private static final String STATE_MACHINE_FIELDS
|
||||
= "id, tenant_id, app_name, name, status, gmt_create, ver, type, content, recover_strategy, comment_";
|
||||
|
||||
private static final String GET_STATE_MACHINE_BY_ID_SQL = "SELECT " + STATE_MACHINE_FIELDS
|
||||
+ " FROM ${TABLE_PREFIX}state_machine_def WHERE id = ?";
|
||||
|
||||
private static final String QUERY_STATE_MACHINES_BY_NAME_AND_TENANT_SQL = "SELECT " + STATE_MACHINE_FIELDS
|
||||
+ " FROM ${TABLE_PREFIX}state_machine_def WHERE name = ? AND tenant_id = ? ORDER BY gmt_create DESC";
|
||||
|
||||
private static final String INSERT_STATE_MACHINE_SQL = "INSERT INTO ${TABLE_PREFIX}state_machine_def ("
|
||||
+ STATE_MACHINE_FIELDS + ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
|
||||
private static final String TABLE_PREFIX_REGEX = "\\$\\{TABLE_PREFIX}";
|
||||
|
||||
private String tablePrefix;
|
||||
|
||||
private String getGetStateMachineByIdSql;
|
||||
private String queryStateMachinesByNameAndTenantSql;
|
||||
private String insertStateMachineSql;
|
||||
|
||||
public StateLangStoreSqls(String tablePrefix) {
|
||||
this.tablePrefix = tablePrefix;
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
getGetStateMachineByIdSql = GET_STATE_MACHINE_BY_ID_SQL.replaceAll(TABLE_PREFIX_REGEX, tablePrefix);
|
||||
queryStateMachinesByNameAndTenantSql = QUERY_STATE_MACHINES_BY_NAME_AND_TENANT_SQL.replaceAll(
|
||||
TABLE_PREFIX_REGEX, tablePrefix);
|
||||
insertStateMachineSql = INSERT_STATE_MACHINE_SQL.replaceAll(TABLE_PREFIX_REGEX, tablePrefix);
|
||||
}
|
||||
|
||||
public String getGetStateMachineByIdSql(String dbType) {
|
||||
return getGetStateMachineByIdSql;
|
||||
}
|
||||
|
||||
public String getQueryStateMachinesByNameAndTenantSql(String dbType) {
|
||||
return queryStateMachinesByNameAndTenantSql;
|
||||
}
|
||||
|
||||
public String getInsertStateMachineSql(String dbType) {
|
||||
return insertStateMachineSql;
|
||||
}
|
||||
|
||||
public String getTablePrefix() {
|
||||
return tablePrefix;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.seata.saga.engine.store.db;
|
||||
|
||||
/**
|
||||
* State log store sqls
|
||||
*
|
||||
* @author lorne.cl
|
||||
*/
|
||||
public class StateLogStoreSqls {
|
||||
|
||||
/**
|
||||
* machine instance
|
||||
**/
|
||||
private static final String STATE_MACHINE_INSTANCE_FIELDS
|
||||
= "id, machine_id, tenant_id, parent_id, business_key, gmt_started, gmt_end, status, compensation_status, "
|
||||
+ "is_running, gmt_updated, start_params, end_params, excep";
|
||||
|
||||
private static final String STATE_MACHINE_INSTANCE_FIELDS_WITHOUT_PARAMS
|
||||
= "id, machine_id, tenant_id, parent_id, business_key, gmt_started, gmt_end, status, compensation_status, "
|
||||
+ "is_running, gmt_updated";
|
||||
|
||||
private static final String RECORD_STATE_MACHINE_STARTED_SQL = "INSERT INTO ${TABLE_PREFIX}state_machine_inst\n"
|
||||
+ "(id, machine_id, tenant_id, parent_id, gmt_started, business_key, start_params, is_running, status, "
|
||||
+ "gmt_updated)\n"
|
||||
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
|
||||
private static final String RECORD_STATE_MACHINE_FINISHED_SQL
|
||||
= "UPDATE ${TABLE_PREFIX}state_machine_inst SET gmt_end = ?, excep = ?, end_params = ?,status = ?, "
|
||||
+ "compensation_status = ?, is_running = ?, gmt_updated = ? WHERE id = ? and gmt_updated = ?";
|
||||
|
||||
private static final String UPDATE_STATE_MACHINE_RUNNING_STATUS_SQL =
|
||||
"UPDATE ${TABLE_PREFIX}state_machine_inst SET\n"
|
||||
+ "is_running = ?, gmt_updated = ? where id = ? and gmt_updated = ?";
|
||||
|
||||
private static final String GET_STATE_MACHINE_INSTANCE_BY_ID_SQL = "SELECT " + STATE_MACHINE_INSTANCE_FIELDS
|
||||
+ " FROM ${TABLE_PREFIX}state_machine_inst WHERE id = ?";
|
||||
|
||||
private static final String GET_STATE_MACHINE_INSTANCE_BY_BUSINESS_KEY_SQL = "SELECT "
|
||||
+ STATE_MACHINE_INSTANCE_FIELDS
|
||||
+ " FROM ${TABLE_PREFIX}state_machine_inst WHERE business_key = ? AND tenant_id = ?";
|
||||
|
||||
private static final String QUERY_STATE_MACHINE_INSTANCES_BY_PARENT_ID_SQL = "SELECT "
|
||||
+ STATE_MACHINE_INSTANCE_FIELDS_WITHOUT_PARAMS
|
||||
+ " FROM ${TABLE_PREFIX}state_machine_inst WHERE parent_id = ? ORDER BY gmt_started DESC";
|
||||
|
||||
/**
|
||||
* state instance
|
||||
**/
|
||||
private static final String STATE_INSTANCE_FIELDS
|
||||
= "id, machine_inst_id, name, type, business_key, gmt_started, service_name, service_method, service_type, "
|
||||
+ "is_for_update, status, input_params, output_params, excep, gmt_end, state_id_compensated_for, "
|
||||
+ "state_id_retried_for";
|
||||
|
||||
private static final String RECORD_STATE_STARTED_SQL =
|
||||
"INSERT INTO ${TABLE_PREFIX}state_inst (id, machine_inst_id, name, type,"
|
||||
+ " gmt_started, service_name, service_method, service_type, is_for_update, input_params, status, "
|
||||
+ "business_key, state_id_compensated_for, state_id_retried_for, gmt_updated)\n"
|
||||
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
|
||||
private static final String RECORD_STATE_FINISHED_SQL =
|
||||
"UPDATE ${TABLE_PREFIX}state_inst SET gmt_end = ?, excep = ?, status = ?, output_params = ?, gmt_updated = ? "
|
||||
+ "WHERE id = ? AND machine_inst_id = ?";
|
||||
|
||||
private static final String UPDATE_STATE_EXECUTION_STATUS_SQL
|
||||
= "UPDATE ${TABLE_PREFIX}state_inst SET status = ?, gmt_updated = ? WHERE machine_inst_id = ? AND id = ?";
|
||||
|
||||
private static final String QUERY_STATE_INSTANCES_BY_MACHINE_INSTANCE_ID_SQL = "SELECT " + STATE_INSTANCE_FIELDS
|
||||
+ " FROM ${TABLE_PREFIX}state_inst WHERE machine_inst_id = ? ORDER BY gmt_started, ID ASC";
|
||||
|
||||
private static final String GET_STATE_INSTANCE_BY_ID_AND_MACHINE_INSTANCE_ID_SQL = "SELECT " + STATE_INSTANCE_FIELDS
|
||||
+ " FROM ${TABLE_PREFIX}state_inst WHERE machine_inst_id = ? AND id = ?";
|
||||
|
||||
private static final String TABLE_PREFIX_REGEX = "\\$\\{TABLE_PREFIX}";
|
||||
|
||||
private String tablePrefix;
|
||||
|
||||
/**
|
||||
* machine instance
|
||||
**/
|
||||
private String recordStateMachineStartedSql;
|
||||
|
||||
private String recordStateMachineFinishedSql;
|
||||
|
||||
private String updateStateMachineRunningStatusSql;
|
||||
|
||||
private String getStateMachineInstanceByIdSql;
|
||||
|
||||
private String getStateMachineInstanceByBusinessKeySql;
|
||||
|
||||
private String queryStateMachineInstancesByParentIdSql;
|
||||
|
||||
/**
|
||||
* state instance
|
||||
**/
|
||||
private String recordStateStartedSql;
|
||||
|
||||
private String recordStateFinishedSql;
|
||||
|
||||
private String updateStateExecutionStatusSql;
|
||||
|
||||
private String queryStateInstancesByMachineInstanceIdSql;
|
||||
|
||||
private String getStateInstanceByIdAndMachineInstanceIdSql;
|
||||
|
||||
public StateLogStoreSqls(String tablePrefix) {
|
||||
this.tablePrefix = tablePrefix;
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
recordStateMachineStartedSql = RECORD_STATE_MACHINE_STARTED_SQL.replaceAll(TABLE_PREFIX_REGEX, tablePrefix);
|
||||
recordStateMachineFinishedSql = RECORD_STATE_MACHINE_FINISHED_SQL.replaceAll(TABLE_PREFIX_REGEX, tablePrefix);
|
||||
updateStateMachineRunningStatusSql = UPDATE_STATE_MACHINE_RUNNING_STATUS_SQL.replaceAll(TABLE_PREFIX_REGEX,
|
||||
tablePrefix);
|
||||
getStateMachineInstanceByIdSql = GET_STATE_MACHINE_INSTANCE_BY_ID_SQL.replaceAll(TABLE_PREFIX_REGEX,
|
||||
tablePrefix);
|
||||
getStateMachineInstanceByBusinessKeySql = GET_STATE_MACHINE_INSTANCE_BY_BUSINESS_KEY_SQL.replaceAll(
|
||||
TABLE_PREFIX_REGEX, tablePrefix);
|
||||
queryStateMachineInstancesByParentIdSql = QUERY_STATE_MACHINE_INSTANCES_BY_PARENT_ID_SQL.replaceAll(
|
||||
TABLE_PREFIX_REGEX, tablePrefix);
|
||||
|
||||
recordStateStartedSql = RECORD_STATE_STARTED_SQL.replaceAll(TABLE_PREFIX_REGEX, tablePrefix);
|
||||
recordStateFinishedSql = RECORD_STATE_FINISHED_SQL.replaceAll(TABLE_PREFIX_REGEX, tablePrefix);
|
||||
updateStateExecutionStatusSql = UPDATE_STATE_EXECUTION_STATUS_SQL.replaceAll(TABLE_PREFIX_REGEX, tablePrefix);
|
||||
queryStateInstancesByMachineInstanceIdSql = QUERY_STATE_INSTANCES_BY_MACHINE_INSTANCE_ID_SQL.replaceAll(
|
||||
TABLE_PREFIX_REGEX, tablePrefix);
|
||||
getStateInstanceByIdAndMachineInstanceIdSql = GET_STATE_INSTANCE_BY_ID_AND_MACHINE_INSTANCE_ID_SQL.replaceAll(
|
||||
TABLE_PREFIX_REGEX, tablePrefix);
|
||||
}
|
||||
|
||||
public String getRecordStateMachineStartedSql(String dbType) {
|
||||
return recordStateMachineStartedSql;
|
||||
}
|
||||
|
||||
public String getRecordStateMachineFinishedSql(String dbType) {
|
||||
return recordStateMachineFinishedSql;
|
||||
}
|
||||
|
||||
public String getUpdateStateMachineRunningStatusSql(String dbType) {
|
||||
return updateStateMachineRunningStatusSql;
|
||||
}
|
||||
|
||||
public String getGetStateMachineInstanceByIdSql(String dbType) {
|
||||
return getStateMachineInstanceByIdSql;
|
||||
}
|
||||
|
||||
public String getGetStateMachineInstanceByBusinessKeySql(String dbType) {
|
||||
return getStateMachineInstanceByBusinessKeySql;
|
||||
}
|
||||
|
||||
public String getQueryStateMachineInstancesByParentIdSql(String dbType) {
|
||||
return queryStateMachineInstancesByParentIdSql;
|
||||
}
|
||||
|
||||
public String getRecordStateStartedSql(String dbType) {
|
||||
return recordStateStartedSql;
|
||||
}
|
||||
|
||||
public String getRecordStateFinishedSql(String dbType) {
|
||||
return recordStateFinishedSql;
|
||||
}
|
||||
|
||||
public String getUpdateStateExecutionStatusSql(String dbType) {
|
||||
return updateStateExecutionStatusSql;
|
||||
}
|
||||
|
||||
public String getQueryStateInstancesByMachineInstanceIdSql(String dbType) {
|
||||
return queryStateInstancesByMachineInstanceIdSql;
|
||||
}
|
||||
|
||||
public String getGetStateInstanceByIdAndMachineInstanceIdSql(String dbType) {
|
||||
return getStateInstanceByIdAndMachineInstanceIdSql;
|
||||
}
|
||||
|
||||
public String getTablePrefix() {
|
||||
return tablePrefix;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
io.seata.saga.engine.pcext.interceptors.InSagaBranchHandlerInterceptor
|
||||
Reference in New Issue
Block a user