diff --git a/pigx-common/pigx-common-core/src/main/resources/banner.txt b/pigx-common/pigx-common-core/src/main/resources/banner.txt
new file mode 100644
index 000000000..63be6e1eb
--- /dev/null
+++ b/pigx-common/pigx-common-core/src/main/resources/banner.txt
@@ -0,0 +1,16 @@
+${AnsiColor.BRIGHT_YELLOW}
+
+ ::::::::: ::::::::::: :::::::: ::: :::
+ :+: :+: :+: :+: :+: :+: :+:
+ +:+ +:+ +:+ +:+ +:+ +:+
+ +#++:++#+ +#+ :#: +#++:+
+ +#+ +#+ +#+ +#+# +#+ +#+
+ #+# #+# #+# #+# #+# #+#
+ ### ########### ######## ### ###
+
+ www.pig4cloud.com
+
+ Pig Microservice Architecture
+
+
+
diff --git a/pigx-common/pigx-common-transaction/pom.xml b/pigx-common/pigx-common-transaction/pom.xml
new file mode 100644
index 000000000..bb506510d
--- /dev/null
+++ b/pigx-common/pigx-common-transaction/pom.xml
@@ -0,0 +1,30 @@
+
+
+ 4.0.0
+
+ com.pig4cloud
+ pigx-common
+ ${pigx.version}
+
+
+ pigx-common-transaction
+ ${pigx.version}
+ jar
+ pigx-common-transaction
+ pigx lcn transaction
+
+
+
+
+ com.codingapi
+ tx-client
+ ${lcn.version}
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-openfeign
+
+
+
diff --git a/pigx-common/pigx-common-transaction/src/main/java/com/pig4cloud/pigx/common/transaction/pack-info.md b/pigx-common/pigx-common-transaction/src/main/java/com/pig4cloud/pigx/common/transaction/pack-info.md
new file mode 100644
index 000000000..d48381f67
--- /dev/null
+++ b/pigx-common/pigx-common-transaction/src/main/java/com/pig4cloud/pigx/common/transaction/pack-info.md
@@ -0,0 +1,6 @@
+由于LCN 暂未发布适配 2.0 版本
+当前包是根据TCN transaction-springcloud 模块修改而来
+解决LCN 不兼容 Spring Cloud Finchley 问题
+
+关于LCN
+https://github.com/codingapi/tx-lcn
diff --git a/pigx-common/pigx-common-transaction/src/main/java/com/pig4cloud/pigx/common/transaction/ribbon/loadbalancer/LcnLoadBalancerRule.java b/pigx-common/pigx-common-transaction/src/main/java/com/pig4cloud/pigx/common/transaction/ribbon/loadbalancer/LcnLoadBalancerRule.java
new file mode 100755
index 000000000..594f04bad
--- /dev/null
+++ b/pigx-common/pigx-common-transaction/src/main/java/com/pig4cloud/pigx/common/transaction/ribbon/loadbalancer/LcnLoadBalancerRule.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.transaction.ribbon.loadbalancer;
+
+
+import com.codingapi.tx.aop.bean.TxTransactionLocal;
+import com.lorne.core.framework.utils.encode.MD5Util;
+import com.netflix.loadbalancer.Server;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang.StringUtils;
+
+import java.util.List;
+
+/**
+ * created by foxdd 2017-12-05
+ *
+ * @author LCN
+ * @since 4.1.0
+ */
+@Slf4j
+public class LcnLoadBalancerRule {
+
+ public Server proxy(List servers, Server server) {
+
+ TxTransactionLocal txTransactionLocal = TxTransactionLocal.current();
+ if (txTransactionLocal == null) {
+ return server;
+ }
+
+ try {
+ log.debug("LCNBalanceProxy - > start");
+
+ String groupId = txTransactionLocal.getGroupId();
+
+ //取出组件的appName
+ String appName = server.getMetaInfo().getAppName();
+
+
+ String key = MD5Util.md5((groupId + "_" + appName).getBytes());
+
+ //如果只有一个可调用模块,则用当前的,且需要将数据记录到redis中
+ if (servers.size() == 1) {
+ putServer(key, txTransactionLocal, server);
+ log.debug("LCNBalanceProxy -> only one server available");
+ return server;
+ }
+
+ Server oldServer = getServer(txTransactionLocal, servers, key);
+ if (oldServer != null) {
+ log.debug("LCNBalanceProxy - > load old server ");
+ return server;
+ }
+
+ putServer(key, txTransactionLocal, server);
+ log.debug("LCNBalanceProxy - > load new server ");
+
+ return server;
+ } finally {
+ log.debug("LCNBalanceProxy - > end");
+ }
+ }
+
+
+ private void putServer(String key, TxTransactionLocal txTransactionLocal, Server server) {
+ String serviceName = server.getMetaInfo().getAppName();
+ String address = server.getHostPort();
+
+ String md5 = MD5Util.md5((address + serviceName).getBytes());
+
+ log.debug("putServer->address->" + address + ",md5-->" + md5);
+
+ txTransactionLocal.putLoadBalance(key, md5);
+ }
+
+
+ private Server getServer(TxTransactionLocal txTransactionLocal, List servers, String key) {
+ String val = txTransactionLocal.getLoadBalance(key);
+ if (StringUtils.isEmpty(val)) {
+ return null;
+ }
+ for (Server server : servers) {
+ String serviceName = server.getMetaInfo().getAppName();
+ String address = server.getHostPort();
+
+ String md5 = MD5Util.md5((address + serviceName).getBytes());
+
+ log.debug("getServer->address->" + address + ",md5-->" + md5);
+
+ if (val.equals(md5)) {
+ return server;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/pigx-common/pigx-common-transaction/src/main/java/com/pig4cloud/pigx/common/transaction/ribbon/loadbalancer/LcnNoOpLoadBalancerProxy.java b/pigx-common/pigx-common-transaction/src/main/java/com/pig4cloud/pigx/common/transaction/ribbon/loadbalancer/LcnNoOpLoadBalancerProxy.java
new file mode 100755
index 000000000..643357b06
--- /dev/null
+++ b/pigx-common/pigx-common-transaction/src/main/java/com/pig4cloud/pigx/common/transaction/ribbon/loadbalancer/LcnNoOpLoadBalancerProxy.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.transaction.ribbon.loadbalancer;
+
+import com.netflix.loadbalancer.NoOpLoadBalancer;
+import com.netflix.loadbalancer.Server;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * created by foxdd 2017-12-05
+ *
+ * @author LCN
+ * @since 4.1.0
+ */
+@Slf4j
+public class LcnNoOpLoadBalancerProxy extends NoOpLoadBalancer {
+
+ private LcnLoadBalancerRule lcnLoadBalancerRule = new LcnLoadBalancerRule();
+
+ public LcnNoOpLoadBalancerProxy() {
+ super();
+ }
+
+ @Override
+ public Server chooseServer(Object key) {
+ log.debug("enter chooseServer method, key:" + key);
+
+ List serverList = new ArrayList();
+ return lcnLoadBalancerRule.proxy(serverList, super.chooseServer(key));
+
+ }
+
+}
diff --git a/pigx-common/pigx-common-transaction/src/main/java/com/pig4cloud/pigx/common/transaction/ribbon/loadbalancer/LcnRibbonConfiguration.java b/pigx-common/pigx-common-transaction/src/main/java/com/pig4cloud/pigx/common/transaction/ribbon/loadbalancer/LcnRibbonConfiguration.java
new file mode 100755
index 000000000..d0effe101
--- /dev/null
+++ b/pigx-common/pigx-common-transaction/src/main/java/com/pig4cloud/pigx/common/transaction/ribbon/loadbalancer/LcnRibbonConfiguration.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.transaction.ribbon.loadbalancer;
+
+import com.netflix.client.config.IClientConfig;
+import com.netflix.loadbalancer.*;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author LCN
+ * @since 4.1.0
+ */
+@Configuration
+public class LcnRibbonConfiguration {
+
+ /**
+ * 为ribbon的loadbalancer做代理,相比于重写IRULE,重写loadbalancer更有利于用户自选LB算法,而且有默认LB算法可用
+ *
+ * @param config
+ * @param serverList
+ * @param serverListFilter
+ * @param rule
+ * @param ping
+ * @param serverListUpdater
+ * @return
+ */
+ @Bean
+ public ILoadBalancer ribbonLoadBalancer(IClientConfig config,
+ ServerList serverList, ServerListFilter serverListFilter,
+ IRule rule, IPing ping, ServerListUpdater serverListUpdater) {
+ return new LcnZoneAwareLoadBalancerProxy(config, rule, ping, serverList,
+ serverListFilter, serverListUpdater);
+ }
+
+
+}
diff --git a/pigx-common/pigx-common-transaction/src/main/java/com/pig4cloud/pigx/common/transaction/ribbon/loadbalancer/LcnZoneAwareLoadBalancerProxy.java b/pigx-common/pigx-common-transaction/src/main/java/com/pig4cloud/pigx/common/transaction/ribbon/loadbalancer/LcnZoneAwareLoadBalancerProxy.java
new file mode 100755
index 000000000..cee16d10e
--- /dev/null
+++ b/pigx-common/pigx-common-transaction/src/main/java/com/pig4cloud/pigx/common/transaction/ribbon/loadbalancer/LcnZoneAwareLoadBalancerProxy.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.transaction.ribbon.loadbalancer;
+
+import com.netflix.client.config.IClientConfig;
+import com.netflix.loadbalancer.*;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.List;
+
+/**
+ * created by foxdd 2017-12-05
+ *
+ * @author LCN
+ * @since 4.1.0
+ */
+@Slf4j
+public class LcnZoneAwareLoadBalancerProxy extends ZoneAwareLoadBalancer {
+
+ LcnLoadBalancerRule lcnLoadBalancerRule = new LcnLoadBalancerRule();
+
+ public LcnZoneAwareLoadBalancerProxy(IClientConfig clientConfig, IRule rule,
+ IPing ping, ServerList serverList, ServerListFilter filter,
+ ServerListUpdater serverListUpdater) {
+ super(clientConfig, rule, ping, serverList, filter, serverListUpdater);
+ }
+
+ @Override
+ public Server chooseServer(Object key) {
+ log.info("enter chooseServer method, key:" + key);
+ //利用Dynamic负载类中的方法,可以在运行时更新服务实例清单
+ List serverList;
+ //获取处理之后的serverlist
+ serverList = super.getServerListImpl().getUpdatedListOfServers();
+ //获取过滤之后的serverlist
+ serverList = super.getFilter().getFilteredListOfServers(serverList);
+ if (null == serverList || serverList.isEmpty()) {
+ return super.chooseServer(key);
+ }
+ return lcnLoadBalancerRule.proxy(serverList, super.chooseServer(key));
+
+ }
+
+}
diff --git a/pigx-common/pigx-common-transaction/src/main/java/com/pig4cloud/pigx/common/transaction/tx/RequestInterceptorConfiguration.java b/pigx-common/pigx-common-transaction/src/main/java/com/pig4cloud/pigx/common/transaction/tx/RequestInterceptorConfiguration.java
new file mode 100755
index 000000000..c482d4c73
--- /dev/null
+++ b/pigx-common/pigx-common-transaction/src/main/java/com/pig4cloud/pigx/common/transaction/tx/RequestInterceptorConfiguration.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.transaction.tx;
+
+import com.pig4cloud.pigx.common.transaction.tx.springcloud.feign.TransactionRestTemplateInterceptor;
+import feign.RequestInterceptor;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * create by lorne on 2018/1/18
+ *
+ * @author LCN
+ * @since 4.1.0
+ */
+@Configuration
+public class RequestInterceptorConfiguration {
+
+ @Bean
+ public RequestInterceptor requestInterceptor() {
+ return new TransactionRestTemplateInterceptor();
+ }
+}
diff --git a/pigx-common/pigx-common-transaction/src/main/java/com/pig4cloud/pigx/common/transaction/tx/TransactionConfiguration.java b/pigx-common/pigx-common-transaction/src/main/java/com/pig4cloud/pigx/common/transaction/tx/TransactionConfiguration.java
new file mode 100755
index 000000000..a10426935
--- /dev/null
+++ b/pigx-common/pigx-common-transaction/src/main/java/com/pig4cloud/pigx/common/transaction/tx/TransactionConfiguration.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.transaction.tx;
+
+import com.pig4cloud.pigx.common.transaction.ribbon.loadbalancer.LcnRibbonConfiguration;
+import org.springframework.cloud.netflix.ribbon.RibbonClients;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * Created by lorne on 2017/6/26.
+ *
+ * @author LCN
+ * @since 4.1.0
+ */
+
+@Configuration
+@ComponentScan
+@RibbonClients(defaultConfiguration = LcnRibbonConfiguration.class)
+public class TransactionConfiguration {
+
+
+}
diff --git a/pigx-common/pigx-common-transaction/src/main/java/com/pig4cloud/pigx/common/transaction/tx/springcloud/feign/TransactionRestTemplateInterceptor.java b/pigx-common/pigx-common-transaction/src/main/java/com/pig4cloud/pigx/common/transaction/tx/springcloud/feign/TransactionRestTemplateInterceptor.java
new file mode 100755
index 000000000..a44a416cd
--- /dev/null
+++ b/pigx-common/pigx-common-transaction/src/main/java/com/pig4cloud/pigx/common/transaction/tx/springcloud/feign/TransactionRestTemplateInterceptor.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.transaction.tx.springcloud.feign;
+
+import com.codingapi.tx.aop.bean.TxTransactionLocal;
+import feign.RequestInterceptor;
+import feign.RequestTemplate;
+import lombok.extern.slf4j.Slf4j;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Created by lorne on 2017/6/26.
+ *
+ * @author LCN
+ * @since 4.1.0
+ */
+@Slf4j
+public class TransactionRestTemplateInterceptor implements RequestInterceptor {
+
+ @Override
+ public void apply(RequestTemplate requestTemplate) {
+
+ TxTransactionLocal txTransactionLocal = TxTransactionLocal.current();
+ String groupId = txTransactionLocal == null ? null : txTransactionLocal.getGroupId();
+
+ log.info("LCN-SpringCloud TxGroup info -> groupId:" + groupId);
+
+ if (txTransactionLocal != null) {
+ requestTemplate.header("tx-group", groupId);
+ }
+ }
+
+}
diff --git a/pigx-common/pigx-common-transaction/src/main/java/com/pig4cloud/pigx/common/transaction/tx/springcloud/http/TransactionHttpRequestInterceptor.java b/pigx-common/pigx-common-transaction/src/main/java/com/pig4cloud/pigx/common/transaction/tx/springcloud/http/TransactionHttpRequestInterceptor.java
new file mode 100755
index 000000000..98b456698
--- /dev/null
+++ b/pigx-common/pigx-common-transaction/src/main/java/com/pig4cloud/pigx/common/transaction/tx/springcloud/http/TransactionHttpRequestInterceptor.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.transaction.tx.springcloud.http;
+
+import com.codingapi.tx.aop.bean.TxTransactionLocal;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpRequest;
+import org.springframework.http.client.ClientHttpRequestExecution;
+import org.springframework.http.client.ClientHttpRequestInterceptor;
+import org.springframework.http.client.ClientHttpResponse;
+
+import java.io.IOException;
+
+/**
+ * Created by lorne on 2017/7/3.
+ *
+ * @author LCN
+ * @since 4.1.0
+ */
+@Slf4j
+public class TransactionHttpRequestInterceptor implements ClientHttpRequestInterceptor {
+ @Override
+ public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
+
+ TxTransactionLocal txTransactionLocal = TxTransactionLocal.current();
+ String groupId = txTransactionLocal == null ? null : txTransactionLocal.getGroupId();
+
+ log.info("LCN-SpringCloud TxGroup info -> groupId:" + groupId);
+
+ if (txTransactionLocal != null) {
+ request.getHeaders().add("tx-group", groupId);
+ }
+ return execution.execute(request, body);
+ }
+}
diff --git a/pigx-common/pigx-common-transaction/src/main/java/com/pig4cloud/pigx/common/transaction/tx/springcloud/interceptor/TransactionAspect.java b/pigx-common/pigx-common-transaction/src/main/java/com/pig4cloud/pigx/common/transaction/tx/springcloud/interceptor/TransactionAspect.java
new file mode 100755
index 000000000..2566bffd5
--- /dev/null
+++ b/pigx-common/pigx-common-transaction/src/main/java/com/pig4cloud/pigx/common/transaction/tx/springcloud/interceptor/TransactionAspect.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.transaction.tx.springcloud.interceptor;
+
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.Ordered;
+import org.springframework.stereotype.Component;
+
+/**
+ * LCN 事务拦截器
+ * create by lorne on 2018/1/5
+ *
+ * @author LCN
+ * @since 4.1.0
+ */
+
+@Slf4j
+@Aspect
+@Component
+public class TransactionAspect implements Ordered {
+
+ @Autowired
+ private TxManagerInterceptor txManagerInterceptor;
+
+
+ @Around("@annotation(com.codingapi.tx.annotation.TxTransaction)")
+ public Object transactionRunning(ProceedingJoinPoint point) throws Throwable {
+ log.debug("annotation-TransactionRunning-start---->");
+ Object obj = txManagerInterceptor.around(point);
+ log.debug("annotation-TransactionRunning-end---->");
+ return obj;
+ }
+
+ @Around("this(com.codingapi.tx.annotation.ITxTransaction) && execution( * *(..))")
+ public Object around(ProceedingJoinPoint point) throws Throwable {
+ log.debug("interface-ITransactionRunning-start---->");
+ Object obj = txManagerInterceptor.around(point);
+ log.debug("interface-ITransactionRunning-end---->");
+ return obj;
+ }
+
+
+ @Override
+ public int getOrder() {
+ return HIGHEST_PRECEDENCE;
+ }
+
+
+}
diff --git a/pigx-common/pigx-common-transaction/src/main/java/com/pig4cloud/pigx/common/transaction/tx/springcloud/interceptor/TxManagerInterceptor.java b/pigx-common/pigx-common-transaction/src/main/java/com/pig4cloud/pigx/common/transaction/tx/springcloud/interceptor/TxManagerInterceptor.java
new file mode 100755
index 000000000..93b8b6d7e
--- /dev/null
+++ b/pigx-common/pigx-common-transaction/src/main/java/com/pig4cloud/pigx/common/transaction/tx/springcloud/interceptor/TxManagerInterceptor.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.transaction.tx.springcloud.interceptor;
+
+import com.codingapi.tx.aop.service.AspectBeforeService;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.request.RequestAttributes;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * Created by lorne on 2017/6/7.
+ *
+ * @author LCN
+ * @since 4.1.0
+ */
+
+@Component
+public class TxManagerInterceptor {
+
+ @Autowired
+ private AspectBeforeService aspectBeforeService;
+
+ public Object around(ProceedingJoinPoint point) throws Throwable {
+ String groupId = null;
+ try {
+ RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
+ HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
+ groupId = request.getHeader("tx-group");
+ } catch (Exception e) {
+ }
+ return aspectBeforeService.around(groupId, point);
+ }
+}
diff --git a/pigx-common/pigx-common-transaction/src/main/java/com/pig4cloud/pigx/common/transaction/tx/springcloud/listener/ServerListener.java b/pigx-common/pigx-common-transaction/src/main/java/com/pig4cloud/pigx/common/transaction/tx/springcloud/listener/ServerListener.java
new file mode 100755
index 000000000..7cd9694fa
--- /dev/null
+++ b/pigx-common/pigx-common-transaction/src/main/java/com/pig4cloud/pigx/common/transaction/tx/springcloud/listener/ServerListener.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.transaction.tx.springcloud.listener;
+
+import com.codingapi.tx.listener.service.InitService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.web.context.WebServerInitializedEvent;
+import org.springframework.context.ApplicationListener;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author LCN
+ * @since 4.1.0
+ */
+@Component
+public class ServerListener implements ApplicationListener {
+
+ private Logger logger = LoggerFactory.getLogger(ServerListener.class);
+
+ private int serverPort;
+
+ @Autowired
+ private InitService initService;
+
+ @Override
+ public void onApplicationEvent(WebServerInitializedEvent event) {
+ logger.info("onApplicationEvent -> onApplicationEvent. " + event.getWebServer());
+ this.serverPort = event.getWebServer().getPort();
+ initService.start();
+ }
+
+ public int getPort() {
+ return this.serverPort;
+ }
+}
diff --git a/pigx-common/pigx-common-transaction/src/main/java/com/pig4cloud/pigx/common/transaction/tx/springcloud/service/impl/ModelNameServiceImpl.java b/pigx-common/pigx-common-transaction/src/main/java/com/pig4cloud/pigx/common/transaction/tx/springcloud/service/impl/ModelNameServiceImpl.java
new file mode 100755
index 000000000..180f5fe0e
--- /dev/null
+++ b/pigx-common/pigx-common-transaction/src/main/java/com/pig4cloud/pigx/common/transaction/tx/springcloud/service/impl/ModelNameServiceImpl.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.transaction.tx.springcloud.service.impl;
+
+import com.codingapi.tx.listener.service.ModelNameService;
+import com.lorne.core.framework.utils.encode.MD5Util;
+import com.pig4cloud.pigx.common.transaction.tx.springcloud.listener.ServerListener;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.stereotype.Service;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * Created by lorne on 2017/7/12.
+ *
+ * @author LCN
+ * @since 4.1.0
+ */
+@Service
+@Configuration
+public class ModelNameServiceImpl implements ModelNameService {
+
+ @Value("${spring.application.name}")
+ private String modelName;
+
+ @Autowired
+ private ServerListener serverListener;
+
+
+ private String host = null;
+
+ @Override
+ public String getModelName() {
+ return modelName;
+ }
+
+ private String getIp() {
+ if (host == null) {
+ try {
+ host = InetAddress.getLocalHost().getHostAddress();
+ } catch (UnknownHostException e) {
+ e.printStackTrace();
+ }
+ }
+ return host;
+ }
+
+ private int getPort() {
+ int port = serverListener.getPort();
+ int count = 0;
+ while (port == 0) {
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ port = serverListener.getPort();
+ count++;
+
+ if (count == 2000) {
+ throw new RuntimeException("get server port error.");
+ }
+ }
+
+ return port;
+ }
+
+ @Override
+ public String getUniqueKey() {
+ String address = getIp() + getPort();
+ return MD5Util.md5(address.getBytes());
+ }
+
+
+ @Override
+ public String getIpAddress() {
+ String address = getIp() + ":" + getPort();
+ return address;
+ }
+}
diff --git a/pigx-common/pigx-common-transaction/src/main/resources/META-INF/spring.factories b/pigx-common/pigx-common-transaction/src/main/resources/META-INF/spring.factories
new file mode 100644
index 000000000..9704185b3
--- /dev/null
+++ b/pigx-common/pigx-common-transaction/src/main/resources/META-INF/spring.factories
@@ -0,0 +1 @@
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.pig4cloud.pigx.common.transaction.tx.TransactionConfiguration
diff --git a/pigx-common/pom.xml b/pigx-common/pom.xml
index 5b70d52ef..d9c6e1762 100644
--- a/pigx-common/pom.xml
+++ b/pigx-common/pom.xml
@@ -39,5 +39,6 @@
pigx-common-logpigx-common-securitypigx-common-swagger
+ pigx-common-transaction
diff --git a/pigx-config/src/main/resources/banner.txt b/pigx-config/src/main/resources/banner.txt
new file mode 100644
index 000000000..63be6e1eb
--- /dev/null
+++ b/pigx-config/src/main/resources/banner.txt
@@ -0,0 +1,16 @@
+${AnsiColor.BRIGHT_YELLOW}
+
+ ::::::::: ::::::::::: :::::::: ::: :::
+ :+: :+: :+: :+: :+: :+: :+:
+ +:+ +:+ +:+ +:+ +:+ +:+
+ +#++:++#+ +#+ :#: +#++:+
+ +#+ +#+ +#+ +#+# +#+ +#+
+ #+# #+# #+# #+# #+# #+#
+ ### ########### ######## ### ###
+
+ www.pig4cloud.com
+
+ Pig Microservice Architecture
+
+
+
diff --git a/pigx-config/src/main/resources/config/pigx-tx-manager-dev.yml b/pigx-config/src/main/resources/config/pigx-tx-manager-dev.yml
new file mode 100644
index 000000000..5b9515450
--- /dev/null
+++ b/pigx-config/src/main/resources/config/pigx-tx-manager-dev.yml
@@ -0,0 +1,24 @@
+# 页面配置
+spring:
+ mvc:
+ static-path-pattern: /**
+ resources:
+ static-locations: classpath:/static/
+
+
+# LCN 配置
+tm:
+ transaction:
+ netty:
+ delaytime: 5 # 客户端链接最大通讯时间 (秒)
+ hearttime: 15 # 客户端心跳时间 (秒)
+ redis:
+ savemaxtime: 30 # redis 保存时间 (秒)
+ socket:
+ port: 9998 # 通讯端口
+ maxconnection: 1000 #最大链接数
+ compensate:
+ auto: false #是否自动补偿
+ notifyUrl: http://ip:port/path #补偿结果通知(配消息总线里面)
+ tryTime: 30 # z再次重试时间间隔
+ maxWaitTime: 5000 # 请求超时的最大时间 (毫秒)
diff --git a/pigx-eureka/src/main/resources/banner.txt b/pigx-eureka/src/main/resources/banner.txt
new file mode 100644
index 000000000..63be6e1eb
--- /dev/null
+++ b/pigx-eureka/src/main/resources/banner.txt
@@ -0,0 +1,16 @@
+${AnsiColor.BRIGHT_YELLOW}
+
+ ::::::::: ::::::::::: :::::::: ::: :::
+ :+: :+: :+: :+: :+: :+: :+:
+ +:+ +:+ +:+ +:+ +:+ +:+
+ +#++:++#+ +#+ :#: +#++:+
+ +#+ +#+ +#+ +#+# +#+ +#+
+ #+# #+# #+# #+# #+# #+#
+ ### ########### ######## ### ###
+
+ www.pig4cloud.com
+
+ Pig Microservice Architecture
+
+
+
diff --git a/pigx-visual/pigx-tx-manager/pom.xml b/pigx-visual/pigx-tx-manager/pom.xml
new file mode 100644
index 000000000..807c6194c
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/pom.xml
@@ -0,0 +1,83 @@
+
+
+ 4.0.0
+
+ com.pig4cloud
+ pigx-visual
+ ${pigx.version}
+
+
+ pigx-tx-manager
+ ${pigx.version}
+ jar
+
+ pigx-tx-manager
+ pigx lcn tx manager
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ spring-boot-starter-tomcat
+ org.springframework.boot
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-undertow
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-config
+
+
+
+ com.github.1991wangliang
+ lorne_core
+ 1.0.0
+
+
+ org.slf4j
+ *
+
+
+
+
+
+ io.netty
+ netty-all
+ 4.1.12.Final
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-netflix-eureka-client
+
+
+
+ com.pig4cloud
+ pigx-common-core
+ ${pigx.version}
+
+
+ javax.servlet
+ javax.servlet-api
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/PigxTxManagerApplication.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/PigxTxManagerApplication.java
new file mode 100644
index 000000000..03001ec54
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/PigxTxManagerApplication.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
+
+
+@SpringBootApplication
+@EnableDiscoveryClient
+public class PigxTxManagerApplication {
+
+
+ public static void main(String[] args) {
+ SpringApplication.run(PigxTxManagerApplication.class, args);
+ }
+
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/api/controller/AdminController.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/api/controller/AdminController.java
new file mode 100644
index 000000000..51355d5c1
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/api/controller/AdminController.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.api.controller;
+
+import com.lorne.core.framework.exception.ServiceException;
+import com.pig4cloud.pigx.manager.api.service.ApiAdminService;
+import com.pig4cloud.pigx.manager.api.service.ApiModelService;
+import com.pig4cloud.pigx.manager.compensate.model.TxModel;
+import com.pig4cloud.pigx.manager.model.ModelInfo;
+import com.pig4cloud.pigx.manager.model.ModelName;
+import com.pig4cloud.pigx.manager.model.TxState;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * Created by lorne on 2017/7/1.
+ */
+@RestController
+@RequestMapping("/admin")
+public class AdminController {
+
+ @Autowired
+ private ApiAdminService apiAdminService;
+
+ @Autowired
+ private ApiModelService apiModelService;
+
+
+ @RequestMapping(value = "/onlines", method = RequestMethod.GET)
+ public List onlines() {
+ return apiModelService.onlines();
+ }
+
+
+ @RequestMapping(value = "/setting", method = RequestMethod.GET)
+ public TxState setting() {
+ return apiAdminService.getState();
+ }
+
+ @RequestMapping(value = "/json", method = RequestMethod.GET)
+ public String json() {
+ return apiAdminService.loadNotifyJson();
+ }
+
+ @RequestMapping(value = "/modelList", method = RequestMethod.GET)
+ public List modelList() {
+ return apiAdminService.modelList();
+ }
+
+ @RequestMapping(value = "/modelTimes", method = RequestMethod.GET)
+ public List modelTimes(@RequestParam("model") String model) {
+ return apiAdminService.modelTimes(model);
+ }
+
+
+ @RequestMapping(value = "/modelInfos", method = RequestMethod.GET)
+ public List modelInfos(@RequestParam("path") String path) {
+ return apiAdminService.modelInfos(path);
+ }
+
+ @RequestMapping(value = "/compensate", method = RequestMethod.GET)
+ public boolean compensate(@RequestParam("path") String path) throws ServiceException {
+ return apiAdminService.compensate(path);
+ }
+
+ @RequestMapping(value = "/delCompensate", method = RequestMethod.GET)
+ public boolean delCompensate(@RequestParam("path") String path) throws ServiceException {
+ return apiAdminService.delCompensate(path);
+ }
+
+ @RequestMapping(value = "/hasCompensate", method = RequestMethod.GET)
+ public boolean hasCompensate() throws ServiceException {
+ return apiAdminService.hasCompensate();
+ }
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/api/controller/TxManagerController.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/api/controller/TxManagerController.java
new file mode 100644
index 000000000..053872613
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/api/controller/TxManagerController.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.api.controller;
+
+import com.pig4cloud.pigx.manager.api.service.ApiTxManagerService;
+import com.pig4cloud.pigx.manager.model.TxServer;
+import com.pig4cloud.pigx.manager.model.TxState;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * Created by lorne on 2017/7/1.
+ */
+@RestController
+@RequestMapping("/tx/manager")
+public class TxManagerController {
+
+ @Autowired
+ private ApiTxManagerService apiTxManagerService;
+
+
+ @RequestMapping("/getServer")
+ public TxServer getServer() {
+ return apiTxManagerService.getServer();
+ }
+
+
+ @RequestMapping("/cleanNotifyTransaction")
+ public int cleanNotifyTransaction(@RequestParam("groupId") String groupId, @RequestParam("taskId") String taskId) {
+ return apiTxManagerService.cleanNotifyTransaction(groupId, taskId);
+ }
+
+
+ @RequestMapping("/sendMsg")
+ public String sendMsg(@RequestParam("msg") String msg, @RequestParam("model") String model) {
+ return apiTxManagerService.sendMsg(model, msg);
+ }
+
+
+ @RequestMapping("/sendCompensateMsg")
+ public boolean sendCompensateMsg(@RequestParam("model") String model, @RequestParam("uniqueKey") String uniqueKey,
+ @RequestParam("currentTime") long currentTime,
+ @RequestParam("groupId") String groupId, @RequestParam("className") String className,
+ @RequestParam("time") int time, @RequestParam("data") String data,
+ @RequestParam("methodStr") String methodStr, @RequestParam("address") String address,
+ @RequestParam("startError") int startError) {
+ return apiTxManagerService.sendCompensateMsg(currentTime, groupId, model, address, uniqueKey, className, methodStr, data, time, startError);
+ }
+
+
+ @RequestMapping("/state")
+ public TxState state() {
+ return apiTxManagerService.getState();
+ }
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/api/service/ApiAdminService.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/api/service/ApiAdminService.java
new file mode 100644
index 000000000..367bf7346
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/api/service/ApiAdminService.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.api.service;
+
+import com.lorne.core.framework.exception.ServiceException;
+import com.pig4cloud.pigx.manager.compensate.model.TxModel;
+import com.pig4cloud.pigx.manager.model.ModelName;
+import com.pig4cloud.pigx.manager.model.TxState;
+
+import java.util.List;
+
+/**
+ * create by lorne on 2017/11/12
+ */
+public interface ApiAdminService {
+
+ TxState getState();
+
+ String loadNotifyJson();
+
+ List modelList();
+
+
+ List modelTimes(String model);
+
+ List modelInfos(String path);
+
+ boolean compensate(String path) throws ServiceException;
+
+ boolean hasCompensate();
+
+ boolean delCompensate(String path);
+
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/api/service/ApiModelService.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/api/service/ApiModelService.java
new file mode 100644
index 000000000..1a226a835
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/api/service/ApiModelService.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.api.service;
+
+import com.pig4cloud.pigx.manager.model.ModelInfo;
+
+import java.util.List;
+
+/**
+ * create by lorne on 2017/11/13
+ */
+public interface ApiModelService {
+
+ List onlines();
+
+
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/api/service/ApiTxManagerService.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/api/service/ApiTxManagerService.java
new file mode 100644
index 000000000..54fc8642e
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/api/service/ApiTxManagerService.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.api.service;
+
+import com.pig4cloud.pigx.manager.model.TxServer;
+import com.pig4cloud.pigx.manager.model.TxState;
+
+/**
+ * Created by lorne on 2017/7/1.
+ */
+public interface ApiTxManagerService {
+
+
+ /**
+ * 获取本服务的信息
+ *
+ * @return 服务信息
+ */
+ TxServer getServer();
+
+
+ /**
+ * 给 tx模块发送指令
+ *
+ * @param model 模块名称
+ * @param msg 指令
+ * @return 指令返回结果
+ */
+ String sendMsg(String model, String msg);
+
+ /**
+ * 检查并清理事务数据
+ *
+ * @param groupId 事务组Id
+ * @param taskId 任务Id
+ * @param isGroup 是否合并事务
+ * @return 事务状态
+ */
+ int cleanNotifyTransaction(String groupId, String taskId);
+
+
+ /**
+ * 保存事务补偿日志信息
+ *
+ * @param currentTime 时间
+ * @param groupId 事务组id
+ * @param model 模块名称
+ * @param address 模块地址
+ * @param uniqueKey 唯一标示
+ * @param className 事务启动类
+ * @param methodStr 事务启动方法
+ * @param data 切面数据
+ * @param time 执行时间
+ * @param startError 启动模块异常
+ * @return 是否保存成功
+ */
+ boolean sendCompensateMsg(long currentTime, String groupId, String model, String address, String uniqueKey, String className, String methodStr, String data, int time, int startError);
+
+ /**
+ * 获取服务器状态
+ *
+ * @return 状态
+ */
+ TxState getState();
+
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/api/service/impl/ApiAdminServiceImpl.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/api/service/impl/ApiAdminServiceImpl.java
new file mode 100644
index 000000000..aeb0fbcc9
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/api/service/impl/ApiAdminServiceImpl.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.api.service.impl;
+
+
+import com.lorne.core.framework.exception.ServiceException;
+import com.pig4cloud.pigx.manager.api.service.ApiAdminService;
+import com.pig4cloud.pigx.manager.compensate.model.TxModel;
+import com.pig4cloud.pigx.manager.compensate.service.CompensateService;
+import com.pig4cloud.pigx.manager.manager.service.MicroService;
+import com.pig4cloud.pigx.manager.model.ModelName;
+import com.pig4cloud.pigx.manager.model.TxState;
+import com.pig4cloud.pigx.manager.redis.RedisServerService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * create by lorne on 2017/11/12
+ */
+@Service
+public class ApiAdminServiceImpl implements ApiAdminService {
+
+
+ @Autowired
+ private MicroService eurekaService;
+
+ @Autowired
+ private RedisServerService redisServerService;
+
+ @Autowired
+ private CompensateService compensateService;
+
+ @Override
+ public TxState getState() {
+ return eurekaService.getState();
+ }
+
+ @Override
+ public String loadNotifyJson() {
+ return redisServerService.loadNotifyJson();
+ }
+
+ @Override
+ public List modelList() {
+ return compensateService.loadModelList();
+ }
+
+
+ @Override
+ public List modelTimes(String model) {
+ return compensateService.loadCompensateTimes(model);
+ }
+
+ @Override
+ public List modelInfos(String path) {
+ return compensateService.loadCompensateByModelAndTime(path);
+ }
+
+ @Override
+ public boolean compensate(String path) throws ServiceException {
+ return compensateService.executeCompensate(path);
+ }
+
+ @Override
+ public boolean delCompensate(String path) {
+ return compensateService.delCompensate(path);
+ }
+
+ @Override
+ public boolean hasCompensate() {
+ return compensateService.hasCompensate();
+ }
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/api/service/impl/ApiModelServiceImpl.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/api/service/impl/ApiModelServiceImpl.java
new file mode 100644
index 000000000..631900dc3
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/api/service/impl/ApiModelServiceImpl.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.api.service.impl;
+
+import com.pig4cloud.pigx.manager.api.service.ApiModelService;
+import com.pig4cloud.pigx.manager.manager.ModelInfoManager;
+import com.pig4cloud.pigx.manager.model.ModelInfo;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * create by lorne on 2017/11/13
+ */
+@Service
+public class ApiModelServiceImpl implements ApiModelService {
+
+
+ @Override
+ public List onlines() {
+ return ModelInfoManager.getInstance().getOnlines();
+ }
+
+
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/api/service/impl/ApiTxManagerServiceImpl.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/api/service/impl/ApiTxManagerServiceImpl.java
new file mode 100644
index 000000000..e908f25c4
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/api/service/impl/ApiTxManagerServiceImpl.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.api.service.impl;
+
+
+import com.pig4cloud.pigx.manager.api.service.ApiTxManagerService;
+import com.pig4cloud.pigx.manager.compensate.model.TransactionCompensateMsg;
+import com.pig4cloud.pigx.manager.compensate.service.CompensateService;
+import com.pig4cloud.pigx.manager.config.ConfigReader;
+import com.pig4cloud.pigx.manager.manager.service.MicroService;
+import com.pig4cloud.pigx.manager.manager.service.TxManagerSenderService;
+import com.pig4cloud.pigx.manager.manager.service.TxManagerService;
+import com.pig4cloud.pigx.manager.model.TxServer;
+import com.pig4cloud.pigx.manager.model.TxState;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * Created by lorne on 2017/7/1.
+ */
+@Service
+public class ApiTxManagerServiceImpl implements ApiTxManagerService {
+
+
+ @Autowired
+ private TxManagerService managerService;
+
+ @Autowired
+ private MicroService eurekaService;
+
+ @Autowired
+ private CompensateService compensateService;
+
+
+ @Autowired
+ private TxManagerSenderService txManagerSenderService;
+
+ @Autowired
+ private ConfigReader configReader;
+
+
+ @Override
+ public TxServer getServer() {
+ return eurekaService.getServer();
+ }
+
+
+ @Override
+ public int cleanNotifyTransaction(String groupId, String taskId) {
+ return managerService.cleanNotifyTransaction(groupId, taskId);
+ }
+
+
+ @Override
+ public boolean sendCompensateMsg(long currentTime, String groupId, String model, String address, String uniqueKey, String className, String methodStr, String data, int time, int startError) {
+ TransactionCompensateMsg transactionCompensateMsg = new TransactionCompensateMsg(currentTime, groupId, model, address, uniqueKey, className, methodStr, data, time, 0, startError);
+ return compensateService.saveCompensateMsg(transactionCompensateMsg);
+ }
+
+ @Override
+ public String sendMsg(String model, String msg) {
+ return txManagerSenderService.sendMsg(model, msg, configReader.getTransactionNettyDelayTime());
+ }
+
+
+ @Override
+ public TxState getState() {
+ return eurekaService.getState();
+ }
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/compensate/dao/CompensateDao.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/compensate/dao/CompensateDao.java
new file mode 100644
index 000000000..d0a84f019
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/compensate/dao/CompensateDao.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.compensate.dao;
+
+import com.pig4cloud.pigx.manager.compensate.model.TransactionCompensateMsg;
+
+import java.util.List;
+
+/**
+ * create by lorne on 2017/11/11
+ */
+public interface CompensateDao {
+
+ String saveCompensateMsg(TransactionCompensateMsg transactionCompensateMsg);
+
+ List loadCompensateKeys();
+
+ List loadCompensateTimes(String model);
+
+ List loadCompensateByModelAndTime(String path);
+
+ String getCompensate(String key);
+
+ String getCompensateByGroupId(String groupId);
+
+ void deleteCompensateByPath(String path);
+
+ void deleteCompensateByKey(String key);
+
+ boolean hasCompensate();
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/compensate/dao/impl/CompensateDaoImpl.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/compensate/dao/impl/CompensateDaoImpl.java
new file mode 100644
index 000000000..eb926f16c
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/compensate/dao/impl/CompensateDaoImpl.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.compensate.dao.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.lorne.core.framework.utils.DateUtil;
+import com.pig4cloud.pigx.manager.compensate.dao.CompensateDao;
+import com.pig4cloud.pigx.manager.compensate.model.TransactionCompensateMsg;
+import com.pig4cloud.pigx.manager.config.ConfigReader;
+import com.pig4cloud.pigx.manager.redis.RedisServerService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * create by lorne on 2017/11/11
+ */
+@Service
+public class CompensateDaoImpl implements CompensateDao {
+
+
+ @Autowired
+ private RedisServerService redisServerService;
+
+ @Autowired
+ private ConfigReader configReader;
+
+
+ @Override
+ public String saveCompensateMsg(TransactionCompensateMsg transactionCompensateMsg) {
+
+ String name = String.format("%s%s:%s:%s.json", configReader.getKeyPrefixCompensate(), transactionCompensateMsg.getModel(), DateUtil.getCurrentDateFormat(), transactionCompensateMsg.getGroupId());
+
+ String json = JSON.toJSONString(transactionCompensateMsg);
+
+ redisServerService.saveCompensateMsg(name, json);
+
+ return name;
+ }
+
+
+ @Override
+ public List loadCompensateKeys() {
+ String key = configReader.getKeyPrefixCompensate() + "*";
+ return redisServerService.getKeys(key);
+ }
+
+
+ @Override
+ public boolean hasCompensate() {
+ String key = configReader.getKeyPrefixCompensate() + "*";
+ List keys = redisServerService.getKeys(key);
+ return keys != null && keys.size() > 0;
+ }
+
+ @Override
+ public List loadCompensateTimes(String model) {
+ String key = configReader.getKeyPrefixCompensate() + model + ":*";
+ List keys = redisServerService.getKeys(key);
+ List times = new ArrayList();
+ for (String k : keys) {
+ if (k.length() > 36) {
+ String time = k.substring(k.length() - 24, k.length() - 14);
+ if (!times.contains(time)) {
+ times.add(time);
+ }
+ }
+ }
+ return times;
+ }
+
+
+ @Override
+ public List loadCompensateByModelAndTime(String path) {
+ String key = String.format("%s%s*", configReader.getKeyPrefixCompensate(), path);
+ List keys = redisServerService.getKeys(key);
+ List values = redisServerService.getValuesByKeys(keys);
+ return values;
+ }
+
+ @Override
+ public String getCompensate(String path) {
+ String key = String.format("%s%s.json", configReader.getKeyPrefixCompensate(), path);
+ return redisServerService.getValueByKey(key);
+ }
+
+
+ @Override
+ public void deleteCompensateByPath(String path) {
+ String key = String.format("%s%s.json", configReader.getKeyPrefixCompensate(), path);
+ redisServerService.deleteKey(key);
+ }
+
+
+ @Override
+ public void deleteCompensateByKey(String key) {
+ redisServerService.deleteKey(key);
+ }
+
+ @Override
+ public String getCompensateByGroupId(String groupId) {
+ String key = String.format("%s*%s.json", configReader.getKeyPrefixCompensate(), groupId);
+ List keys = redisServerService.getKeys(key);
+ if (keys != null && keys.size() == 1) {
+ String k = keys.get(0);
+ return redisServerService.getValueByKey(k);
+ }
+ return null;
+ }
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/compensate/model/TransactionCompensateMsg.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/compensate/model/TransactionCompensateMsg.java
new file mode 100644
index 000000000..2c6865e04
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/compensate/model/TransactionCompensateMsg.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.compensate.model;
+
+import com.pig4cloud.pigx.manager.netty.model.TxGroup;
+
+/**
+ * create by lorne on 2017/11/11
+ */
+public class TransactionCompensateMsg {
+
+ private long currentTime;
+ private String groupId;
+ private String model;
+ private String address;
+ private String uniqueKey;
+ private String className;
+ private String methodStr;
+ private String data;
+ private int time;
+ private int startError;
+
+ private TxGroup txGroup;
+
+ private int state;
+
+
+ public TransactionCompensateMsg(long currentTime, String groupId, String model, String address,
+ String uniqueKey, String className,
+ String methodStr, String data, int time, int state, int startError) {
+ this.currentTime = currentTime;
+ this.groupId = groupId;
+ this.model = model;
+ this.uniqueKey = uniqueKey;
+ this.className = className;
+ this.methodStr = methodStr;
+ this.data = data;
+ this.time = time;
+ this.address = address;
+ this.state = state;
+ this.startError = startError;
+ }
+
+ public int getStartError() {
+ return startError;
+ }
+
+ public void setStartError(int startError) {
+ this.startError = startError;
+ }
+
+ public int getState() {
+ return state;
+ }
+
+ public void setState(int state) {
+ this.state = state;
+ }
+
+ public long getCurrentTime() {
+ return currentTime;
+ }
+
+ public void setCurrentTime(long currentTime) {
+ this.currentTime = currentTime;
+ }
+
+ public String getAddress() {
+ return address;
+ }
+
+ public void setAddress(String address) {
+ this.address = address;
+ }
+
+ public TxGroup getTxGroup() {
+ return txGroup;
+ }
+
+ public void setTxGroup(TxGroup txGroup) {
+ this.txGroup = txGroup;
+ }
+
+ public String getGroupId() {
+ return groupId;
+ }
+
+ public void setGroupId(String groupId) {
+ this.groupId = groupId;
+ }
+
+ public String getModel() {
+ return model;
+ }
+
+ public void setModel(String model) {
+ this.model = model;
+ }
+
+ public String getUniqueKey() {
+ return uniqueKey;
+ }
+
+ public void setUniqueKey(String uniqueKey) {
+ this.uniqueKey = uniqueKey;
+ }
+
+ public String getClassName() {
+ return className;
+ }
+
+ public void setClassName(String className) {
+ this.className = className;
+ }
+
+
+ public String getMethodStr() {
+ return methodStr;
+ }
+
+ public void setMethodStr(String methodStr) {
+ this.methodStr = methodStr;
+ }
+
+ public String getData() {
+ return data;
+ }
+
+ public void setData(String data) {
+ this.data = data;
+ }
+
+ public int getTime() {
+ return time;
+ }
+
+ public void setTime(int time) {
+ this.time = time;
+ }
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/compensate/model/TxModel.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/compensate/model/TxModel.java
new file mode 100644
index 000000000..aa0b26455
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/compensate/model/TxModel.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.compensate.model;
+
+/**
+ * create by lorne on 2017/11/12
+ */
+public class TxModel {
+
+ private String time;
+
+ private String className;
+
+ private String method;
+
+ private int executeTime;
+
+ private String base64;
+
+ private int state;
+
+ private long order;
+
+ private String key;
+
+ public String getKey() {
+ return key;
+ }
+
+ public void setKey(String key) {
+ this.key = key;
+ }
+
+ public long getOrder() {
+ return order;
+ }
+
+ public void setOrder(long order) {
+ this.order = order;
+ }
+
+ public String getBase64() {
+ return base64;
+ }
+
+ public void setBase64(String base64) {
+ this.base64 = base64;
+ }
+
+ public String getClassName() {
+ return className;
+ }
+
+ public void setClassName(String className) {
+ this.className = className;
+ }
+
+ public String getMethod() {
+ return method;
+ }
+
+ public void setMethod(String method) {
+ this.method = method;
+ }
+
+ public int getExecuteTime() {
+ return executeTime;
+ }
+
+ public void setExecuteTime(int executeTime) {
+ this.executeTime = executeTime;
+ }
+
+ public String getTime() {
+ return time;
+ }
+
+ public void setTime(String time) {
+ this.time = time;
+ }
+
+ public int getState() {
+ return state;
+ }
+
+ public void setState(int state) {
+ this.state = state;
+ }
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/compensate/service/CompensateService.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/compensate/service/CompensateService.java
new file mode 100644
index 000000000..4275c325b
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/compensate/service/CompensateService.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.compensate.service;
+
+import com.lorne.core.framework.exception.ServiceException;
+import com.pig4cloud.pigx.manager.compensate.model.TransactionCompensateMsg;
+import com.pig4cloud.pigx.manager.compensate.model.TxModel;
+import com.pig4cloud.pigx.manager.model.ModelName;
+import com.pig4cloud.pigx.manager.netty.model.TxGroup;
+
+import java.util.List;
+
+/**
+ * create by lorne on 2017/11/11
+ */
+public interface CompensateService {
+
+ boolean saveCompensateMsg(TransactionCompensateMsg transactionCompensateMsg);
+
+ List loadModelList();
+
+ List loadCompensateTimes(String model);
+
+ List loadCompensateByModelAndTime(String path);
+
+ void autoCompensate(String compensateKey, TransactionCompensateMsg transactionCompensateMsg);
+
+ boolean executeCompensate(String key) throws ServiceException;
+
+ void reloadCompensate(TxGroup txGroup);
+
+ boolean hasCompensate();
+
+ boolean delCompensate(String path);
+
+ TxGroup getCompensateByGroupId(String groupId);
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/compensate/service/impl/CompensateServiceImpl.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/compensate/service/impl/CompensateServiceImpl.java
new file mode 100644
index 000000000..b2f4f0cdf
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/compensate/service/impl/CompensateServiceImpl.java
@@ -0,0 +1,351 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.compensate.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.google.common.collect.Lists;
+import com.lorne.core.framework.exception.ServiceException;
+import com.lorne.core.framework.utils.DateUtil;
+import com.lorne.core.framework.utils.encode.Base64Utils;
+import com.lorne.core.framework.utils.http.HttpUtils;
+import com.pig4cloud.pigx.manager.compensate.dao.CompensateDao;
+import com.pig4cloud.pigx.manager.compensate.model.TransactionCompensateMsg;
+import com.pig4cloud.pigx.manager.compensate.model.TxModel;
+import com.pig4cloud.pigx.manager.compensate.service.CompensateService;
+import com.pig4cloud.pigx.manager.config.ConfigReader;
+import com.pig4cloud.pigx.manager.manager.ModelInfoManager;
+import com.pig4cloud.pigx.manager.manager.service.TxManagerSenderService;
+import com.pig4cloud.pigx.manager.manager.service.TxManagerService;
+import com.pig4cloud.pigx.manager.model.ModelInfo;
+import com.pig4cloud.pigx.manager.model.ModelName;
+import com.pig4cloud.pigx.manager.netty.model.TxGroup;
+import com.pig4cloud.pigx.manager.netty.model.TxInfo;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+
+/**
+ * create by lorne on 2017/11/11
+ */
+@Service
+public class CompensateServiceImpl implements CompensateService {
+
+
+ private Logger logger = LoggerFactory.getLogger(CompensateServiceImpl.class);
+
+ @Autowired
+ private CompensateDao compensateDao;
+
+ @Autowired
+ private ConfigReader configReader;
+
+ @Autowired
+ private TxManagerSenderService managerSenderService;
+
+ @Autowired
+ private TxManagerService managerService;
+
+
+ private Executor threadPool = Executors.newFixedThreadPool(20);
+
+ @Override
+ public boolean saveCompensateMsg(final TransactionCompensateMsg transactionCompensateMsg) {
+
+ TxGroup txGroup = managerService.getTxGroup(transactionCompensateMsg.getGroupId());
+ if (txGroup == null) {
+ //仅发起方异常,其他模块正常
+ txGroup = new TxGroup();
+ txGroup.setNowTime(System.currentTimeMillis());
+ txGroup.setGroupId(transactionCompensateMsg.getGroupId());
+ txGroup.setIsCompensate(1);
+ } else {
+ managerService.deleteTxGroup(txGroup);
+ }
+
+ transactionCompensateMsg.setTxGroup(txGroup);
+
+ final String json = JSON.toJSONString(transactionCompensateMsg);
+
+ logger.info("Compensate->" + json);
+
+ final String compensateKey = compensateDao.saveCompensateMsg(transactionCompensateMsg);
+
+ //调整自动补偿机制,若开启了自动补偿,需要通知业务返回success,方可执行自动补偿
+ threadPool.execute(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ String groupId = transactionCompensateMsg.getGroupId();
+ JSONObject requestJson = new JSONObject();
+ requestJson.put("action", "compensate");
+ requestJson.put("groupId", groupId);
+ requestJson.put("json", json);
+
+ String url = configReader.getCompensateNotifyUrl();
+ logger.error("Compensate Callback Address->" + url);
+ String res = HttpUtils.postJson(url, requestJson.toJSONString());
+ logger.error("Compensate Callback Result->" + res);
+ if (configReader.isCompensateAuto()) {
+ //自动补偿,是否自动执行补偿
+ if (res.contains("success") || res.contains("SUCCESS")) {
+ //自动补偿
+ autoCompensate(compensateKey, transactionCompensateMsg);
+ }
+ }
+ } catch (Exception e) {
+ logger.error("Compensate Callback Fails->" + e.getMessage());
+ }
+ }
+ });
+
+ return StringUtils.isNotEmpty(compensateKey);
+
+
+ }
+
+ @Override
+ public void autoCompensate(final String compensateKey, TransactionCompensateMsg transactionCompensateMsg) {
+ final String json = JSON.toJSONString(transactionCompensateMsg);
+ logger.info("Auto Compensate->" + json);
+ //自动补偿业务执行...
+ final int tryTime = configReader.getCompensateTryTime();
+ boolean autoExecuteRes = false;
+ try {
+ int executeCount = 0;
+ autoExecuteRes = _executeCompensate(json);
+ logger.info("Automatic Compensate Result->" + autoExecuteRes + ",json->" + json);
+ while (!autoExecuteRes) {
+ logger.info("Compensate Failure, Entering Compensate Queue->" + autoExecuteRes + ",json->" + json);
+ executeCount++;
+ if (executeCount == 3) {
+ autoExecuteRes = false;
+ break;
+ }
+ try {
+ Thread.sleep(tryTime * 1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ autoExecuteRes = _executeCompensate(json);
+ }
+
+ //执行成功删除数据
+ if (autoExecuteRes) {
+ compensateDao.deleteCompensateByKey(compensateKey);
+ }
+
+ } catch (Exception e) {
+ logger.error("Auto Compensate Fails,msg:" + e.getLocalizedMessage());
+ //推送数据给第三方通知
+ autoExecuteRes = false;
+ }
+
+ //执行补偿以后通知给业务方
+ String groupId = transactionCompensateMsg.getGroupId();
+ JSONObject requestJson = new JSONObject();
+ requestJson.put("action", "notify");
+ requestJson.put("groupId", groupId);
+ requestJson.put("resState", autoExecuteRes);
+
+ String url = configReader.getCompensateNotifyUrl();
+ logger.error("Compensate Result Callback Address->" + url);
+ String res = HttpUtils.postJson(url, requestJson.toJSONString());
+ logger.error("Compensate Result Callback Result->" + res);
+
+ }
+
+
+ @Override
+ public List loadModelList() {
+ List keys = compensateDao.loadCompensateKeys();
+
+ Map models = new HashMap();
+
+ for (String key : keys) {
+ if (key.length() > 36) {
+ String name = key.substring(11, key.length() - 25);
+ int v = 1;
+ if (models.containsKey(name)) {
+ v = models.get(name) + 1;
+ }
+ models.put(name, v);
+ }
+ }
+ List names = new ArrayList<>();
+
+ for (String key : models.keySet()) {
+ int v = models.get(key);
+ ModelName modelName = new ModelName();
+ modelName.setName(key);
+ modelName.setCount(v);
+ names.add(modelName);
+ }
+ return names;
+ }
+
+ @Override
+ public List loadCompensateTimes(String model) {
+ return compensateDao.loadCompensateTimes(model);
+ }
+
+ @Override
+ public List loadCompensateByModelAndTime(String path) {
+ List logs = compensateDao.loadCompensateByModelAndTime(path);
+
+ List models = new ArrayList<>();
+ for (String json : logs) {
+ JSONObject jsonObject = JSON.parseObject(json);
+ TxModel model = new TxModel();
+ long currentTime = jsonObject.getLong("currentTime");
+ model.setTime(DateUtil.formatDate(new Date(currentTime), DateUtil.FULL_DATE_TIME_FORMAT));
+ model.setClassName(jsonObject.getString("className"));
+ model.setMethod(jsonObject.getString("methodStr"));
+ model.setExecuteTime(jsonObject.getInteger("time"));
+ model.setBase64(Base64Utils.encode(json.getBytes()));
+ model.setState(jsonObject.getInteger("state"));
+ model.setOrder(currentTime);
+
+ String groupId = jsonObject.getString("groupId");
+
+ String key = path + ":" + groupId;
+ model.setKey(key);
+
+ models.add(model);
+ }
+ Collections.sort(models, new Comparator() {
+ @Override
+ public int compare(TxModel o1, TxModel o2) {
+ if (o2.getOrder() > o1.getOrder()) {
+ return 1;
+ } else {
+ return -1;
+ }
+ }
+ });
+ return models;
+ }
+
+ @Override
+ public boolean hasCompensate() {
+ return compensateDao.hasCompensate();
+ }
+
+ @Override
+ public boolean delCompensate(String path) {
+ compensateDao.deleteCompensateByPath(path);
+ return true;
+ }
+
+ @Override
+ public void reloadCompensate(TxGroup txGroup) {
+ TxGroup compensateGroup = getCompensateByGroupId(txGroup.getGroupId());
+ if (compensateGroup != null) {
+
+ if (compensateGroup.getList() != null && !compensateGroup.getList().isEmpty()) {
+ //引用集合 iterator,方便匹配后剔除列表
+ Iterator iterator = Lists.newArrayList(compensateGroup.getList()).iterator();
+ for (TxInfo txInfo : txGroup.getList()) {
+ while (iterator.hasNext()) {
+ TxInfo cinfo = iterator.next();
+ if (cinfo.getModel().equals(txInfo.getModel()) && cinfo.getMethodStr().equals(txInfo.getMethodStr())) {
+ //根据之前的数据补偿现在的事务
+ int oldNotify = cinfo.getNotify();
+
+ if (oldNotify == 1) {
+ //本次回滚
+ txInfo.setIsCommit(0);
+ } else {
+ //本次提交
+ txInfo.setIsCommit(1);
+ }
+ //匹配后剔除列表
+ iterator.remove();
+ break;
+ }
+ }
+ }
+ } else {//当没有List数据只记录了补偿数据时,理解问仅发起方提交其他均回滚
+ for (TxInfo txInfo : txGroup.getList()) {
+ //本次回滚
+ txInfo.setIsCommit(0);
+ }
+ }
+ }
+ logger.info("Compensate Loaded->" + JSON.toJSONString(txGroup));
+ }
+
+ public TxGroup getCompensateByGroupId(String groupId) {
+ String json = compensateDao.getCompensateByGroupId(groupId);
+ if (json == null) {
+ return null;
+ }
+ JSONObject jsonObject = JSON.parseObject(json);
+ String txGroup = jsonObject.getString("txGroup");
+ return JSON.parseObject(txGroup, TxGroup.class);
+ }
+
+
+ @Override
+ public boolean executeCompensate(String path) throws ServiceException {
+
+ String json = compensateDao.getCompensate(path);
+ if (json == null) {
+ throw new ServiceException("no data existing");
+ }
+
+ boolean hasOk = _executeCompensate(json);
+ if (hasOk) {
+ // 删除本地补偿数据
+ compensateDao.deleteCompensateByPath(path);
+
+ return true;
+ }
+ return false;
+ }
+
+
+ private boolean _executeCompensate(String json) throws ServiceException {
+ JSONObject jsonObject = JSON.parseObject(json);
+
+ String model = jsonObject.getString("model");
+
+ int startError = jsonObject.getInteger("startError");
+
+ ModelInfo modelInfo = ModelInfoManager.getInstance().getModelByModel(model);
+ if (modelInfo == null) {
+ throw new ServiceException("current model offline.");
+ }
+
+ String data = jsonObject.getString("data");
+
+ String groupId = jsonObject.getString("groupId");
+
+ String res = managerSenderService.sendCompensateMsg(modelInfo.getChannelName(), groupId, data, startError);
+
+ logger.debug("executeCompensate->" + json + ",@@->" + res);
+
+ return "1".equals(res);
+ }
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/config/ConfigReader.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/config/ConfigReader.java
new file mode 100644
index 000000000..31d54bae2
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/config/ConfigReader.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.config;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+/**
+ * create by lorne on 2017/11/11
+ */
+@Component
+public class ConfigReader {
+
+ /**
+ * 事务默认数据的位置,有最大时间
+ */
+ private final String key_prefix = "tx:manager:default:";
+ /**
+ * 负载均衡模块存储信息
+ */
+ private final String key_prefix_loadbalance = "tx:manager:loadbalance:";
+ /**
+ * 补偿事务永久存储数据
+ */
+ private final String key_prefix_compensate = "tx:manager:compensate:";
+ @Value("${tm.socket.port}")
+ private int socketPort;
+ @Value("${tm.socket.maxconnection}")
+ private int socketMaxConnection;
+ @Value("${tm.transaction.netty.hearttime}")
+ private int transactionNettyHeartTime;
+ @Value("${tm.transaction.netty.delaytime}")
+ private int transactionNettyDelayTime;
+ @Value("${tm.redis.savemaxtime}")
+ private int redisSaveMaxTime;
+ @Value("${tm.compensate.notifyUrl}")
+ private String compensateNotifyUrl;
+ @Value("${tm.compensate.auto}")
+ private boolean isCompensateAuto;
+ @Value("${tm.compensate.tryTime}")
+ private int compensateTryTime;
+ @Value("${tm.compensate.maxWaitTime}")
+ private int compensateMaxWaitTime;
+
+ public String getKeyPrefixLoadbalance() {
+ return key_prefix_loadbalance;
+ }
+
+ public String getCompensateNotifyUrl() {
+ return compensateNotifyUrl;
+ }
+
+ public String getKeyPrefix() {
+ return key_prefix;
+ }
+
+ public String getKeyPrefixCompensate() {
+ return key_prefix_compensate;
+ }
+
+ public int getSocketPort() {
+ return socketPort;
+ }
+
+ public int getSocketMaxConnection() {
+ return socketMaxConnection;
+ }
+
+ public int getTransactionNettyHeartTime() {
+ return transactionNettyHeartTime;
+ }
+
+ public int getRedisSaveMaxTime() {
+ return redisSaveMaxTime;
+ }
+
+ public int getTransactionNettyDelayTime() {
+ return transactionNettyDelayTime;
+ }
+
+ public boolean isCompensateAuto() {
+ return isCompensateAuto;
+ }
+
+ public int getCompensateTryTime() {
+ return compensateTryTime;
+ }
+
+ public int getCompensateMaxWaitTime() {
+ return compensateMaxWaitTime;
+ }
+
+
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/config/CorsConfig.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/config/CorsConfig.java
new file mode 100644
index 000000000..bdfd6edf9
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/config/CorsConfig.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.cors.CorsConfiguration;
+import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
+import org.springframework.web.filter.CorsFilter;
+
+/**
+ * create by lorne on 2017/8/17
+ */
+@Configuration
+public class CorsConfig {
+
+ /**
+ * 跨域过滤器
+ *
+ * @return
+ */
+ private CorsConfiguration buildConfig() {
+ CorsConfiguration corsConfiguration = new CorsConfiguration();
+ corsConfiguration.addAllowedOrigin("*");
+ corsConfiguration.addAllowedHeader("*");
+ corsConfiguration.addAllowedMethod("*");
+ return corsConfiguration;
+ }
+
+
+ /**
+ * 跨域过滤器
+ *
+ * @return
+ */
+ @Bean
+ public CorsFilter corsFilter() {
+ UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+ source.registerCorsConfiguration("/**", buildConfig());
+ return new CorsFilter(source);
+ }
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/config/RestConfig.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/config/RestConfig.java
new file mode 100644
index 000000000..ad682736f
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/config/RestConfig.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.config;
+
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * Created by lorne on 2017/7/5.
+ */
+
+@Configuration
+@EnableAutoConfiguration
+public class RestConfig {
+
+
+ @Bean
+ public RestTemplate getRestTemplate() {
+ RestTemplate restTemplate = new RestTemplate();
+ return restTemplate;
+ }
+
+
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/framework/utils/Constants.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/framework/utils/Constants.java
new file mode 100644
index 000000000..18430b709
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/framework/utils/Constants.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.framework.utils;
+
+/**
+ * Created by lorne on 2017/6/8.
+ */
+public class Constants {
+
+
+ public static int maxConnection;
+
+ public static int socketPort;
+
+ public static String address;
+
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/framework/utils/SocketManager.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/framework/utils/SocketManager.java
new file mode 100644
index 000000000..1e7009546
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/framework/utils/SocketManager.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.framework.utils;
+
+import io.netty.channel.Channel;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * Created by lorne on 2017/6/30.
+ */
+public class SocketManager {
+
+ private static SocketManager manager = null;
+ /**
+ * 最大连接数
+ */
+ private int maxConnection = Constants.maxConnection;
+ /**
+ * 当前连接数
+ */
+ private int nowConnection;
+ /**
+ * 允许连接请求 true允许 false拒绝
+ */
+ private boolean allowConnection = true;
+ private List clients = null;
+ private Map lines = null;
+
+ private SocketManager() {
+ clients = new CopyOnWriteArrayList();
+ lines = new ConcurrentHashMap();
+ }
+
+ public static SocketManager getInstance() {
+ if (manager == null) {
+ synchronized (SocketManager.class) {
+ if (manager == null) {
+ manager = new SocketManager();
+ }
+ }
+ }
+ return manager;
+ }
+
+ public Channel getChannelByModelName(String name) {
+ for (Channel channel : clients) {
+ String modelName = channel.remoteAddress().toString();
+
+ if (modelName.equals(name)) {
+ return channel;
+ }
+ }
+ return null;
+ }
+
+ public void addClient(Channel client) {
+ clients.add(client);
+ nowConnection = clients.size();
+
+ allowConnection = (maxConnection != nowConnection);
+ }
+
+ public void removeClient(Channel client) {
+ clients.remove(client);
+ nowConnection = clients.size();
+
+ allowConnection = (maxConnection != nowConnection);
+ }
+
+
+ public int getMaxConnection() {
+ return maxConnection;
+ }
+
+ public int getNowConnection() {
+ return nowConnection;
+ }
+
+ public boolean isAllowConnection() {
+ return allowConnection;
+ }
+
+ public void outLine(String modelName) {
+ lines.remove(modelName);
+ }
+
+ public void onLine(String modelName, String uniqueKey) {
+ lines.put(modelName, uniqueKey);
+ }
+
+ public Channel getChannelByUniqueKey(String uniqueKey) {
+ for (Channel channel : clients) {
+ String modelName = channel.remoteAddress().toString();
+ String value = lines.get(modelName);
+ if (uniqueKey.equals(value)) {
+ return channel;
+ }
+ }
+ return null;
+ }
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/framework/utils/SocketUtils.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/framework/utils/SocketUtils.java
new file mode 100644
index 000000000..a5156f8e0
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/framework/utils/SocketUtils.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.framework.utils;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.util.ReferenceCountUtil;
+
+/**
+ * Created by lorne on 2017/7/6.
+ */
+public class SocketUtils {
+
+ public static String getJson(Object msg) {
+ String json;
+ try {
+ ByteBuf buf = (ByteBuf) msg;
+ byte[] bytes = new byte[buf.readableBytes()];
+ buf.readBytes(bytes);
+ json = new String(bytes);
+ } finally {
+ ReferenceCountUtil.release(msg);
+ }
+ return json;
+
+ }
+
+ public static void sendMsg(ChannelHandlerContext ctx, String msg) {
+ ctx.writeAndFlush(Unpooled.buffer().writeBytes(msg.getBytes()));
+ }
+
+
+ public static void sendMsg(Channel ctx, String msg) {
+ ctx.writeAndFlush(Unpooled.buffer().writeBytes(msg.getBytes()));
+ }
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/listener/ApplicationStartListener.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/listener/ApplicationStartListener.java
new file mode 100644
index 000000000..96e4130b1
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/listener/ApplicationStartListener.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.listener;
+
+import com.pig4cloud.pigx.manager.framework.utils.Constants;
+import org.springframework.boot.web.context.WebServerInitializedEvent;
+import org.springframework.context.ApplicationListener;
+import org.springframework.stereotype.Component;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * create by lorne on 2017/8/7
+ */
+@Component
+public class ApplicationStartListener implements ApplicationListener {
+
+
+ @Override
+ public void onApplicationEvent(WebServerInitializedEvent event) {
+ int serverPort = event.getWebServer().getPort();
+ String ip = getIp();
+ Constants.address = ip + ":" + serverPort;
+ }
+
+
+ private String getIp() {
+ String host = null;
+ try {
+ host = InetAddress.getLocalHost().getHostAddress();
+ } catch (UnknownHostException e) {
+ e.printStackTrace();
+ }
+ return host;
+ }
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/listener/ServerListener.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/listener/ServerListener.java
new file mode 100644
index 000000000..6382f8311
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/listener/ServerListener.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.listener;
+
+import com.pig4cloud.pigx.manager.listener.service.InitService;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.context.support.WebApplicationContextUtils;
+
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+
+
+/**
+ * Created by lorne on 2017/7/1.
+ */
+
+@Component
+public class ServerListener implements ServletContextListener {
+
+ private WebApplicationContext springContext;
+
+
+ private InitService initService;
+
+ @Override
+ public void contextInitialized(ServletContextEvent event) {
+ springContext = WebApplicationContextUtils
+ .getWebApplicationContext(event.getServletContext());
+ initService = springContext.getBean(InitService.class);
+ initService.start();
+ }
+
+
+ @Override
+ public void contextDestroyed(ServletContextEvent event) {
+ initService.close();
+ }
+
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/listener/service/InitService.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/listener/service/InitService.java
new file mode 100644
index 000000000..7c84ca927
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/listener/service/InitService.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.listener.service;
+
+/**
+ * Created by lorne on 2017/7/4.
+ */
+public interface InitService {
+
+ void start();
+
+
+ void close();
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/listener/service/impl/InitServiceImpl.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/listener/service/impl/InitServiceImpl.java
new file mode 100644
index 000000000..3301092a3
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/listener/service/impl/InitServiceImpl.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.listener.service.impl;
+
+import com.pig4cloud.pigx.manager.config.ConfigReader;
+import com.pig4cloud.pigx.manager.framework.utils.Constants;
+import com.pig4cloud.pigx.manager.listener.service.InitService;
+import com.pig4cloud.pigx.manager.netty.service.NettyServerService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+
+/**
+ * Created by lorne on 2017/7/4.
+ */
+@Service
+public class InitServiceImpl implements InitService {
+
+ @Autowired
+ private NettyServerService nettyServerService;
+
+ @Autowired
+ private ConfigReader configReader;
+
+
+ @Override
+ public void start() {
+ /**加载本地服务信息**/
+
+ Constants.socketPort = configReader.getSocketPort();
+ Constants.maxConnection = configReader.getSocketMaxConnection();
+ nettyServerService.start();
+ }
+
+ @Override
+ public void close() {
+ nettyServerService.close();
+ }
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/manager/ModelInfoManager.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/manager/ModelInfoManager.java
new file mode 100644
index 000000000..496c55bde
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/manager/ModelInfoManager.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.manager;
+
+import com.pig4cloud.pigx.manager.model.ModelInfo;
+
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * create by lorne on 2017/11/13
+ */
+public class ModelInfoManager {
+
+
+ private static ModelInfoManager manager = null;
+ private List modelInfos = new CopyOnWriteArrayList();
+
+ public static ModelInfoManager getInstance() {
+ if (manager == null) {
+ synchronized (ModelInfoManager.class) {
+ if (manager == null) {
+ manager = new ModelInfoManager();
+ }
+ }
+ }
+ return manager;
+ }
+
+ public void removeModelInfo(String channelName) {
+ for (ModelInfo modelInfo : modelInfos) {
+ if (channelName.equalsIgnoreCase(modelInfo.getChannelName())) {
+ modelInfos.remove(modelInfo);
+ }
+ }
+ }
+
+
+ public void addModelInfo(ModelInfo minfo) {
+ for (ModelInfo modelInfo : modelInfos) {
+ if (minfo.getChannelName().equalsIgnoreCase(modelInfo.getChannelName())) {
+ return;
+ }
+
+ if (minfo.getIpAddress().equalsIgnoreCase(modelInfo.getIpAddress())) {
+ return;
+ }
+ }
+ modelInfos.add(minfo);
+ }
+
+ public List getOnlines() {
+ return modelInfos;
+ }
+
+ public ModelInfo getModelByChannelName(String channelName) {
+ for (ModelInfo modelInfo : modelInfos) {
+ if (channelName.equalsIgnoreCase(modelInfo.getChannelName())) {
+ return modelInfo;
+ }
+ }
+ return null;
+ }
+
+ public ModelInfo getModelByModel(String model) {
+ for (ModelInfo modelInfo : modelInfos) {
+ if (model.equalsIgnoreCase(modelInfo.getModel())) {
+ return modelInfo;
+ }
+ }
+ return null;
+ }
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/manager/service/LoadBalanceService.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/manager/service/LoadBalanceService.java
new file mode 100644
index 000000000..3e862cf3a
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/manager/service/LoadBalanceService.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.manager.service;
+
+import com.pig4cloud.pigx.manager.model.LoadBalanceInfo;
+
+/**
+ * create by lorne on 2017/12/5
+ */
+public interface LoadBalanceService {
+
+ boolean put(LoadBalanceInfo loadBalanceInfo);
+
+ LoadBalanceInfo get(String groupId, String key);
+
+ boolean remove(String groupId);
+
+ String getLoadBalanceGroupName(String groupId);
+
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/manager/service/MicroService.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/manager/service/MicroService.java
new file mode 100644
index 000000000..f7ec76c80
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/manager/service/MicroService.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.manager.service;
+
+import com.pig4cloud.pigx.manager.model.TxServer;
+import com.pig4cloud.pigx.manager.model.TxState;
+
+/**
+ * create by lorne on 2017/11/11
+ */
+public interface MicroService {
+
+ String tmKey = "tx-manager";
+
+ TxServer getServer();
+
+ TxState getState();
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/manager/service/TxManagerSenderService.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/manager/service/TxManagerSenderService.java
new file mode 100644
index 000000000..2373e2a1d
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/manager/service/TxManagerSenderService.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.manager.service;
+
+import com.pig4cloud.pigx.manager.netty.model.TxGroup;
+
+/**
+ * Created by lorne on 2017/6/9.
+ */
+public interface TxManagerSenderService {
+
+ int confirm(TxGroup group);
+
+ String sendMsg(String model, String msg, int delay);
+
+ String sendCompensateMsg(String model, String groupId, String data, int startState);
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/manager/service/TxManagerService.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/manager/service/TxManagerService.java
new file mode 100644
index 000000000..3b35df3f8
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/manager/service/TxManagerService.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.manager.service;
+
+import com.pig4cloud.pigx.manager.netty.model.TxGroup;
+
+/**
+ * Created by lorne on 2017/6/7.
+ */
+
+public interface TxManagerService {
+
+
+ /**
+ * 创建事物组
+ *
+ * @param groupId 补偿事务组id
+ */
+ TxGroup createTransactionGroup(String groupId);
+
+
+ /**
+ * 添加事务组子对象
+ *
+ * @return
+ */
+
+ TxGroup addTransactionGroup(String groupId, String taskId, int isGroup, String channelAddress, String methodStr);
+
+
+ /**
+ * 关闭事务组
+ *
+ * @param groupId 事务组id
+ * @param state 事务状态
+ * @return 0 事务存在补偿 1 事务正常 -1 事务强制回滚
+ */
+ int closeTransactionGroup(String groupId, int state);
+
+
+ void dealTxGroup(TxGroup txGroup, boolean hasOk);
+
+
+ /**
+ * 删除事务组
+ *
+ * @param txGroup 事务组
+ */
+ void deleteTxGroup(TxGroup txGroup);
+
+
+ /**
+ * 获取事务组信息
+ *
+ * @param groupId 事务组id
+ * @return 事务组
+ */
+ TxGroup getTxGroup(String groupId);
+
+
+ /**
+ * 获取事务组的key
+ *
+ * @param groupId 事务组id
+ * @return key
+ */
+ String getTxGroupKey(String groupId);
+
+
+ /**
+ * 检查事务组数据
+ *
+ * @param groupId 事务组id
+ * @param taskId 任务id
+ * @return 本次请求的是否提交 1提交 0回滚
+ */
+ int cleanNotifyTransaction(String groupId, String taskId);
+
+
+ /**
+ * 设置强制回滚事务
+ *
+ * @param groupId 事务组id
+ * @return true 成功 false 失败
+ */
+ boolean rollbackTransactionGroup(String groupId);
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/manager/service/impl/LoadBalanceServiceImpl.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/manager/service/impl/LoadBalanceServiceImpl.java
new file mode 100644
index 000000000..0399c8faa
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/manager/service/impl/LoadBalanceServiceImpl.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.manager.service.impl;
+
+import com.pig4cloud.pigx.manager.config.ConfigReader;
+import com.pig4cloud.pigx.manager.manager.service.LoadBalanceService;
+import com.pig4cloud.pigx.manager.model.LoadBalanceInfo;
+import com.pig4cloud.pigx.manager.redis.RedisServerService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * create by lorne on 2017/12/5
+ */
+@Service
+public class LoadBalanceServiceImpl implements LoadBalanceService {
+
+ @Autowired
+ private RedisServerService redisServerService;
+
+ @Autowired
+ private ConfigReader configReader;
+
+ @Override
+ public boolean put(LoadBalanceInfo loadBalanceInfo) {
+ String groupName = getLoadBalanceGroupName(loadBalanceInfo.getGroupId());
+ redisServerService.saveLoadBalance(groupName, loadBalanceInfo.getKey(), loadBalanceInfo.getData());
+ return true;
+ }
+
+ @Override
+ public LoadBalanceInfo get(String groupId, String key) {
+ String groupName = getLoadBalanceGroupName(groupId);
+ String bytes = redisServerService.getLoadBalance(groupName, key);
+ if (bytes == null) {
+ return null;
+ }
+
+ LoadBalanceInfo loadBalanceInfo = new LoadBalanceInfo();
+ loadBalanceInfo.setGroupId(groupId);
+ loadBalanceInfo.setKey(key);
+ loadBalanceInfo.setData(bytes);
+ return loadBalanceInfo;
+ }
+
+ @Override
+ public boolean remove(String groupId) {
+ redisServerService.deleteKey(getLoadBalanceGroupName(groupId));
+ return true;
+ }
+
+ @Override
+ public String getLoadBalanceGroupName(String groupId) {
+ return configReader.getKeyPrefixLoadbalance() + groupId;
+ }
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/manager/service/impl/MicroServiceImpl.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/manager/service/impl/MicroServiceImpl.java
new file mode 100644
index 000000000..c32433c51
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/manager/service/impl/MicroServiceImpl.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.manager.service.impl;
+
+import com.pig4cloud.pigx.manager.config.ConfigReader;
+import com.pig4cloud.pigx.manager.framework.utils.Constants;
+import com.pig4cloud.pigx.manager.framework.utils.SocketManager;
+import com.pig4cloud.pigx.manager.manager.service.MicroService;
+import com.pig4cloud.pigx.manager.model.TxServer;
+import com.pig4cloud.pigx.manager.model.TxState;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cloud.client.ServiceInstance;
+import org.springframework.cloud.client.discovery.DiscoveryClient;
+import org.springframework.cloud.client.serviceregistry.Registration;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestTemplate;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * create by lorne on 2017/11/11
+ */
+@Service
+public class MicroServiceImpl implements MicroService {
+
+
+ @Autowired
+ private RestTemplate restTemplate;
+
+ @Autowired
+ private ConfigReader configReader;
+
+
+ @Autowired
+ private DiscoveryClient discoveryClient;
+
+ @Autowired
+ private Registration registration;
+
+ private boolean isIp(String ipAddress) {
+ String ip = "([1-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3}";
+ Pattern pattern = Pattern.compile(ip);
+ Matcher matcher = pattern.matcher(ipAddress);
+ return matcher.matches();
+ }
+
+
+ @Override
+ public TxState getState() {
+ TxState state = new TxState();
+ String ipAddress = registration.getHost();
+ if (!isIp(ipAddress)) {
+ ipAddress = "127.0.0.1";
+ }
+ state.setIp(ipAddress);
+ state.setPort(Constants.socketPort);
+ state.setMaxConnection(SocketManager.getInstance().getMaxConnection());
+ state.setNowConnection(SocketManager.getInstance().getNowConnection());
+ state.setRedisSaveMaxTime(configReader.getRedisSaveMaxTime());
+ state.setTransactionNettyDelayTime(configReader.getTransactionNettyDelayTime());
+ state.setTransactionNettyHeartTime(configReader.getTransactionNettyHeartTime());
+ state.setNotifyUrl(configReader.getCompensateNotifyUrl());
+ state.setCompensate(configReader.isCompensateAuto());
+ state.setCompensateTryTime(configReader.getCompensateTryTime());
+ state.setCompensateMaxWaitTime(configReader.getCompensateMaxWaitTime());
+ state.setSlbList(getServices());
+ return state;
+ }
+
+ private List getServices() {
+ List urls = new ArrayList<>();
+ List serviceInstances = discoveryClient.getInstances(tmKey);
+ for (ServiceInstance instanceInfo : serviceInstances) {
+ urls.add(instanceInfo.getUri().toASCIIString());
+ }
+ return urls;
+ }
+
+ @Override
+ public TxServer getServer() {
+ List urls = getServices();
+ List states = new ArrayList<>();
+ for (String url : urls) {
+ try {
+ TxState state = restTemplate.getForObject(url + "/tx/manager/state", TxState.class);
+ states.add(state);
+ } catch (Exception e) {
+ }
+
+ }
+ if (states.size() <= 1) {
+ TxState state = getState();
+ if (state.getMaxConnection() > state.getNowConnection()) {
+ return TxServer.format(state);
+ } else {
+ return null;
+ }
+ } else {
+ //找默认数据
+ TxState state = getDefault(states, 0);
+ if (state == null) {
+ //没有满足的默认数据
+ return null;
+ }
+ return TxServer.format(state);
+ }
+ }
+
+ private TxState getDefault(List states, int index) {
+ TxState state = states.get(index);
+ if (state.getMaxConnection() == state.getNowConnection()) {
+ index++;
+ if (states.size() - 1 >= index) {
+ return getDefault(states, index);
+ } else {
+ return null;
+ }
+ } else {
+ return state;
+ }
+ }
+
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/manager/service/impl/TxManagerSenderServiceImpl.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/manager/service/impl/TxManagerSenderServiceImpl.java
new file mode 100644
index 000000000..55177ff26
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/manager/service/impl/TxManagerSenderServiceImpl.java
@@ -0,0 +1,335 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.manager.service.impl;
+
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.lorne.core.framework.utils.KidUtils;
+import com.lorne.core.framework.utils.task.ConditionUtils;
+import com.lorne.core.framework.utils.task.IBack;
+import com.lorne.core.framework.utils.task.Task;
+import com.lorne.core.framework.utils.thread.CountDownLatchHelper;
+import com.lorne.core.framework.utils.thread.IExecute;
+import com.pig4cloud.pigx.manager.compensate.service.CompensateService;
+import com.pig4cloud.pigx.manager.config.ConfigReader;
+import com.pig4cloud.pigx.manager.framework.utils.Constants;
+import com.pig4cloud.pigx.manager.framework.utils.SocketManager;
+import com.pig4cloud.pigx.manager.framework.utils.SocketUtils;
+import com.pig4cloud.pigx.manager.manager.service.TxManagerSenderService;
+import com.pig4cloud.pigx.manager.manager.service.TxManagerService;
+import com.pig4cloud.pigx.manager.model.ChannelSender;
+import com.pig4cloud.pigx.manager.netty.model.TxGroup;
+import com.pig4cloud.pigx.manager.netty.model.TxInfo;
+import com.pig4cloud.pigx.manager.redis.RedisServerService;
+import io.netty.channel.Channel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.concurrent.*;
+
+
+/**
+ * Created by lorne on 2017/6/9.
+ */
+@Service
+public class TxManagerSenderServiceImpl implements TxManagerSenderService {
+
+
+ private Logger logger = LoggerFactory.getLogger(TxManagerSenderServiceImpl.class);
+
+ private ScheduledExecutorService executorService = Executors.newScheduledThreadPool(100);
+
+ private Executor threadPool = Executors.newFixedThreadPool(100);
+
+ @Autowired
+ private TxManagerService txManagerService;
+
+ @Autowired
+ private RedisServerService redisServerService;
+
+ @Autowired
+ private ConfigReader configReader;
+
+ @Autowired
+ private CompensateService compensateService;
+
+ @Override
+ public int confirm(TxGroup txGroup) {
+ //绑定管道对象,检查网络
+ setChannel(txGroup.getList());
+
+ //事务不满足直接回滚事务
+ if (txGroup.getState() == 0) {
+ transaction(txGroup, 0);
+ return 0;
+ }
+
+ if (txGroup.getRollback() == 1) {
+ transaction(txGroup, 0);
+ return -1;
+ }
+
+ boolean hasOk = transaction(txGroup, 1);
+ txManagerService.dealTxGroup(txGroup, hasOk);
+ return hasOk ? 1 : 0;
+ }
+
+
+ /**
+ * 匹配管道
+ *
+ * @param list
+ */
+ private void setChannel(List list) {
+ for (TxInfo info : list) {
+ if (Constants.address.equals(info.getAddress())) {
+ Channel channel = SocketManager.getInstance().getChannelByModelName(info.getChannelAddress());
+ if (channel != null && channel.isActive()) {
+ ChannelSender sender = new ChannelSender();
+ sender.setChannel(channel);
+
+ info.setChannel(sender);
+ }
+ } else {
+ ChannelSender sender = new ChannelSender();
+ sender.setAddress(info.getAddress());
+ sender.setModelName(info.getChannelAddress());
+
+ info.setChannel(sender);
+ }
+ }
+ }
+
+
+ /**
+ * 事务提交或回归
+ *
+ * @param checkSate
+ */
+ private boolean transaction(final TxGroup txGroup, final int checkSate) {
+
+
+ if (checkSate == 1) {
+
+ //补偿请求,加载历史数据
+ if (txGroup.getIsCompensate() == 1) {
+ compensateService.reloadCompensate(txGroup);
+ }
+
+ CountDownLatchHelper countDownLatchHelper = new CountDownLatchHelper();
+ for (final TxInfo txInfo : txGroup.getList()) {
+ if (txInfo.getIsGroup() == 0) {
+ countDownLatchHelper.addExecute(new IExecute() {
+ @Override
+ public Boolean execute() {
+ if (txInfo.getChannel() == null) {
+ return false;
+ }
+
+ final JSONObject jsonObject = new JSONObject();
+ jsonObject.put("a", "t");
+
+
+ if (txGroup.getIsCompensate() == 1) { //补偿请求
+ jsonObject.put("c", txInfo.getIsCommit());
+ } else { //正常业务
+ jsonObject.put("c", checkSate);
+ }
+
+ jsonObject.put("t", txInfo.getKid());
+ final String key = KidUtils.generateShortUuid();
+ jsonObject.put("k", key);
+
+ Task task = ConditionUtils.getInstance().createTask(key);
+
+ ScheduledFuture future = schedule(key, configReader.getTransactionNettyDelayTime());
+
+ threadAwaitSend(task, txInfo, jsonObject.toJSONString());
+
+ task.awaitTask();
+
+ if (!future.isDone()) {
+ future.cancel(false);
+ }
+
+ try {
+ String data = (String) task.getBack().doing();
+ // 1 成功 0 失败 -1 task为空 -2 超过
+ boolean res = "1".equals(data);
+
+ if (res) {
+ txInfo.setNotify(1);
+ }
+
+ return res;
+ } catch (Throwable throwable) {
+ throwable.printStackTrace();
+ return false;
+ } finally {
+ task.remove();
+ }
+ }
+ });
+ }
+ }
+
+ List hasOks = countDownLatchHelper.execute().getData();
+
+ String key = configReader.getKeyPrefix() + txGroup.getGroupId();
+ redisServerService.saveTransaction(key, txGroup.toJsonString());
+
+ boolean hasOk = true;
+ for (boolean bl : hasOks) {
+ if (!bl) {
+ hasOk = false;
+ break;
+ }
+ }
+ logger.info("--->" + hasOk + ",group:" + txGroup.getGroupId() + ",state:" + checkSate + ",list:" + txGroup.toJsonString());
+ return hasOk;
+ } else {
+ //回滚操作只发送通过不需要等待确认
+ for (TxInfo txInfo : txGroup.getList()) {
+ if (txInfo.getChannel() != null) {
+ if (txInfo.getIsGroup() == 0) {
+ JSONObject jsonObject = new JSONObject();
+ jsonObject.put("a", "t");
+ jsonObject.put("c", checkSate);
+ jsonObject.put("t", txInfo.getKid());
+ String key = KidUtils.generateShortUuid();
+ jsonObject.put("k", key);
+ txInfo.getChannel().send(jsonObject.toJSONString());
+ }
+ }
+ }
+ txManagerService.deleteTxGroup(txGroup);
+ return true;
+ }
+
+ }
+
+ @Override
+ public String sendCompensateMsg(String model, String groupId, String data, int startState) {
+ JSONObject newCmd = new JSONObject();
+ newCmd.put("a", "c");
+ newCmd.put("d", data);
+ newCmd.put("ss", startState);
+ newCmd.put("g", groupId);
+ newCmd.put("k", KidUtils.generateShortUuid());
+ return sendMsg(model, newCmd.toJSONString(), configReader.getRedisSaveMaxTime());
+ }
+
+ @Override
+ public String sendMsg(final String model, final String msg, int delay) {
+ JSONObject jsonObject = JSON.parseObject(msg);
+ String key = jsonObject.getString("k");
+
+ //创建Task
+ final Task task = ConditionUtils.getInstance().createTask(key);
+
+ threadPool.execute(new Runnable() {
+ @Override
+ public void run() {
+ while (!task.isAwait() && !Thread.currentThread().interrupted()) {
+ try {
+ Thread.sleep(1);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ Channel channel = SocketManager.getInstance().getChannelByModelName(model);
+ if (channel != null && channel.isActive()) {
+ SocketUtils.sendMsg(channel, msg);
+ }
+ }
+ });
+
+ ScheduledFuture future = schedule(key, delay);
+
+ task.awaitTask();
+
+ if (!future.isDone()) {
+ future.cancel(false);
+ }
+
+ try {
+ return (String) task.getBack().doing();
+ } catch (Throwable throwable) {
+ return "-1";
+ } finally {
+ task.remove();
+ }
+ }
+
+
+ private void threadAwaitSend(final Task task, final TxInfo txInfo, final String msg) {
+ threadPool.execute(new Runnable() {
+ @Override
+ public void run() {
+ while (!task.isAwait() && !Thread.currentThread().interrupted()) {
+ try {
+ Thread.sleep(1);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ if (txInfo != null && txInfo.getChannel() != null) {
+ txInfo.getChannel().send(msg, task);
+ } else {
+ task.setBack(new IBack() {
+ @Override
+ public Object doing(Object... objs) throws Throwable {
+ return "-2";
+ }
+ });
+ task.signalTask();
+ }
+ }
+ });
+
+ }
+
+
+ private ScheduledFuture schedule(final String key, int delayTime) {
+ ScheduledFuture future = executorService.schedule(new Runnable() {
+ @Override
+ public void run() {
+ Task task = ConditionUtils.getInstance().getTask(key);
+ if (task != null && !task.isNotify()) {
+ task.setBack(new IBack() {
+ @Override
+ public Object doing(Object... objs) throws Throwable {
+ return "-2";
+ }
+ });
+ task.signalTask();
+ }
+ }
+ }, delayTime, TimeUnit.SECONDS);
+
+ return future;
+ }
+
+
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/manager/service/impl/TxManagerServiceImpl.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/manager/service/impl/TxManagerServiceImpl.java
new file mode 100644
index 000000000..f943fcd02
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/manager/service/impl/TxManagerServiceImpl.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.manager.service.impl;
+
+
+import com.pig4cloud.pigx.manager.compensate.service.CompensateService;
+import com.pig4cloud.pigx.manager.config.ConfigReader;
+import com.pig4cloud.pigx.manager.framework.utils.Constants;
+import com.pig4cloud.pigx.manager.manager.ModelInfoManager;
+import com.pig4cloud.pigx.manager.manager.service.LoadBalanceService;
+import com.pig4cloud.pigx.manager.manager.service.TxManagerSenderService;
+import com.pig4cloud.pigx.manager.manager.service.TxManagerService;
+import com.pig4cloud.pigx.manager.model.ModelInfo;
+import com.pig4cloud.pigx.manager.netty.model.TxGroup;
+import com.pig4cloud.pigx.manager.netty.model.TxInfo;
+import com.pig4cloud.pigx.manager.redis.RedisServerService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * Created by lorne on 2017/6/7.
+ */
+@Service
+public class TxManagerServiceImpl implements TxManagerService {
+ @Autowired
+ private ConfigReader configReader;
+ @Autowired
+ private RedisServerService redisServerService;
+
+
+ @Autowired
+ private TxManagerSenderService transactionConfirmService;
+
+
+ @Autowired
+ private LoadBalanceService loadBalanceService;
+
+ @Autowired
+ private CompensateService compensateService;
+
+
+ private Logger logger = LoggerFactory.getLogger(TxManagerServiceImpl.class);
+
+
+ @Override
+ public TxGroup createTransactionGroup(String groupId) {
+ TxGroup txGroup = new TxGroup();
+ if (compensateService.getCompensateByGroupId(groupId) != null) {
+ txGroup.setIsCompensate(1);
+ }
+
+ txGroup.setStartTime(System.currentTimeMillis());
+ txGroup.setGroupId(groupId);
+
+ String key = configReader.getKeyPrefix() + groupId;
+ redisServerService.saveTransaction(key, txGroup.toJsonString());
+
+ return txGroup;
+ }
+
+
+ @Override
+ public TxGroup addTransactionGroup(String groupId, String taskId, int isGroup, String channelAddress, String methodStr) {
+ String key = getTxGroupKey(groupId);
+ TxGroup txGroup = getTxGroup(groupId);
+ if (txGroup == null) {
+ return null;
+ }
+ TxInfo txInfo = new TxInfo();
+ txInfo.setChannelAddress(channelAddress);
+ txInfo.setKid(taskId);
+ txInfo.setAddress(Constants.address);
+ txInfo.setIsGroup(isGroup);
+ txInfo.setMethodStr(methodStr);
+
+
+ ModelInfo modelInfo = ModelInfoManager.getInstance().getModelByChannelName(channelAddress);
+ if (modelInfo != null) {
+ txInfo.setUniqueKey(modelInfo.getUniqueKey());
+ txInfo.setModelIpAddress(modelInfo.getIpAddress());
+ txInfo.setModel(modelInfo.getModel());
+ }
+
+ txGroup.addTransactionInfo(txInfo);
+
+ redisServerService.saveTransaction(key, txGroup.toJsonString());
+
+ return txGroup;
+ }
+
+ @Override
+ public boolean rollbackTransactionGroup(String groupId) {
+ String key = getTxGroupKey(groupId);
+ TxGroup txGroup = getTxGroup(groupId);
+ if (txGroup == null) {
+ return false;
+ }
+ txGroup.setRollback(1);
+ redisServerService.saveTransaction(key, txGroup.toJsonString());
+ return true;
+ }
+
+ @Override
+ public int cleanNotifyTransaction(String groupId, String taskId) {
+ int res = 0;
+ logger.info("start-cleanNotifyTransaction->groupId:" + groupId + ",taskId:" + taskId);
+ String key = getTxGroupKey(groupId);
+ TxGroup txGroup = getTxGroup(groupId);
+ if (txGroup == null) {
+ logger.info("cleanNotifyTransaction - > txGroup is null ");
+ return res;
+ }
+
+ if (txGroup.getHasOver() == 0) {
+
+ //整个事务回滚.
+ txGroup.setRollback(1);
+ redisServerService.saveTransaction(key, txGroup.toJsonString());
+
+ logger.info("cleanNotifyTransaction - > groupId " + groupId + " not over,all transaction must rollback !");
+ return 0;
+ }
+
+ if (txGroup.getRollback() == 1) {
+ logger.info("cleanNotifyTransaction - > groupId " + groupId + " only rollback !");
+ return 0;
+ }
+
+ //更新数据
+ boolean hasSet = false;
+ for (TxInfo info : txGroup.getList()) {
+ if (info.getKid().equals(taskId)) {
+ if (info.getNotify() == 0 && info.getIsGroup() == 0) {
+ info.setNotify(1);
+ hasSet = true;
+ res = 1;
+
+ break;
+ }
+ }
+ }
+
+ //判断是否都结束
+ boolean isOver = true;
+ for (TxInfo info : txGroup.getList()) {
+ if (info.getIsGroup() == 0 && info.getNotify() == 0) {
+ isOver = false;
+ break;
+ }
+ }
+
+ if (isOver) {
+ deleteTxGroup(txGroup);
+ }
+
+ //有更新的数据,需要修改记录
+ if (!isOver && hasSet) {
+ redisServerService.saveTransaction(key, txGroup.toJsonString());
+ }
+
+ logger.info("end-cleanNotifyTransaction->groupId:" + groupId + ",taskId:" + taskId + ",res(1:commit,0:rollback):" + res);
+ return res;
+ }
+
+
+ @Override
+ public int closeTransactionGroup(String groupId, int state) {
+ String key = getTxGroupKey(groupId);
+ TxGroup txGroup = getTxGroup(groupId);
+ if (txGroup == null) {
+ return 0;
+ }
+ txGroup.setState(state);
+ txGroup.setHasOver(1);
+ redisServerService.saveTransaction(key, txGroup.toJsonString());
+ return transactionConfirmService.confirm(txGroup);
+ }
+
+
+ @Override
+ public void dealTxGroup(TxGroup txGroup, boolean hasOk) {
+ if (hasOk) {
+ deleteTxGroup(txGroup);
+ }
+ }
+
+
+ @Override
+ public void deleteTxGroup(TxGroup txGroup) {
+ String groupId = txGroup.getGroupId();
+
+ String key = getTxGroupKey(groupId);
+ redisServerService.deleteKey(key);
+
+ loadBalanceService.remove(groupId);
+ }
+
+
+ @Override
+ public TxGroup getTxGroup(String groupId) {
+ String key = getTxGroupKey(groupId);
+ return redisServerService.getTxGroupByKey(key);
+ }
+
+ @Override
+ public String getTxGroupKey(String groupId) {
+ return configReader.getKeyPrefix() + groupId;
+ }
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/model/ChannelSender.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/model/ChannelSender.java
new file mode 100644
index 000000000..489d39bc2
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/model/ChannelSender.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.model;
+
+import com.lorne.core.framework.utils.http.HttpUtils;
+import com.lorne.core.framework.utils.task.IBack;
+import com.lorne.core.framework.utils.task.Task;
+import com.pig4cloud.pigx.manager.framework.utils.SocketUtils;
+import io.netty.channel.Channel;
+import org.apache.commons.lang.StringUtils;
+
+/**
+ * create by lorne on 2017/8/7
+ */
+public class ChannelSender {
+
+
+ private Channel channel;
+
+ private String address;
+
+ private String modelName;
+
+ public void setModelName(String modelName) {
+ this.modelName = modelName;
+ }
+
+ public void setChannel(Channel channel) {
+ this.channel = channel;
+ }
+
+ public void setAddress(String address) {
+ this.address = address;
+ }
+
+
+ public void send(String msg) {
+ if (channel != null) {
+ SocketUtils.sendMsg(channel, msg);
+ }
+
+ }
+
+ public void send(String msg, Task task) {
+ if (channel != null) {
+ SocketUtils.sendMsg(channel, msg);
+ } else {
+ String url = String.format("http://%s/tx/manager/sendMsg", address);
+ final String res = HttpUtils.post(url, "msg=" + msg + "&model=" + modelName);
+ if (StringUtils.isNotEmpty(res)) {
+ if (task != null) {
+ task.setBack(new IBack() {
+ @Override
+ public Object doing(Object... objs) throws Throwable {
+ return res;
+ }
+ });
+ task.signalTask();
+ }
+ } else {
+ if (task != null) {
+ task.setBack(new IBack() {
+ @Override
+ public Object doing(Object... objs) throws Throwable {
+ return "-2";
+ }
+ });
+ task.signalTask();
+ }
+ }
+ }
+
+ }
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/model/LoadBalanceInfo.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/model/LoadBalanceInfo.java
new file mode 100644
index 000000000..5c47d38c9
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/model/LoadBalanceInfo.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.model;
+
+/**
+ * 负载均衡模块信息
+ * create by lorne on 2017/12/5
+ */
+public class LoadBalanceInfo {
+
+ private String groupId;
+
+ private String key;
+
+ private String data;
+
+
+ public String getGroupId() {
+ return groupId;
+ }
+
+ public void setGroupId(String groupId) {
+ this.groupId = groupId;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public void setKey(String key) {
+ this.key = key;
+ }
+
+ public String getData() {
+ return data;
+ }
+
+ public void setData(String data) {
+ this.data = data;
+ }
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/model/ModelInfo.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/model/ModelInfo.java
new file mode 100644
index 000000000..0f1cca193
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/model/ModelInfo.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.model;
+
+/**
+ * 模块信息
+ * create by lorne on 2017/11/13
+ */
+public class ModelInfo {
+
+ private String model;
+
+ private String ipAddress;
+
+ private String channelName;
+
+ private String uniqueKey;
+
+ public String getModel() {
+ return model;
+ }
+
+ public void setModel(String model) {
+ this.model = model;
+ }
+
+ public String getIpAddress() {
+ return ipAddress;
+ }
+
+ public void setIpAddress(String ipAddress) {
+ this.ipAddress = ipAddress;
+ }
+
+ public String getChannelName() {
+ return channelName;
+ }
+
+ public void setChannelName(String channelName) {
+ this.channelName = channelName;
+ }
+
+ public String getUniqueKey() {
+ return uniqueKey;
+ }
+
+ public void setUniqueKey(String uniqueKey) {
+ this.uniqueKey = uniqueKey;
+ }
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/model/ModelName.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/model/ModelName.java
new file mode 100644
index 000000000..1d51694ed
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/model/ModelName.java
@@ -0,0 +1,45 @@
+
+
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.model;
+
+/**
+ * create by lorne on 2017/11/22
+ */
+public class ModelName {
+
+ private String name;
+ private int count;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+ public void setCount(int count) {
+ this.count = count;
+ }
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/model/TxServer.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/model/TxServer.java
new file mode 100644
index 000000000..7c6c19251
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/model/TxServer.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.model;
+
+/**
+ * Created by lorne on 2017/7/1.
+ */
+public class TxServer {
+
+ private String ip;
+ private int port;
+ private int heart;
+ private int delay;
+ private int compensateMaxWaitTime;
+
+ public static TxServer format(TxState state) {
+ TxServer txServer = new TxServer();
+ txServer.setIp(state.getIp());
+ txServer.setPort(state.getPort());
+ txServer.setHeart(state.getTransactionNettyHeartTime());
+ txServer.setDelay(state.getTransactionNettyDelayTime());
+ txServer.setCompensateMaxWaitTime(state.getCompensateMaxWaitTime());
+ return txServer;
+ }
+
+
+ public String getIp() {
+ return ip;
+ }
+
+ public void setIp(String ip) {
+ this.ip = ip;
+ }
+
+
+ public int getPort() {
+ return port;
+ }
+
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+ public int getHeart() {
+ return heart;
+ }
+
+ public void setHeart(int heart) {
+ this.heart = heart;
+ }
+
+ public int getDelay() {
+ return delay;
+ }
+
+ public void setDelay(int delay) {
+ this.delay = delay;
+ }
+
+
+ public int getCompensateMaxWaitTime() {
+ return compensateMaxWaitTime;
+ }
+
+
+ public void setCompensateMaxWaitTime(int compensateMaxWaitTime) {
+ this.compensateMaxWaitTime = compensateMaxWaitTime;
+ }
+
+
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/model/TxState.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/model/TxState.java
new file mode 100644
index 000000000..bf65e3830
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/model/TxState.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.model;
+
+import java.util.List;
+
+/**
+ * Created by lorne on 2017/7/1.
+ */
+public class TxState {
+
+ /**
+ * socket ip
+ */
+ private String ip;
+ /**
+ * socket port
+ */
+ private int port;
+
+ /**
+ * max connection
+ */
+ private int maxConnection;
+
+ /**
+ * now connection
+ */
+ private int nowConnection;
+
+
+ /**
+ * transaction_netty_heart_time
+ */
+ private int transactionNettyHeartTime;
+
+ /**
+ * transaction_netty_delay_time
+ */
+ private int transactionNettyDelayTime;
+
+
+ /**
+ * redis_save_max_time
+ */
+ private int redisSaveMaxTime;
+
+
+ /**
+ * 回调地址
+ */
+ private String notifyUrl;
+
+ /**
+ * 自动补偿
+ */
+ private boolean isCompensate;
+
+ /**
+ * 补偿尝试时间
+ */
+ private int compensateTryTime;
+
+ /**
+ * slb list
+ */
+ private List slbList;
+
+ /**
+ * 自动补偿间隔时间
+ */
+ private int compensateMaxWaitTime;
+
+
+ public String getIp() {
+ return ip;
+ }
+
+ public void setIp(String ip) {
+ this.ip = ip;
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+ public int getMaxConnection() {
+ return maxConnection;
+ }
+
+ public void setMaxConnection(int maxConnection) {
+ this.maxConnection = maxConnection;
+ }
+
+ public int getNowConnection() {
+ return nowConnection;
+ }
+
+ public void setNowConnection(int nowConnection) {
+ this.nowConnection = nowConnection;
+ }
+
+ public boolean isCompensate() {
+ return isCompensate;
+ }
+
+ public void setCompensate(boolean compensate) {
+ isCompensate = compensate;
+ }
+
+ public int getCompensateTryTime() {
+ return compensateTryTime;
+ }
+
+ public void setCompensateTryTime(int compensateTryTime) {
+ this.compensateTryTime = compensateTryTime;
+ }
+
+ public int getRedisSaveMaxTime() {
+ return redisSaveMaxTime;
+ }
+
+ public void setRedisSaveMaxTime(int redisSaveMaxTime) {
+ this.redisSaveMaxTime = redisSaveMaxTime;
+ }
+
+ public List getSlbList() {
+ return slbList;
+ }
+
+ public void setSlbList(List slbList) {
+ this.slbList = slbList;
+ }
+
+ public int getTransactionNettyHeartTime() {
+ return transactionNettyHeartTime;
+ }
+
+ public void setTransactionNettyHeartTime(int transactionNettyHeartTime) {
+ this.transactionNettyHeartTime = transactionNettyHeartTime;
+ }
+
+ public int getTransactionNettyDelayTime() {
+ return transactionNettyDelayTime;
+ }
+
+ public void setTransactionNettyDelayTime(int transactionNettyDelayTime) {
+ this.transactionNettyDelayTime = transactionNettyDelayTime;
+ }
+
+ public String getNotifyUrl() {
+ return notifyUrl;
+ }
+
+ public void setNotifyUrl(String notifyUrl) {
+ this.notifyUrl = notifyUrl;
+ }
+
+ public int getCompensateMaxWaitTime() {
+ return compensateMaxWaitTime;
+ }
+
+ public void setCompensateMaxWaitTime(int compensateMaxWaitTime) {
+ this.compensateMaxWaitTime = compensateMaxWaitTime;
+ }
+
+
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/handler/TxCoreServerHandler.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/handler/TxCoreServerHandler.java
new file mode 100644
index 000000000..70116a5a9
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/handler/TxCoreServerHandler.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.netty.handler;
+
+/**
+ * Created by lorne on 2017/6/29.
+ */
+
+import com.alibaba.fastjson.JSONObject;
+import com.pig4cloud.pigx.manager.framework.utils.SocketManager;
+import com.pig4cloud.pigx.manager.framework.utils.SocketUtils;
+import com.pig4cloud.pigx.manager.manager.ModelInfoManager;
+import com.pig4cloud.pigx.manager.netty.service.IActionService;
+import com.pig4cloud.pigx.manager.netty.service.NettyService;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+import io.netty.handler.timeout.IdleState;
+import io.netty.handler.timeout.IdleStateEvent;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Handles a server-side channel.
+ */
+
+@ChannelHandler.Sharable
+public class TxCoreServerHandler extends ChannelInboundHandlerAdapter { // (1)
+
+ private NettyService nettyService;
+
+
+ private Logger logger = LoggerFactory.getLogger(TxCoreServerHandler.class);
+
+
+ private Executor threadPool;
+
+
+ public TxCoreServerHandler(Executor threadPool, NettyService nettyService) {
+ this.threadPool = threadPool;
+ this.nettyService = nettyService;
+ }
+
+ @Override
+ public void channelRead(final ChannelHandlerContext ctx, Object msg) throws Exception {
+ final String json = SocketUtils.getJson(msg);
+ logger.debug("request->" + json);
+ threadPool.execute(new Runnable() {
+ @Override
+ public void run() {
+ service(json, ctx);
+ }
+ });
+ }
+
+ private void service(String json, ChannelHandlerContext ctx) {
+ if (StringUtils.isNotEmpty(json)) {
+ JSONObject jsonObject = JSONObject.parseObject(json);
+ String action = jsonObject.getString("a");
+ String key = jsonObject.getString("k");
+ JSONObject params = JSONObject.parseObject(jsonObject.getString("p"));
+ String channelAddress = ctx.channel().remoteAddress().toString();
+
+ IActionService actionService = nettyService.getActionService(action);
+
+ String res = actionService.execute(channelAddress, key, params);
+
+ JSONObject resObj = new JSONObject();
+ resObj.put("k", key);
+ resObj.put("d", res);
+
+ SocketUtils.sendMsg(ctx, resObj.toString());
+
+ }
+ }
+
+ @Override
+ public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
+
+ //是否到达最大上线连接数
+ if (SocketManager.getInstance().isAllowConnection()) {
+ SocketManager.getInstance().addClient(ctx.channel());
+ } else {
+ ctx.close();
+ }
+ super.channelRegistered(ctx);
+ }
+
+ @Override
+ public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
+
+ SocketManager.getInstance().removeClient(ctx.channel());
+ String modelName = ctx.channel().remoteAddress().toString();
+ SocketManager.getInstance().outLine(modelName);
+
+ ModelInfoManager.getInstance().removeModelInfo(modelName);
+ super.channelUnregistered(ctx);
+ }
+
+ @Override
+ public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
+ ctx.flush();
+ }
+
+ @Override
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
+ cause.printStackTrace();
+ //ctx.close();
+ }
+
+ @Override
+ public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
+ //心跳配置
+ if (IdleStateEvent.class.isAssignableFrom(evt.getClass())) {
+ IdleStateEvent event = (IdleStateEvent) evt;
+ if (event.state() == IdleState.READER_IDLE) {
+ ctx.close();
+ }
+ }
+ }
+
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/model/TxGroup.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/model/TxGroup.java
new file mode 100644
index 000000000..739d963e7
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/model/TxGroup.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.netty.model;
+
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by lorne on 2017/6/7.
+ */
+public class TxGroup {
+
+ private String groupId;
+
+ private long startTime;
+
+ private long nowTime;
+
+ private int state;
+
+ private int hasOver;
+
+ /**
+ * 补偿请求
+ */
+ private int isCompensate;
+
+
+ /**
+ * 是否强制回滚(1:开启,0:关闭)
+ */
+ private int rollback = 0;
+
+ private List list;
+
+ public TxGroup() {
+ list = new ArrayList();
+ }
+
+ public static TxGroup parser(String json) {
+ try {
+ JSONObject jsonObject = JSONObject.parseObject(json);
+ TxGroup txGroup = new TxGroup();
+ txGroup.setGroupId(jsonObject.getString("g"));
+ txGroup.setStartTime(jsonObject.getLong("st"));
+ txGroup.setNowTime(jsonObject.getLong("nt"));
+ txGroup.setState(jsonObject.getInteger("s"));
+ txGroup.setIsCompensate(jsonObject.getInteger("i"));
+ txGroup.setRollback(jsonObject.getInteger("r"));
+ txGroup.setHasOver(jsonObject.getInteger("o"));
+ JSONArray array = jsonObject.getJSONArray("l");
+ int length = array.size();
+ for (int i = 0; i < length; i++) {
+ JSONObject object = array.getJSONObject(i);
+ TxInfo info = new TxInfo();
+ info.setKid(object.getString("k"));
+ info.setChannelAddress(object.getString("ca"));
+ info.setNotify(object.getInteger("n"));
+ info.setIsGroup(object.getInteger("ig"));
+ info.setAddress(object.getString("a"));
+ info.setUniqueKey(object.getString("u"));
+
+ info.setModel(object.getString("mn"));
+ info.setModelIpAddress(object.getString("ip"));
+ info.setMethodStr(object.getString("ms"));
+
+ txGroup.getList().add(info);
+ }
+ return txGroup;
+
+ } catch (Exception e) {
+ return null;
+ }
+
+ }
+
+ public String getGroupId() {
+ return groupId;
+ }
+
+ public void setGroupId(String groupId) {
+ this.groupId = groupId;
+ }
+
+ public List getList() {
+ return list;
+ }
+
+ public void setList(List list) {
+ this.list = list;
+ }
+
+ public long getStartTime() {
+ return startTime;
+ }
+
+ public void setStartTime(long startTime) {
+ this.startTime = startTime;
+ }
+
+ public int getIsCompensate() {
+ return isCompensate;
+ }
+
+ public void setIsCompensate(int isCompensate) {
+ this.isCompensate = isCompensate;
+ }
+
+ public int getState() {
+ return state;
+ }
+
+ public void setState(int state) {
+ this.state = state;
+ }
+
+ public void addTransactionInfo(TxInfo info) {
+ list.add(info);
+ }
+
+ public long getNowTime() {
+ return nowTime;
+ }
+
+ public void setNowTime(long nowTime) {
+ this.nowTime = nowTime;
+ }
+
+ public int getHasOver() {
+ return hasOver;
+ }
+
+ public void setHasOver(int hasOver) {
+ this.hasOver = hasOver;
+ }
+
+ public int getRollback() {
+ return rollback;
+ }
+
+ public void setRollback(int rollback) {
+ this.rollback = rollback;
+ }
+
+ public String toJsonString(boolean noList) {
+ JSONObject jsonObject = new JSONObject();
+ jsonObject.put("g", getGroupId());
+ jsonObject.put("st", getStartTime());
+ jsonObject.put("nt", getNowTime());
+ jsonObject.put("s", getState());
+ jsonObject.put("i", getIsCompensate());
+ jsonObject.put("r", getRollback());
+ jsonObject.put("o", getHasOver());
+ if (noList) {
+ JSONArray jsonArray = new JSONArray();
+ for (TxInfo info : getList()) {
+ JSONObject item = new JSONObject();
+ item.put("k", info.getKid());
+ item.put("ca", info.getChannelAddress());
+ item.put("n", info.getNotify());
+ item.put("ig", info.getIsGroup());
+ item.put("a", info.getAddress());
+ item.put("u", info.getUniqueKey());
+
+ item.put("mn", info.getModel());
+ item.put("ip", info.getModelIpAddress());
+ item.put("ms", info.getMethodStr());
+
+
+ jsonArray.add(item);
+ }
+ jsonObject.put("l", jsonArray);
+ }
+ return jsonObject.toString();
+ }
+
+ public String toJsonString() {
+ return toJsonString(true);
+ }
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/model/TxInfo.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/model/TxInfo.java
new file mode 100644
index 000000000..89bac0b06
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/model/TxInfo.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.netty.model;
+
+import com.alibaba.fastjson.JSONObject;
+import com.lorne.core.framework.model.JsonModel;
+import com.pig4cloud.pigx.manager.model.ChannelSender;
+
+/**
+ * Created by lorne on 2017/6/7.
+ */
+public class TxInfo extends JsonModel {
+
+ /**
+ * 任务唯一标示
+ */
+ private String kid;
+
+ /**
+ * 模块管道名称(netty管道名称)
+ */
+ private String channelAddress;
+
+ /**
+ * 是否通知成功
+ */
+ private int notify;
+
+ /**
+ * 0 不组合
+ * 1 组合
+ */
+ private int isGroup;
+
+ /**
+ * tm识别标示
+ */
+ private String address;
+
+ /**
+ * tx识别标示
+ */
+ private String uniqueKey;
+
+
+ /**
+ * 管道发送数据
+ */
+ private ChannelSender channel;
+
+
+ /**
+ * 业务方法名称
+ */
+ private String methodStr;
+
+ /**
+ * 模块名称
+ */
+ private String model;
+
+ /**
+ * 模块地址
+ */
+ private String modelIpAddress;
+
+ /**
+ * 是否提交(临时数据)
+ */
+ private int isCommit;
+
+ public int getIsCommit() {
+ return isCommit;
+ }
+
+ public void setIsCommit(int isCommit) {
+ this.isCommit = isCommit;
+ }
+
+ public String getMethodStr() {
+ return methodStr;
+ }
+
+ public void setMethodStr(String methodStr) {
+ this.methodStr = methodStr;
+ }
+
+ public String getModel() {
+ return model;
+ }
+
+ public void setModel(String model) {
+ this.model = model;
+ }
+
+ public String getModelIpAddress() {
+ return modelIpAddress;
+ }
+
+ public void setModelIpAddress(String modelIpAddress) {
+ this.modelIpAddress = modelIpAddress;
+ }
+
+ public String getKid() {
+ return kid;
+ }
+
+ public void setKid(String kid) {
+ this.kid = kid;
+ }
+
+ public ChannelSender getChannel() {
+ return channel;
+ }
+
+ public void setChannel(ChannelSender channel) {
+ this.channel = channel;
+ }
+
+ public String getChannelAddress() {
+ return channelAddress;
+ }
+
+ public void setChannelAddress(String channelAddress) {
+ this.channelAddress = channelAddress;
+ }
+
+ public int getNotify() {
+ return notify;
+ }
+
+ public void setNotify(int notify) {
+ this.notify = notify;
+ }
+
+ public int getIsGroup() {
+ return isGroup;
+ }
+
+ public void setIsGroup(int isGroup) {
+ this.isGroup = isGroup;
+ }
+
+ public String getAddress() {
+ return address;
+ }
+
+ public void setAddress(String address) {
+ this.address = address;
+ }
+
+ public String getUniqueKey() {
+ return uniqueKey;
+ }
+
+ public void setUniqueKey(String uniqueKey) {
+ this.uniqueKey = uniqueKey;
+ }
+
+ @Override
+ public String toString() {
+ JSONObject jsonObject = new JSONObject();
+ jsonObject.put("kid", getKid());
+ jsonObject.put("channelAddress", getChannelAddress());
+ jsonObject.put("notify", getNotify());
+ jsonObject.put("isGroup", getIsGroup());
+ jsonObject.put("address", getAddress());
+ jsonObject.put("uniqueKey", getUniqueKey());
+
+ jsonObject.put("model", getModel());
+ jsonObject.put("modelIpAddress", getModelIpAddress());
+ jsonObject.put("methodStr", getMethodStr());
+
+ return jsonObject.toString();
+ }
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/IActionService.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/IActionService.java
new file mode 100644
index 000000000..d8ab1b191
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/IActionService.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.netty.service;
+
+import com.alibaba.fastjson.JSONObject;
+
+/**
+ * create by lorne on 2017/11/11
+ */
+public interface IActionService {
+
+
+ String execute(String channelAddress, String key, JSONObject params);
+
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/NettyServerService.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/NettyServerService.java
new file mode 100644
index 000000000..92c5f183a
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/NettyServerService.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.netty.service;
+
+/**
+ * Created by lorne on 2017/6/30.
+ */
+public interface NettyServerService {
+
+ void start();
+
+ void close();
+
+
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/NettyService.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/NettyService.java
new file mode 100644
index 000000000..4d7f774ae
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/NettyService.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.netty.service;
+
+/**
+ * create by lorne on 2017/11/11
+ */
+public interface NettyService {
+
+
+ IActionService getActionService(String action);
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/ActionATGServiceImpl.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/ActionATGServiceImpl.java
new file mode 100644
index 000000000..6347e9df9
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/ActionATGServiceImpl.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.netty.service.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.pig4cloud.pigx.manager.manager.service.TxManagerService;
+import com.pig4cloud.pigx.manager.netty.model.TxGroup;
+import com.pig4cloud.pigx.manager.netty.service.IActionService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * 添加事务组
+ * create by lorne on 2017/11/11
+ */
+@Service(value = "atg")
+public class ActionATGServiceImpl implements IActionService {
+
+
+ @Autowired
+ private TxManagerService txManagerService;
+
+ @Override
+ public String execute(String channelAddress, String key, JSONObject params) {
+ String res = "";
+ String groupId = params.getString("g");
+ String taskId = params.getString("t");
+ String methodStr = params.getString("ms");
+ int isGroup = params.getInteger("s");
+
+ TxGroup txGroup = txManagerService.addTransactionGroup(groupId, taskId, isGroup, channelAddress, methodStr);
+
+ if (txGroup != null) {
+ txGroup.setNowTime(System.currentTimeMillis());
+ res = txGroup.toJsonString(false);
+ } else {
+ res = "";
+ }
+ return res;
+ }
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/ActionCGServiceImpl.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/ActionCGServiceImpl.java
new file mode 100644
index 000000000..e3e61a5c3
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/ActionCGServiceImpl.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.netty.service.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.pig4cloud.pigx.manager.manager.service.TxManagerService;
+import com.pig4cloud.pigx.manager.netty.model.TxGroup;
+import com.pig4cloud.pigx.manager.netty.service.IActionService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * 创建事务组
+ * create by lorne on 2017/11/11
+ */
+@Service(value = "cg")
+public class ActionCGServiceImpl implements IActionService {
+
+
+ @Autowired
+ private TxManagerService txManagerService;
+
+ @Override
+ public String execute(String channelAddress, String key, JSONObject params) {
+ String res = "";
+ String groupId = params.getString("g");
+ TxGroup txGroup = txManagerService.createTransactionGroup(groupId);
+ if (txGroup != null) {
+ txGroup.setNowTime(System.currentTimeMillis());
+ res = txGroup.toJsonString(false);
+ } else {
+ res = "";
+ }
+ return res;
+ }
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/ActionCKGServiceImpl.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/ActionCKGServiceImpl.java
new file mode 100644
index 000000000..1aebad576
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/ActionCKGServiceImpl.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.netty.service.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.pig4cloud.pigx.manager.manager.service.TxManagerService;
+import com.pig4cloud.pigx.manager.netty.service.IActionService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * 检查事务组
+ * create by lorne on 2017/11/11
+ */
+@Service(value = "ckg")
+public class ActionCKGServiceImpl implements IActionService {
+
+
+ @Autowired
+ private TxManagerService txManagerService;
+
+ @Override
+ public String execute(String channelAddress, String key, JSONObject params) {
+ String res = "";
+ String groupId = params.getString("g");
+ String taskId = params.getString("t");
+ int bs = txManagerService.cleanNotifyTransaction(groupId, taskId);
+
+ res = String.valueOf(bs);
+ return res;
+ }
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/ActionCServiceImpl.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/ActionCServiceImpl.java
new file mode 100644
index 000000000..1609e251c
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/ActionCServiceImpl.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.netty.service.impl;
+
+import com.pig4cloud.pigx.manager.netty.service.IActionService;
+import org.springframework.stereotype.Service;
+
+/**
+ * 补偿回调
+ * create by lorne on 2017/11/11
+ */
+@Service(value = "c")
+public class ActionCServiceImpl extends BaseSignalTaskService implements IActionService {
+
+
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/ActionCTGServiceImpl.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/ActionCTGServiceImpl.java
new file mode 100644
index 000000000..3d2a92b45
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/ActionCTGServiceImpl.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.netty.service.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.pig4cloud.pigx.manager.manager.service.TxManagerService;
+import com.pig4cloud.pigx.manager.netty.service.IActionService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * 关闭事务组
+ * create by lorne on 2017/11/11
+ */
+@Service(value = "ctg")
+public class ActionCTGServiceImpl implements IActionService {
+
+
+ @Autowired
+ private TxManagerService txManagerService;
+
+ @Override
+ public String execute(String channelAddress, String key, JSONObject params) {
+ String groupId = params.getString("g");
+ int state = params.getInteger("s");
+ String res = String.valueOf(txManagerService.closeTransactionGroup(groupId, state));
+ return res;
+ }
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/ActionGLBServiceImpl.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/ActionGLBServiceImpl.java
new file mode 100644
index 000000000..9f76e028b
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/ActionGLBServiceImpl.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.netty.service.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.pig4cloud.pigx.manager.manager.service.LoadBalanceService;
+import com.pig4cloud.pigx.manager.model.LoadBalanceInfo;
+import com.pig4cloud.pigx.manager.netty.service.IActionService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * 获取负载模块信息
+ * create by lorne on 2017/11/11
+ */
+@Service(value = "glb")
+public class ActionGLBServiceImpl implements IActionService {
+
+
+ @Autowired
+ private LoadBalanceService loadBalanceService;
+
+
+ @Override
+ public String execute(String channelAddress, String key, JSONObject params) {
+ String res;
+ String groupId = params.getString("g");
+ String k = params.getString("k");
+
+ LoadBalanceInfo loadBalanceInfo = loadBalanceService.get(groupId, k);
+ if (loadBalanceInfo == null) {
+ res = "";
+ } else {
+ res = loadBalanceInfo.getData();
+ }
+ return res;
+ }
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/ActionHServiceImpl.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/ActionHServiceImpl.java
new file mode 100644
index 000000000..f95ea832e
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/ActionHServiceImpl.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.netty.service.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.pig4cloud.pigx.manager.config.ConfigReader;
+import com.pig4cloud.pigx.manager.netty.service.IActionService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * 心跳包
+ * create by lorne on 2017/11/11
+ */
+@Service(value = "h")
+public class ActionHServiceImpl implements IActionService {
+
+
+ @Autowired
+ private ConfigReader configReader;
+
+ @Override
+ public String execute(String channelAddress, String key, JSONObject params) {
+ return String.valueOf(configReader.getTransactionNettyDelayTime());
+ }
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/ActionPLBServiceImpl.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/ActionPLBServiceImpl.java
new file mode 100644
index 000000000..b66052876
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/ActionPLBServiceImpl.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.netty.service.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.pig4cloud.pigx.manager.manager.service.LoadBalanceService;
+import com.pig4cloud.pigx.manager.model.LoadBalanceInfo;
+import com.pig4cloud.pigx.manager.netty.service.IActionService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * 添加负载模块信息
+ * create by lorne on 2017/11/11
+ */
+@Service(value = "plb")
+public class ActionPLBServiceImpl implements IActionService {
+
+
+ @Autowired
+ private LoadBalanceService loadBalanceService;
+
+
+ @Override
+ public String execute(String channelAddress, String key, JSONObject params) {
+
+ String groupId = params.getString("g");
+ String k = params.getString("k");
+ String data = params.getString("d");
+
+ LoadBalanceInfo loadBalanceInfo = new LoadBalanceInfo();
+ loadBalanceInfo.setData(data);
+ loadBalanceInfo.setKey(k);
+ loadBalanceInfo.setGroupId(groupId);
+ boolean ok = loadBalanceService.put(loadBalanceInfo);
+
+ return ok ? "1" : "0";
+ }
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/ActionRGServiceImpl.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/ActionRGServiceImpl.java
new file mode 100644
index 000000000..5b9f394e1
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/ActionRGServiceImpl.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.netty.service.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.pig4cloud.pigx.manager.manager.service.TxManagerService;
+import com.pig4cloud.pigx.manager.netty.service.IActionService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * 强制回滚事务组
+ * create by lorne on 2017/11/11
+ */
+@Service(value = "rg")
+public class ActionRGServiceImpl implements IActionService {
+
+
+ @Autowired
+ private TxManagerService txManagerService;
+
+ @Override
+ public String execute(String channelAddress, String key, JSONObject params) {
+ String res = "";
+ String groupId = params.getString("g");
+ boolean bs = txManagerService.rollbackTransactionGroup(groupId);
+ res = bs ? "1" : "0";
+ return res;
+ }
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/ActionTServiceImpl.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/ActionTServiceImpl.java
new file mode 100644
index 000000000..c0da6b732
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/ActionTServiceImpl.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.netty.service.impl;
+
+import com.pig4cloud.pigx.manager.netty.service.IActionService;
+import org.springframework.stereotype.Service;
+
+/**
+ * 通知事务回调
+ * create by lorne on 2017/11/11
+ */
+@Service(value = "t")
+public class ActionTServiceImpl extends BaseSignalTaskService implements IActionService {
+
+
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/ActionUMIServiceImpl.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/ActionUMIServiceImpl.java
new file mode 100644
index 000000000..94a36c667
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/ActionUMIServiceImpl.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.netty.service.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.pig4cloud.pigx.manager.framework.utils.SocketManager;
+import com.pig4cloud.pigx.manager.manager.ModelInfoManager;
+import com.pig4cloud.pigx.manager.model.ModelInfo;
+import com.pig4cloud.pigx.manager.netty.service.IActionService;
+import org.springframework.stereotype.Service;
+
+/**
+ * 上传模块信息
+ * create by lorne on 2017/11/11
+ */
+@Service(value = "umi")
+public class ActionUMIServiceImpl implements IActionService {
+
+
+ @Override
+ public String execute(String channelAddress, String key, JSONObject params) {
+ String res = "1";
+
+ String uniqueKey = params.getString("u");
+ String ipAddress = params.getString("i");
+ String model = params.getString("m");
+
+
+ ModelInfo modelInfo = new ModelInfo();
+ modelInfo.setChannelName(channelAddress);
+ modelInfo.setIpAddress(ipAddress);
+ modelInfo.setModel(model);
+ modelInfo.setUniqueKey(uniqueKey);
+
+ ModelInfoManager.getInstance().addModelInfo(modelInfo);
+
+ SocketManager.getInstance().onLine(channelAddress, uniqueKey);
+
+ return res;
+ }
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/BaseSignalTaskService.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/BaseSignalTaskService.java
new file mode 100644
index 000000000..166f129e9
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/BaseSignalTaskService.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.netty.service.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.lorne.core.framework.utils.task.ConditionUtils;
+import com.lorne.core.framework.utils.task.IBack;
+import com.lorne.core.framework.utils.task.Task;
+
+/**
+ * create by lorne on 2017/11/13
+ */
+public class BaseSignalTaskService {
+
+ public String execute(String channelAddress, String key, JSONObject params) {
+ String res = "";
+ final String data = params.getString("d");
+ Task task = ConditionUtils.getInstance().getTask(key);
+ if (task != null) {
+ task.setBack(new IBack() {
+ @Override
+ public Object doing(Object... objs) throws Throwable {
+ return data;
+ }
+ });
+ task.signalTask();
+ }
+ return res;
+ }
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/NettyServerServiceImpl.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/NettyServerServiceImpl.java
new file mode 100644
index 000000000..a579139e3
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/NettyServerServiceImpl.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.netty.service.impl;
+
+import com.pig4cloud.pigx.manager.config.ConfigReader;
+import com.pig4cloud.pigx.manager.framework.utils.Constants;
+import com.pig4cloud.pigx.manager.netty.handler.TxCoreServerHandler;
+import com.pig4cloud.pigx.manager.netty.service.NettyServerService;
+import com.pig4cloud.pigx.manager.netty.service.NettyService;
+import io.netty.bootstrap.ServerBootstrap;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelOption;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioServerSocketChannel;
+import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
+import io.netty.handler.codec.LengthFieldPrepender;
+import io.netty.handler.logging.LogLevel;
+import io.netty.handler.logging.LoggingHandler;
+import io.netty.handler.timeout.IdleStateHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Created by lorne on 2017/6/30.
+ */
+@Service
+public class NettyServerServiceImpl implements NettyServerService, DisposableBean {
+
+
+ @Autowired
+ private NettyService nettyService;
+
+ private Logger logger = LoggerFactory.getLogger(NettyServerServiceImpl.class);
+
+ private EventLoopGroup bossGroup;
+ private EventLoopGroup workerGroup;
+
+ private TxCoreServerHandler txCoreServerHandler;
+
+ private ExecutorService threadPool = Executors.newFixedThreadPool(100);
+
+ @Autowired
+ private ConfigReader configReader;
+
+
+ @Override
+ public void start() {
+ final int heartTime = configReader.getTransactionNettyHeartTime() + 10;
+ txCoreServerHandler = new TxCoreServerHandler(threadPool, nettyService);
+ bossGroup = new NioEventLoopGroup(50); // (1)
+ workerGroup = new NioEventLoopGroup();
+ try {
+ ServerBootstrap b = new ServerBootstrap();
+ b.group(bossGroup, workerGroup)
+ .channel(NioServerSocketChannel.class)
+ .option(ChannelOption.SO_BACKLOG, 100)
+ .handler(new LoggingHandler(LogLevel.INFO))
+ .childHandler(new ChannelInitializer() {
+ @Override
+ public void initChannel(SocketChannel ch) throws Exception {
+ ch.pipeline().addLast("timeout", new IdleStateHandler(heartTime, heartTime, heartTime, TimeUnit.SECONDS));
+
+ ch.pipeline().addLast(new LengthFieldPrepender(4, false));
+ ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
+
+ ch.pipeline().addLast(txCoreServerHandler);
+ }
+ });
+
+ // Start the server.
+ b.bind(Constants.socketPort);
+ logger.info("Socket started on port(s): " + Constants.socketPort + " (socket)");
+
+ } catch (Exception e) {
+ // Shut down all event loops to terminate all threads.
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void close() {
+ if (workerGroup != null) {
+ workerGroup.shutdownGracefully();
+ }
+ if (bossGroup != null) {
+ bossGroup.shutdownGracefully();
+ }
+
+ }
+
+ @Override
+ public void destroy() throws Exception {
+ close();
+ threadPool.shutdown();
+ }
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/NettyServiceImpl.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/NettyServiceImpl.java
new file mode 100644
index 000000000..a5359757c
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/netty/service/impl/NettyServiceImpl.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.netty.service.impl;
+
+import com.pig4cloud.pigx.manager.netty.service.IActionService;
+import com.pig4cloud.pigx.manager.netty.service.NettyService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.stereotype.Service;
+
+/**
+ * create by lorne on 2017/11/11
+ */
+@Service
+public class NettyServiceImpl implements NettyService {
+
+ @Autowired
+ private ApplicationContext spring;
+
+ @Override
+ public IActionService getActionService(String action) {
+ return spring.getBean(action, IActionService.class);
+ }
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/pack-info.md b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/pack-info.md
new file mode 100644
index 000000000..ebee96376
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/pack-info.md
@@ -0,0 +1,6 @@
+由于LCN 暂未发布适配 2.0 版本
+当前包是根据TCN tx-manager 模块修改而来 ,重构部分代码
+解决LCN 不兼容 Spring Cloud Finchley 问题
+
+关于LCN
+https://github.com/codingapi/tx-lcn
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/redis/RedisServerService.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/redis/RedisServerService.java
new file mode 100644
index 000000000..ce12a030c
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/redis/RedisServerService.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.redis;
+
+
+import com.pig4cloud.pigx.manager.netty.model.TxGroup;
+
+import java.util.List;
+
+/**
+ * create by lorne on 2017/11/11
+ */
+public interface RedisServerService {
+
+ String loadNotifyJson();
+
+ void saveTransaction(String key, String json);
+
+ TxGroup getTxGroupByKey(String key);
+
+ void saveCompensateMsg(String name, String json);
+
+ List getKeys(String key);
+
+ List getValuesByKeys(List keys);
+
+ String getValueByKey(String key);
+
+ void deleteKey(String key);
+
+ void saveLoadBalance(String groupName, String key, String data);
+
+
+ String getLoadBalance(String groupName, String key);
+
+
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/redis/impl/RedisServerServiceImpl.java b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/redis/impl/RedisServerServiceImpl.java
new file mode 100644
index 000000000..8621a08d4
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/java/com/pig4cloud/pigx/manager/redis/impl/RedisServerServiceImpl.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.manager.redis.impl;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.pig4cloud.pigx.manager.config.ConfigReader;
+import com.pig4cloud.pigx.manager.netty.model.TxGroup;
+import com.pig4cloud.pigx.manager.redis.RedisServerService;
+import org.apache.commons.lang.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.HashOperations;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.ValueOperations;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * create by lorne on 2017/11/11
+ */
+@Service
+public class RedisServerServiceImpl implements RedisServerService {
+
+ @Autowired
+ private RedisTemplate redisTemplate;
+
+ @Autowired
+ private ConfigReader configReader;
+
+ @Override
+ public String loadNotifyJson() {
+ Set keys = redisTemplate.keys(configReader.getKeyPrefixCompensate() + "*");
+ ValueOperations value = redisTemplate.opsForValue();
+ JSONArray jsonArray = new JSONArray();
+ for (String key : keys) {
+ String json = value.get(key);
+ JSONObject jsonObject = new JSONObject();
+ jsonObject.put("key", key);
+ jsonObject.put("value", JSONObject.parse(json));
+ jsonArray.add(jsonObject);
+ }
+ return jsonArray.toJSONString();
+ }
+
+ @Override
+ public void saveTransaction(String key, String json) {
+ ValueOperations value = redisTemplate.opsForValue();
+ value.set(key, json, configReader.getRedisSaveMaxTime(), TimeUnit.SECONDS);
+ }
+
+
+ @Override
+ public TxGroup getTxGroupByKey(String key) {
+ ValueOperations value = redisTemplate.opsForValue();
+ String json = value.get(key);
+ if (StringUtils.isEmpty(json)) {
+ return null;
+ }
+ return TxGroup.parser(json);
+ }
+
+
+ @Override
+ public void saveCompensateMsg(String name, String json) {
+ ValueOperations value = redisTemplate.opsForValue();
+ value.set(name, json);
+ }
+
+ @Override
+ public List getKeys(String key) {
+ Set keys = redisTemplate.keys(key);
+ List list = new ArrayList();
+ for (String k : keys) {
+ list.add(k);
+ }
+ return list;
+ }
+
+ @Override
+ public List getValuesByKeys(List keys) {
+ ValueOperations value = redisTemplate.opsForValue();
+ List list = new ArrayList<>();
+ for (String key : keys) {
+ String json = value.get(key);
+ list.add(json);
+ }
+ return list;
+ }
+
+ @Override
+ public String getValueByKey(String key) {
+ ValueOperations value = redisTemplate.opsForValue();
+ return value.get(key);
+ }
+
+ @Override
+ public void deleteKey(String key) {
+ redisTemplate.delete(key);
+ }
+
+ @Override
+ public void saveLoadBalance(String groupName, String key, String data) {
+ HashOperations value = redisTemplate.opsForHash();
+ value.put(groupName, key, data);
+ }
+
+
+ @Override
+ public String getLoadBalance(String groupName, String key) {
+ HashOperations value = redisTemplate.opsForHash();
+ return value.get(groupName, key);
+ }
+}
diff --git a/pigx-visual/pigx-tx-manager/src/main/resources/bootstrap.yml b/pigx-visual/pigx-tx-manager/src/main/resources/bootstrap.yml
new file mode 100644
index 000000000..15135a9d3
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/resources/bootstrap.yml
@@ -0,0 +1,24 @@
+server:
+ port: 7000
+
+spring:
+ application:
+ name: pigx-tx-manager
+ #配置中心
+ cloud:
+ config:
+ fail-fast: true
+ name: ${spring.application.name}
+ profile: dev
+ discovery:
+ enabled: true
+ service-id: pigx-config
+
+# 注册中心配置
+eureka:
+ instance:
+ prefer-ip-address: true
+ client:
+ service-url:
+ defaultZone: http://pig:pig@localhost:1025/eureka/
+
diff --git a/pigx-visual/pigx-tx-manager/src/main/resources/static/index.html b/pigx-visual/pigx-tx-manager/src/main/resources/static/index.html
new file mode 100644
index 000000000..2395aeb90
--- /dev/null
+++ b/pigx-visual/pigx-tx-manager/src/main/resources/static/index.html
@@ -0,0 +1,139 @@
+
+
+
+
+ TxManager v4.1.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 补偿详细说明:
+ 模块唯一标示:是由模块的ip+port然后md5加密得来,用于LCN系统的模块唯一识别码
+ 事务ID:事务组信息的唯一标示
+ 模块名称列表说明,该记录的数据未必是模块的完整调用曲线数据,没有事务的业务模块是不记录数据的。
+ 例如:参与模块 a b c d ,若a模块是发起方,执行顺序是a->b->c->d,若b事务是只读的,c没有事务,仅有d模块有事务。那么实际记录的模块数据仅会记录d模块的数据。
+