diff --git a/README.md b/README.md
index 013bdf2a..604cb5e1 100644
--- a/README.md
+++ b/README.md
@@ -99,7 +99,7 @@ The path to the target file:
``` xml
-nacos-sync/nacossync-distribution/target/nacos-sync-0.4.8.tar.gz
+nacos-sync/nacossync-distribution/target/nacos-sync-0.5.0.tar.gz
```
@@ -157,4 +157,16 @@ sh startup.sh start
http://127.0.0.1:8083/#/serviceSync
-```
\ No newline at end of file
+```
+
+## Advanced Configuration
+
+### Full Synchronization from Zookeeper to Nacos (Dubbo)
+When “*” is entered in the “Service Name” field of this form, it will fully synchronize all services from Zookeeper to Nacos, but only when using Dubbo.
+
+
+### Full Synchronization from Nacos to Nacos
+When “All” is entered in the “Service Name” field of this form, it will automatically synchronize all registered services within the **default group** of the current cluster.
+
+This description explains the functionality clearly for English-speaking users.
+
\ No newline at end of file
diff --git a/img_1.png b/img_1.png
new file mode 100644
index 00000000..eee07444
Binary files /dev/null and b/img_1.png differ
diff --git a/img_2.png b/img_2.png
new file mode 100644
index 00000000..50dcc2cd
Binary files /dev/null and b/img_2.png differ
diff --git a/nacossync-worker/pom.xml b/nacossync-worker/pom.xml
index 2a553059..96a8cadf 100644
--- a/nacossync-worker/pom.xml
+++ b/nacossync-worker/pom.xml
@@ -59,17 +59,12 @@
- mysql
- mysql-connector-java
+ com.mysql
+ mysql-connector-j
-
- io.springfox
- springfox-swagger2
-
-
- io.springfox
- springfox-swagger-ui
+ org.springdoc
+ springdoc-openapi-ui
org.springframework.boot
@@ -169,8 +164,8 @@
org.apache.maven.plugins
maven-compiler-plugin
- 9
- 9
+ 11
+ 11
diff --git a/nacossync-worker/src/main/java/com/alibaba/nacossync/NacosSyncMain.java b/nacossync-worker/src/main/java/com/alibaba/nacossync/NacosSyncMain.java
index 19e44a14..b2ea8c8a 100644
--- a/nacossync-worker/src/main/java/com/alibaba/nacossync/NacosSyncMain.java
+++ b/nacossync-worker/src/main/java/com/alibaba/nacossync/NacosSyncMain.java
@@ -19,15 +19,12 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
-
import org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration;
-import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
* @author NacosSync
* @version $Id: SkyWalkerMain.java, v 0.1 2018-09-24 PM12:42 NacosSync Exp $$
*/
-@EnableSwagger2
@SpringBootApplication(exclude = EurekaClientAutoConfiguration.class)
public class NacosSyncMain {
diff --git a/nacossync-worker/src/main/java/com/alibaba/nacossync/cache/SkyWalkerCacheServices.java b/nacossync-worker/src/main/java/com/alibaba/nacossync/cache/SkyWalkerCacheServices.java
index 7f4a40fd..b515bf74 100644
--- a/nacossync-worker/src/main/java/com/alibaba/nacossync/cache/SkyWalkerCacheServices.java
+++ b/nacossync-worker/src/main/java/com/alibaba/nacossync/cache/SkyWalkerCacheServices.java
@@ -25,16 +25,17 @@
import com.alibaba.nacossync.pojo.model.TaskDO;
import com.alibaba.nacossync.util.SkyWalkerUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ThreadLocalRandom;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ThreadLocalRandom;
+
/**
* @author NacosSync
* @version $Id: SkyWalkerCacheServices.java, v 0.1 2018-09-27 AM2:47 NacosSync Exp $$
@@ -48,7 +49,7 @@ public class SkyWalkerCacheServices {
@Autowired
private ObjectMapper objectMapper;
- private static Map finishedTaskMap = new ConcurrentHashMap<>();
+ private static final Map finishedTaskMap = new ConcurrentHashMap<>();
public String getClusterConnectKey(String clusterId) {
List allClusterConnectKey = getAllClusterConnectKey(clusterId);
@@ -90,7 +91,7 @@ public FinishedTask getFinishedTask(TaskDO taskDO) {
String operationId = SkyWalkerUtil.getOperationId(taskDO);
- if (StringUtils.isEmpty(operationId)) {
+ if (StringUtils.hasLength(operationId)) {
return null;
}
@@ -98,14 +99,14 @@ public FinishedTask getFinishedTask(TaskDO taskDO) {
}
public FinishedTask getFinishedTask(String operationId) {
- if (StringUtils.isEmpty(operationId)) {
+ if (StringUtils.hasLength(operationId)) {
return null;
}
return finishedTaskMap.get(operationId);
}
public FinishedTask removeFinishedTask(String operationId) {
- if (StringUtils.isEmpty(operationId)) {
+ if (StringUtils.hasLength(operationId)) {
return null;
}
return finishedTaskMap.remove(operationId);
diff --git a/nacossync-worker/src/main/java/com/alibaba/nacossync/constant/SkyWalkerConstants.java b/nacossync-worker/src/main/java/com/alibaba/nacossync/constant/SkyWalkerConstants.java
index 0379e73e..6b85af87 100644
--- a/nacossync-worker/src/main/java/com/alibaba/nacossync/constant/SkyWalkerConstants.java
+++ b/nacossync-worker/src/main/java/com/alibaba/nacossync/constant/SkyWalkerConstants.java
@@ -36,6 +36,6 @@ public class SkyWalkerConstants {
public static final String PAGE_NO="pageNo";
public static final String PAGE_SIZE="pageSize";
public static final String SYNC_INSTANCE_TAG="sync.instance.tag";
- public static final Integer MAX_THREAD_NUM = 200;
+ public static final String NACOS_ALL_SERVICE_NAME = "ALL";
}
diff --git a/nacossync-worker/src/main/java/com/alibaba/nacossync/dao/TaskAccessService.java b/nacossync-worker/src/main/java/com/alibaba/nacossync/dao/TaskAccessService.java
index 649eaf41..8dc3d5e6 100644
--- a/nacossync-worker/src/main/java/com/alibaba/nacossync/dao/TaskAccessService.java
+++ b/nacossync-worker/src/main/java/com/alibaba/nacossync/dao/TaskAccessService.java
@@ -16,6 +16,7 @@
*/
package com.alibaba.nacossync.dao;
+import com.alibaba.nacossync.constant.SkyWalkerConstants;
import com.alibaba.nacossync.pojo.QueryCondition;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
@@ -60,7 +61,7 @@ public void deleteTaskById(String taskId) {
*/
public void deleteTaskInBatch(List taskIds) {
List tds=taskRepository.findAllByTaskIdIn(taskIds);
- taskRepository.deleteInBatch(tds);
+ taskRepository.deleteAllInBatch(tds);
}
public Iterable findAll() {
@@ -115,8 +116,12 @@ private Page getTaskDOS(QueryCondition queryCondition, Pageable pageable
}, pageable);
}
- public List findServiceNameIsNull() {
- return taskRepository.findAllByServiceNameEquals("ALL");
+ public List findAllByServiceNameEqualAll() {
+ return taskRepository.findAllByServiceNameEqualsIgnoreCase(SkyWalkerConstants.NACOS_ALL_SERVICE_NAME);
+ }
+
+ public List findAllByServiceNameNotEqualAll() {
+ return taskRepository.findAllByServiceNameNotIgnoreCase(SkyWalkerConstants.NACOS_ALL_SERVICE_NAME);
}
}
diff --git a/nacossync-worker/src/main/java/com/alibaba/nacossync/dao/repository/TaskRepository.java b/nacossync-worker/src/main/java/com/alibaba/nacossync/dao/repository/TaskRepository.java
index fed44c45..2b40a8ce 100644
--- a/nacossync-worker/src/main/java/com/alibaba/nacossync/dao/repository/TaskRepository.java
+++ b/nacossync-worker/src/main/java/com/alibaba/nacossync/dao/repository/TaskRepository.java
@@ -16,15 +16,13 @@
*/
package com.alibaba.nacossync.dao.repository;
-import java.util.List;
-
-import javax.transaction.Transactional;
-
+import com.alibaba.nacossync.pojo.model.TaskDO;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.CrudRepository;
-import com.alibaba.nacossync.pojo.model.TaskDO;
+import javax.transaction.Transactional;
+import java.util.List;
/**
* @author NacosSync
@@ -47,6 +45,7 @@ public interface TaskRepository extends CrudRepository, JpaRepo
* @param serviceName
* @return
*/
- List findAllByServiceNameEquals(String serviceName);
+ List findAllByServiceNameEqualsIgnoreCase(String serviceName);
+ List findAllByServiceNameNotIgnoreCase(String serviceName);
}
diff --git a/nacossync-worker/src/main/java/com/alibaba/nacossync/event/DeleteAllSubTaskEvent.java b/nacossync-worker/src/main/java/com/alibaba/nacossync/event/DeleteAllSubTaskEvent.java
new file mode 100644
index 00000000..05b2eba4
--- /dev/null
+++ b/nacossync-worker/src/main/java/com/alibaba/nacossync/event/DeleteAllSubTaskEvent.java
@@ -0,0 +1,13 @@
+package com.alibaba.nacossync.event;
+
+import com.alibaba.nacossync.pojo.model.TaskDO;
+import lombok.Data;
+
+@Data
+public class DeleteAllSubTaskEvent {
+ public DeleteAllSubTaskEvent(TaskDO taskDO) {
+ this.taskDO = taskDO;
+ }
+
+ private final TaskDO taskDO;
+}
diff --git a/nacossync-worker/src/main/java/com/alibaba/nacossync/event/listener/EventListener.java b/nacossync-worker/src/main/java/com/alibaba/nacossync/event/listener/EventListener.java
index 40b3c12a..c15ff5f9 100644
--- a/nacossync-worker/src/main/java/com/alibaba/nacossync/event/listener/EventListener.java
+++ b/nacossync-worker/src/main/java/com/alibaba/nacossync/event/listener/EventListener.java
@@ -16,21 +16,19 @@
*/
package com.alibaba.nacossync.event.listener;
-import javax.annotation.PostConstruct;
-
-import com.alibaba.nacossync.constant.MetricsStatisticsType;
-import com.alibaba.nacossync.monitor.MetricsManager;
-import lombok.extern.slf4j.Slf4j;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
import com.alibaba.nacossync.cache.SkyWalkerCacheServices;
+import com.alibaba.nacossync.constant.MetricsStatisticsType;
import com.alibaba.nacossync.event.DeleteTaskEvent;
import com.alibaba.nacossync.event.SyncTaskEvent;
import com.alibaba.nacossync.extension.SyncManagerService;
+import com.alibaba.nacossync.monitor.MetricsManager;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
/**
* @author NacosSync
@@ -80,7 +78,7 @@ public void listenerDeleteTaskEvent(DeleteTaskEvent deleteTaskEvent) {
try {
long start = System.currentTimeMillis();
if (syncManagerService.delete(deleteTaskEvent.getTaskDO())) {
- skyWalkerCacheServices.addFinishedTask(deleteTaskEvent.getTaskDO());
+ skyWalkerCacheServices.removeFinishedTask(deleteTaskEvent.getTaskDO().getOperationId());
metricsManager.record(MetricsStatisticsType.DELETE_TASK_RT, System.currentTimeMillis() - start);
} else {
log.warn("listenerDeleteTaskEvent delete failure");
diff --git a/nacossync-worker/src/main/java/com/alibaba/nacossync/extension/SyncManagerService.java b/nacossync-worker/src/main/java/com/alibaba/nacossync/extension/SyncManagerService.java
index 252ee6e9..2fd33d18 100644
--- a/nacossync-worker/src/main/java/com/alibaba/nacossync/extension/SyncManagerService.java
+++ b/nacossync-worker/src/main/java/com/alibaba/nacossync/extension/SyncManagerService.java
@@ -12,14 +12,12 @@
*/
package com.alibaba.nacossync.extension;
-import static com.alibaba.nacossync.util.SkyWalkerUtil.generateSyncKey;
-
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacossync.cache.SkyWalkerCacheServices;
import com.alibaba.nacossync.constant.ClusterTypeEnum;
import com.alibaba.nacossync.extension.annotation.NacosSyncService;
import com.alibaba.nacossync.pojo.model.TaskDO;
-import java.util.concurrent.ConcurrentHashMap;
+import com.alibaba.nacossync.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
@@ -27,6 +25,10 @@
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static com.alibaba.nacossync.util.SkyWalkerUtil.generateSyncKey;
+
/**
* @author NacosSync
* @version $Id: SyncManagerService.java, v 0.1 2018-09-25 PM5:17 NacosSync Exp $$
@@ -60,11 +62,11 @@ public boolean sync(TaskDO taskDO, Integer index) {
@Override
public void afterPropertiesSet() {
- this.applicationContext.getBeansOfType(SyncService.class).forEach((key, value) -> {
+ this.applicationContext.getBeansWithAnnotation(NacosSyncService.class).forEach((key, value) -> {
NacosSyncService nacosSyncService = value.getClass().getAnnotation(NacosSyncService.class);
ClusterTypeEnum sourceCluster = nacosSyncService.sourceCluster();
ClusterTypeEnum destinationCluster = nacosSyncService.destinationCluster();
- syncServiceMap.put(generateSyncKey(sourceCluster, destinationCluster), value);
+ syncServiceMap.put(generateSyncKey(sourceCluster, destinationCluster), (SyncService) value);
});
}
@@ -74,7 +76,9 @@ public void setApplicationContext(ApplicationContext applicationContext) throws
}
public SyncService getSyncService(String sourceClusterId, String destClusterId) {
-
+ if (StringUtils.isEmpty(sourceClusterId) || StringUtils.isEmpty(destClusterId)) {
+ throw new IllegalArgumentException("Source cluster id and destination cluster id must not be null or empty");
+ }
ClusterTypeEnum sourceClusterType = this.skyWalkerCacheServices.getClusterType(sourceClusterId);
ClusterTypeEnum destClusterType = this.skyWalkerCacheServices.getClusterType(destClusterId);
diff --git a/nacossync-worker/src/main/java/com/alibaba/nacossync/extension/client/SyncQueryClient.java b/nacossync-worker/src/main/java/com/alibaba/nacossync/extension/client/SyncQueryClient.java
index 1e88b1c6..d33368fb 100644
--- a/nacossync-worker/src/main/java/com/alibaba/nacossync/extension/client/SyncQueryClient.java
+++ b/nacossync-worker/src/main/java/com/alibaba/nacossync/extension/client/SyncQueryClient.java
@@ -7,5 +7,6 @@ public interface SyncQueryClient {
List getAllInstance(InstanceQueryModel instanceQueryModel);
-
+
+
}
diff --git a/nacossync-worker/src/main/java/com/alibaba/nacossync/extension/holder/AbstractServerHolderImpl.java b/nacossync-worker/src/main/java/com/alibaba/nacossync/extension/holder/AbstractServerHolderImpl.java
index dfde9e4d..6ff8e0c1 100644
--- a/nacossync-worker/src/main/java/com/alibaba/nacossync/extension/holder/AbstractServerHolderImpl.java
+++ b/nacossync-worker/src/main/java/com/alibaba/nacossync/extension/holder/AbstractServerHolderImpl.java
@@ -13,18 +13,19 @@
package com.alibaba.nacossync.extension.holder;
import com.alibaba.nacossync.cache.SkyWalkerCacheServices;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
/**
* @author paderlol
* @date 2018-12-24 22:08
*/
@Slf4j
-public abstract class AbstractServerHolderImpl implements Holder {
+public abstract class AbstractServerHolderImpl implements Holder {
protected final Map serviceMap = new ConcurrentHashMap<>();
diff --git a/nacossync-worker/src/main/java/com/alibaba/nacossync/extension/holder/NacosServerHolder.java b/nacossync-worker/src/main/java/com/alibaba/nacossync/extension/holder/NacosServerHolder.java
index dda88a53..e030d810 100644
--- a/nacossync-worker/src/main/java/com/alibaba/nacossync/extension/holder/NacosServerHolder.java
+++ b/nacossync-worker/src/main/java/com/alibaba/nacossync/extension/holder/NacosServerHolder.java
@@ -13,24 +13,19 @@
package com.alibaba.nacossync.extension.holder;
import com.alibaba.nacos.api.PropertyKeyConst;
-import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingFactory;
import com.alibaba.nacos.api.naming.NamingService;
-import com.alibaba.nacossync.constant.SkyWalkerConstants;
import com.alibaba.nacossync.dao.ClusterAccessService;
-import com.alibaba.nacossync.dao.TaskAccessService;
import com.alibaba.nacossync.pojo.model.ClusterDO;
-import com.alibaba.nacossync.pojo.model.TaskDO;
import com.google.common.base.Joiner;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.logging.log4j.util.Strings;
+import org.springframework.stereotype.Service;
+
import java.util.List;
import java.util.Optional;
import java.util.Properties;
-import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.logging.log4j.util.Strings;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
/**
* @author paderlol
@@ -42,29 +37,16 @@ public class NacosServerHolder extends AbstractServerHolderImpl {
private final ClusterAccessService clusterAccessService;
- private final TaskAccessService taskAccessService;
-
- private static ConcurrentHashMap globalNameService = new ConcurrentHashMap<>(16);
-
- public NacosServerHolder(ClusterAccessService clusterAccessService, TaskAccessService taskAccessService) {
+ public NacosServerHolder(ClusterAccessService clusterAccessService) {
this.clusterAccessService = clusterAccessService;
- this.taskAccessService = taskAccessService;
}
@Override
NamingService createServer(String clusterId, Supplier serverAddressSupplier)
throws Exception {
- String newClusterId;
- if (clusterId.contains(":")) {
- String[] split = clusterId.split(":");
- newClusterId = split[1];
- } else {
- newClusterId = clusterId;
- }
- //代表此时为组合key,确定target集群中的nameService是不同的
List allClusterConnectKey = skyWalkerCacheServices
- .getAllClusterConnectKey(newClusterId);
- ClusterDO clusterDO = clusterAccessService.findByClusterId(newClusterId);
+ .getAllClusterConnectKey(clusterId);
+ ClusterDO clusterDO = clusterAccessService.findByClusterId(clusterId);
String serverList = Joiner.on(",").join(allClusterConnectKey);
Properties properties = new Properties();
properties.setProperty(PropertyKeyConst.SERVER_ADDR, serverList);
@@ -77,51 +59,7 @@ NamingService createServer(String clusterId, Supplier serverAddressSuppl
Optional.ofNullable(clusterDO.getPassword()).ifPresent(value ->
properties.setProperty(PropertyKeyConst.PASSWORD, value)
);
- NamingService namingService = NamingFactory.createNamingService(properties);
- globalNameService.put(clusterId,namingService);
- return namingService;
+ return NamingFactory.createNamingService(properties);
}
- /**
- * Get NamingService for different clients
- * @param clusterId clusterId
- * @return Returns Naming Service objects for different clusters
- */
- public NamingService getNameService(String clusterId){
- return globalNameService.get(clusterId);
- }
-
- public NamingService getSourceNamingService(String taskId, String sourceClusterId) {
- String key = taskId + sourceClusterId;
- return serviceMap.computeIfAbsent(key, k->{
- try {
- log.info("Starting create source cluster server, key={}", key);
- //代表此时为组合key,确定target集群中的nameService是不同的
- List allClusterConnectKey = skyWalkerCacheServices
- .getAllClusterConnectKey(sourceClusterId);
- ClusterDO clusterDO = clusterAccessService.findByClusterId(sourceClusterId);
- TaskDO task = taskAccessService.findByTaskId(taskId);
- String serverList = Joiner.on(",").join(allClusterConnectKey);
- Properties properties = new Properties();
- properties.setProperty(PropertyKeyConst.SERVER_ADDR, serverList);
- properties.setProperty(PropertyKeyConst.NAMESPACE, Optional.ofNullable(clusterDO.getNamespace()).orElse(
- Strings.EMPTY));
- Optional.ofNullable(clusterDO.getUserName()).ifPresent(value ->
- properties.setProperty(PropertyKeyConst.USERNAME, value)
- );
-
- Optional.ofNullable(clusterDO.getPassword()).ifPresent(value ->
- properties.setProperty(PropertyKeyConst.PASSWORD, value)
- );
- properties.setProperty(SkyWalkerConstants.SOURCE_CLUSTERID_KEY,task.getSourceClusterId());
- properties.setProperty(SkyWalkerConstants.DEST_CLUSTERID_KEY,task.getDestClusterId());
- return NamingFactory.createNamingService(properties);
- }catch (NacosException e) {
- log.error("start source server fail,taskId:{},sourceClusterId:{}"
- , taskId, sourceClusterId, e);
- return null;
- }
- });
-
- }
}
diff --git a/nacossync-worker/src/main/java/com/alibaba/nacossync/extension/impl/AbstractNacosSync.java b/nacossync-worker/src/main/java/com/alibaba/nacossync/extension/impl/AbstractNacosSync.java
index 9e4bda19..e0e07f7a 100644
--- a/nacossync-worker/src/main/java/com/alibaba/nacossync/extension/impl/AbstractNacosSync.java
+++ b/nacossync-worker/src/main/java/com/alibaba/nacossync/extension/impl/AbstractNacosSync.java
@@ -11,11 +11,16 @@
import com.alibaba.nacossync.extension.holder.NacosServerHolder;
import com.alibaba.nacossync.monitor.MetricsManager;
import com.alibaba.nacossync.pojo.model.TaskDO;
+import com.alibaba.nacossync.util.BatchTaskExecutor;
+import com.google.common.base.Stopwatch;
+import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -38,63 +43,111 @@ public abstract class AbstractNacosSync implements SyncService {
private final Map syncTaskTap = new ConcurrentHashMap<>();
private final ConcurrentHashMap allSyncTaskMap = new ConcurrentHashMap<>();
-
+ private ScheduledExecutorService executorService;
@Autowired
private MetricsManager metricsManager;
+ @Getter
@Autowired
private NacosServerHolder nacosServerHolder;
/**
- * 因为网络故障等原因,nacos sync的同步任务会失败,导致目标集群注册中心缺少同步实例, 为避免目标集群注册中心长时间缺少同步实例,每隔5分钟启动一个兜底工作线程执行一遍全部的同步任务。
+ * Due to network issues or other reasons, the Nacos Sync synchronization tasks may fail,
+ * resulting in the target cluster's registry missing synchronized instances.
+ * To prevent the target cluster's registry from missing synchronized instances for an extended period,
+ * a fallback worker thread is started every 5 minutes to execute all synchronization tasks.
*/
@PostConstruct
- public void startBasicSyncTaskThread() {
- ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(r -> {
+ public void afterPropertiesSet() {
+ initializeExecutorService();
+ scheduleSyncTasks();
+ }
+
+ @PreDestroy
+ public void destroy() {
+ if (executorService != null && !executorService.isShutdown()) {
+ executorService.shutdown();
+ try {
+ if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
+ executorService.shutdownNow();
+ }
+ } catch (InterruptedException e) {
+ executorService.shutdownNow();
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ private void initializeExecutorService() {
+ executorService = Executors.newSingleThreadScheduledExecutor(r -> {
Thread t = new Thread(r);
t.setDaemon(true);
t.setName("com.alibaba.nacossync.basic.synctask");
return t;
});
+ }
+
+ private void scheduleSyncTasks() {
+ executorService.scheduleWithFixedDelay(this::executeSyncTasks, 0, 300, TimeUnit.SECONDS);
+ }
+
+ private void executeSyncTasks() {
+ if (allSyncTaskMap.isEmpty()) {
+ return;
+ }
- executorService.scheduleWithFixedDelay(() -> {
- if (allSyncTaskMap.size() == 0) {
- return;
- }
-
- try {
- for (TaskDO taskDO : allSyncTaskMap.values()) {
- String taskId = taskDO.getTaskId();
- NamingService sourceNamingService = nacosServerHolder.get(taskDO.getSourceClusterId());
- try {
- doSync(taskId, taskDO, sourceNamingService);
- } catch (Exception e) {
- log.error("basic sync task process fail, taskId:{}", taskId, e);
- metricsManager.recordError(MetricsStatisticsType.SYNC_ERROR);
- }
- }
- } catch (Throwable e) {
- log.warn("basic synctask thread error", e);
- }
- }, 0, 300, TimeUnit.SECONDS);
+ Collection taskCollections = allSyncTaskMap.values();
+ List taskDOList = new ArrayList<>(taskCollections);
+
+ if (CollectionUtils.isNotEmpty(taskDOList)) {
+ BatchTaskExecutor.batchOperation(taskDOList, this::executeTask);
+ }
+ }
+
+ private void executeTask(TaskDO task) {
+ Stopwatch stopwatch = Stopwatch.createStarted();
+ String taskId = task.getTaskId();
+ try {
+ NamingService sourceNamingService = nacosServerHolder.get(task.getSourceClusterId());
+ doSync(taskId, task, sourceNamingService);
+ } catch (NacosException e) {
+ log.error("sync task from nacos to nacos failed, taskId:{}", taskId, e);
+ metricsManager.recordError(MetricsStatisticsType.SYNC_ERROR);
+ } catch (Exception e) {
+ log.error("Unexpected error during sync task, taskId:{}", taskId, e);
+ metricsManager.recordError(MetricsStatisticsType.SYNC_ERROR);
+ } finally {
+ stopwatch.stop();
+ log.debug("Task execution time for taskId {}: {} ms", taskId, stopwatch.elapsed(TimeUnit.MILLISECONDS));
+ }
}
@Override
public boolean delete(TaskDO taskDO) {
+ String taskId = taskDO.getTaskId();
try {
+
NamingService sourceNamingService = nacosServerHolder.get(taskDO.getSourceClusterId());
//移除订阅
+ EventListener listener = listenerMap.remove(taskId);
+ if (listener!= null) {
+ sourceNamingService.unsubscribe(taskDO.getServiceName(), getGroupNameOrDefault(taskDO.getGroupName()), listener);
+ }
sourceNamingService.unsubscribe(taskDO.getServiceName(), getGroupNameOrDefault(taskDO.getGroupName()),
- listenerMap.remove(taskDO.getTaskId()));
- sourceInstanceSnapshot.remove(taskDO.getTaskId());
- allSyncTaskMap.remove(taskDO.getTaskId());
+ listenerMap.remove(taskId));
+ sourceInstanceSnapshot.remove(taskId);
+ allSyncTaskMap.remove(taskId);
// 删除目标集群中同步的实例列表
deregisterInstance(taskDO);
+ }catch (NacosException e) {
+ log.error("Delete task from nacos to specify destination was failed, taskId:{}", taskId, e);
+ metricsManager.recordError(MetricsStatisticsType.SYNC_ERROR);
+ return false;
} catch (Exception e) {
- log.error("delete task from nacos to specify destination was failed, taskId:{}", taskDO.getTaskId(), e);
- metricsManager.recordError(MetricsStatisticsType.DELETE_ERROR);
+ log.error("Unexpected error during sync task, taskId:{}", taskId, e);
+ metricsManager.recordError(MetricsStatisticsType.SYNC_ERROR);
return false;
}
return true;
@@ -120,8 +173,12 @@ public boolean sync(TaskDO taskDO, Integer index) {
});
sourceNamingService.subscribe(taskDO.getServiceName(), getGroupNameOrDefault(taskDO.getGroupName()),
listenerMap.get(taskId));
+ }catch (NacosException e) {
+ log.error("Nacos sync task process fail, taskId:{}", taskId, e);
+ metricsManager.recordError(MetricsStatisticsType.SYNC_ERROR);
+ return false;
} catch (Exception e) {
- log.error("sync task from nacos to specify destination was failed, taskId:{}", taskId, e);
+ log.error("Unexpected error during sync task, taskId:{}", taskId, e);
metricsManager.recordError(MetricsStatisticsType.SYNC_ERROR);
return false;
}
@@ -205,7 +262,4 @@ public boolean needSync(Map sourceMetaData) {
public abstract void removeInvalidInstance(TaskDO taskDO, Set invalidInstanceKeys) throws Exception;
- public NacosServerHolder getNacosServerHolder() {
- return nacosServerHolder;
- }
}
diff --git a/nacossync-worker/src/main/java/com/alibaba/nacossync/extension/impl/NacosSyncToNacosServiceImpl.java b/nacossync-worker/src/main/java/com/alibaba/nacossync/extension/impl/NacosSyncToNacosServiceImpl.java
index 89eced92..a6d5f41a 100644
--- a/nacossync-worker/src/main/java/com/alibaba/nacossync/extension/impl/NacosSyncToNacosServiceImpl.java
+++ b/nacossync-worker/src/main/java/com/alibaba/nacossync/extension/impl/NacosSyncToNacosServiceImpl.java
@@ -18,9 +18,7 @@
import com.alibaba.nacos.api.naming.listener.EventListener;
import com.alibaba.nacos.api.naming.listener.NamingEvent;
import com.alibaba.nacos.api.naming.pojo.Instance;
-import com.alibaba.nacos.api.naming.pojo.ListView;
import com.alibaba.nacos.common.utils.CollectionUtils;
-import com.alibaba.nacos.common.utils.ConcurrentHashSet;
import com.alibaba.nacossync.cache.SkyWalkerCacheServices;
import com.alibaba.nacossync.constant.ClusterTypeEnum;
import com.alibaba.nacossync.constant.MetricsStatisticsType;
@@ -31,19 +29,18 @@
import com.alibaba.nacossync.extension.holder.NacosServerHolder;
import com.alibaba.nacossync.monitor.MetricsManager;
import com.alibaba.nacossync.pojo.model.TaskDO;
-import com.alibaba.nacossync.template.processor.TaskUpdateProcessor;
-import com.alibaba.nacossync.timer.FastSyncHelper;
+import com.alibaba.nacossync.util.BatchTaskExecutor;
import com.alibaba.nacossync.util.StringUtils;
+import com.google.common.base.Stopwatch;
import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
-import org.springframework.beans.factory.annotation.Autowired;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
@@ -60,125 +57,133 @@
@Slf4j
@NacosSyncService(sourceCluster = ClusterTypeEnum.NACOS, destinationCluster = ClusterTypeEnum.NACOS)
-public class NacosSyncToNacosServiceImpl implements SyncService, InitializingBean {
+public class NacosSyncToNacosServiceImpl implements SyncService, InitializingBean, DisposableBean {
- private Map listenerMap = new ConcurrentHashMap<>();
+ private final Map listenerMap = new ConcurrentHashMap<>();
private final Map syncTaskTap = new ConcurrentHashMap<>();
- @Autowired
- private MetricsManager metricsManager;
+ private final ConcurrentHashMap allSyncTaskMap = new ConcurrentHashMap<>();
- @Autowired
- private SkyWalkerCacheServices skyWalkerCacheServices;
+ private ScheduledExecutorService executorService;
- @Autowired
- private NacosServerHolder nacosServerHolder;
+ private final MetricsManager metricsManager;
- private ConcurrentHashMap allSyncTaskMap = new ConcurrentHashMap<>();
+ private final NacosServerHolder nacosServerHolder;
- @Autowired
- private ClusterAccessService clusterAccessService;
+ private final ClusterAccessService clusterAccessService;
- public static Map> serviceClient = new ConcurrentHashMap<>();
+ private final SkyWalkerCacheServices skyWalkerCacheServices;
- @Autowired
- private FastSyncHelper fastSyncHelper;
-
- @Autowired
- private TaskUpdateProcessor taskUpdateProcessor;
+ public NacosSyncToNacosServiceImpl(MetricsManager metricsManager, NacosServerHolder nacosServerHolder,
+ ClusterAccessService clusterAccessService, SkyWalkerCacheServices skyWalkerCacheServices) {
+ this.metricsManager = metricsManager;
+ this.nacosServerHolder = nacosServerHolder;
+ this.clusterAccessService = clusterAccessService;
+ this.skyWalkerCacheServices = skyWalkerCacheServices;
+ }
/**
- * 因为网络故障等原因,nacos sync的同步任务会失败,导致目标集群注册中心缺少同步实例, 为避免目标集群注册中心长时间缺少同步实例,每隔5分钟启动一个兜底工作线程执行一遍全部的同步任务。
+ * Due to network issues or other reasons, the Nacos Sync synchronization tasks may fail,
+ * resulting in the target cluster's registry missing synchronized instances.
+ * To prevent the target cluster's registry from missing synchronized instances for an extended period,
+ * a fallback worker thread is started every 5 minutes to execute all synchronization tasks.
*/
-
-
@Override
public void afterPropertiesSet() {
- ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(r -> {
+ initializeExecutorService();
+ scheduleSyncTasks();
+ }
+
+ @Override
+ public void destroy() {
+ if (executorService != null && !executorService.isShutdown()) {
+ executorService.shutdown();
+ try {
+ if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
+ executorService.shutdownNow();
+ }
+ } catch (InterruptedException e) {
+ executorService.shutdownNow();
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ private void initializeExecutorService() {
+ executorService = Executors.newSingleThreadScheduledExecutor(r -> {
Thread t = new Thread(r);
t.setDaemon(true);
t.setName("com.alibaba.nacossync.basic.synctask");
return t;
});
+ }
+
+ private void scheduleSyncTasks() {
+ executorService.scheduleWithFixedDelay(this::executeSyncTasks, 0, 300, TimeUnit.SECONDS);
+ }
+
+ private void executeSyncTasks() {
+ if (allSyncTaskMap.isEmpty()) {
+ return;
+ }
- executorService.scheduleWithFixedDelay(() -> {
- if (allSyncTaskMap.size() == 0) {
- return;
- }
-
- try {
- Collection taskCollections = allSyncTaskMap.values();
- List taskDOList = new ArrayList<>(taskCollections);
-
- if (CollectionUtils.isNotEmpty(taskDOList)) {
- fastSyncHelper.syncWithThread(taskDOList, this::timeSync);
- }
-
- } catch (Throwable e) {
- log.warn("basic synctask thread error", e);
- }
- }, 0, 300, TimeUnit.SECONDS);
+ Collection taskCollections = allSyncTaskMap.values();
+ List taskDOList = new ArrayList<>(taskCollections);
+
+ if (CollectionUtils.isNotEmpty(taskDOList)) {
+ BatchTaskExecutor.batchOperation(taskDOList, this::executeTask);
+ }
+ }
+
+ private void executeTask(TaskDO task) {
+ Stopwatch stopwatch = Stopwatch.createStarted();
+ String taskId = task.getTaskId();
+ try {
+ NamingService sourceNamingService = nacosServerHolder.get(task.getSourceClusterId());
+ NamingService destNamingService = nacosServerHolder.get(task.getDestClusterId());
+ doSync(taskId, task, sourceNamingService, destNamingService);
+ } catch (NacosException e) {
+ log.error("sync task from nacos to nacos failed, taskId:{}", taskId, e);
+ metricsManager.recordError(MetricsStatisticsType.SYNC_ERROR);
+ } catch (Exception e) {
+ log.error("Unexpected error during sync task, taskId:{}", taskId, e);
+ metricsManager.recordError(MetricsStatisticsType.SYNC_ERROR);
+ } finally {
+ stopwatch.stop();
+ log.debug("Task execution time for taskId {}: {} ms", taskId, stopwatch.elapsed(TimeUnit.MILLISECONDS));
+ }
}
@Override
public boolean delete(TaskDO taskDO) {
try {
- NamingService sourceNamingService = nacosServerHolder.getSourceNamingService(taskDO.getTaskId(),
- taskDO.getSourceClusterId());
+ NamingService sourceNamingService = nacosServerHolder.get(taskDO.getSourceClusterId());
+ int level = clusterAccessService.findClusterLevel(taskDO.getSourceClusterId());
+ String taskId = taskDO.getTaskId();
- if ("ALL".equals(taskDO.getServiceName())) {
- String operationId = taskUpdateProcessor.getTaskIdAndOperationIdMap(taskDO.getTaskId());
- if (!StringUtils.isEmpty(operationId)) {
- allSyncTaskMap.remove(operationId);
- }
-
- //处理group级别的服务任务删除
- ListView servicesOfServer = sourceNamingService.getServicesOfServer(0, Integer.MAX_VALUE,
- taskDO.getGroupName());
- List serviceNames = servicesOfServer.getData();
- for (String serviceName : serviceNames) {
- String operationKey = taskDO.getTaskId() + serviceName;
- skyWalkerCacheServices.removeFinishedTask(operationKey);
- allSyncTaskMap.remove(operationKey);
- NamingService destNamingService = popNamingService(taskDO);
- sourceNamingService.unsubscribe(serviceName, getGroupNameOrDefault(taskDO.getGroupName()),
- listenerMap.remove(taskDO.getTaskId() + serviceName));
-
- List sourceInstances = sourceNamingService.getAllInstances(serviceName,
- getGroupNameOrDefault(taskDO.getGroupName()), new ArrayList<>(), false);
- for (Instance instance : sourceInstances) {
- if (needSync(instance.getMetadata())) {
- destNamingService.deregisterInstance(serviceName,
- getGroupNameOrDefault(taskDO.getGroupName()), instance.getIp(), instance.getPort());
- }
- }
- }
- } else {
- //处理服务级别的任务删除
- String operationId = taskUpdateProcessor.getTaskIdAndOperationIdMap(taskDO.getTaskId());
- if (StringUtils.isEmpty(operationId)) {
- log.warn("operationId is null data synchronization is not currently performed.{}", operationId);
- return false;
- }
-
- sourceNamingService.unsubscribe(taskDO.getServiceName(), getGroupNameOrDefault(taskDO.getGroupName()),
- listenerMap.remove(operationId));
- List sourceInstances = sourceNamingService.getAllInstances(taskDO.getServiceName(),
- getGroupNameOrDefault(taskDO.getGroupName()), new ArrayList<>(), false);
-
- NamingService destNamingService = popNamingService(taskDO);
- for (Instance instance : sourceInstances) {
- if (needSync(instance.getMetadata())) {
- destNamingService.deregisterInstance(taskDO.getServiceName(),
- getGroupNameOrDefault(taskDO.getGroupName()), instance);
- }
+ //Handle individual service
+ if (StringUtils.isEmpty(taskId)) {
+ log.warn("taskId is null data synchronization is not currently performed.{}", taskId);
+ return false;
+ }
+ EventListener listener = listenerMap.remove(taskId);
+ if (listener!= null) {
+ sourceNamingService.unsubscribe(taskDO.getServiceName(), getGroupNameOrDefault(taskDO.getGroupName()), listener);
+ }
+ List sourceInstances = sourceNamingService.getAllInstances(taskDO.getServiceName(),
+ getGroupNameOrDefault(taskDO.getGroupName()), new ArrayList<>(), false);
+
+ NamingService destNamingService = nacosServerHolder.get(taskDO.getDestClusterId());
+ for (Instance instance : sourceInstances) {
+ if (needSync(instance.getMetadata(), level, taskDO.getDestClusterId())) {
+ destNamingService.deregisterInstance(taskDO.getServiceName(),
+ getGroupNameOrDefault(taskDO.getGroupName()), instance);
}
- // 移除任务
- skyWalkerCacheServices.removeFinishedTask(operationId);
- // 移除所有需要同步的Task
- allSyncTaskMap.remove(operationId);
}
+ // Remove all tasks that need to be synchronized.
+ allSyncTaskMap.remove(taskId);
+
} catch (Exception e) {
log.error("delete task from nacos to nacos was failed, operationalId:{}", taskDO.getOperationId(), e);
metricsManager.recordError(MetricsStatisticsType.DELETE_ERROR);
@@ -189,75 +194,52 @@ public boolean delete(TaskDO taskDO) {
@Override
public boolean sync(TaskDO taskDO, Integer index) {
- log.info("线程 {} 开始同步 {} ", Thread.currentThread().getId(), System.currentTimeMillis());
- String operationId = taskDO.getOperationId();
+ log.info("Thread {} started synchronization at {}", Thread.currentThread().getId(), System.currentTimeMillis());
+ String taskId = taskDO.getTaskId();
try {
- NamingService sourceNamingService = nacosServerHolder.getSourceNamingService(taskDO.getTaskId(),
- taskDO.getSourceClusterId());
- NamingService destNamingService = getDestNamingService(taskDO, index);
- allSyncTaskMap.put(operationId, taskDO);
- //防止暂停同步任务后,重新同步/或删除任务以后新建任务不会再接收到新的事件导致不能同步,所以每次订阅事件之前,先全量同步一次任务
- long startTime = System.currentTimeMillis();
- doSync(operationId, taskDO, sourceNamingService, destNamingService);
- log.info("同步一个服务注册耗时:{} ms", System.currentTimeMillis() - startTime);
- this.listenerMap.putIfAbsent(operationId, event -> {
+ NamingService sourceNamingService = nacosServerHolder.get(taskDO.getSourceClusterId());
+ NamingService destNamingService = nacosServerHolder.get(taskDO.getDestClusterId());
+ allSyncTaskMap.put(taskId, taskDO);
+ // To prevent issues where tasks paused for synchronization, newly created tasks after deletion,
+ // or resynchronization tasks do not receive new events and hence cannot synchronize,
+ // perform a full synchronization of tasks before subscribing to events each time.
+ Stopwatch stopwatch = Stopwatch.createStarted();
+ doSync(taskId, taskDO, sourceNamingService, destNamingService);
+ log.debug("Time taken to synchronize a service registration: {} ms",
+ stopwatch.elapsed(TimeUnit.MILLISECONDS));
+ this.listenerMap.putIfAbsent(taskId, event -> {
if (event instanceof NamingEvent) {
NamingEvent namingEvent = (NamingEvent) event;
- log.info("监听到服务{}信息改变, taskId:{},实例数:{},发起同步", namingEvent.getServiceName(),
- operationId, namingEvent.getInstances() == null ? null : namingEvent.getInstances().size());
+ log.info("Detected changes in service {} information, taskId: {}, number of instances: {}, initiating synchronization",
+ namingEvent.getServiceName(), taskId,
+ namingEvent.getInstances() == null ? null : namingEvent.getInstances().size());
try {
- doSync(operationId, taskDO, sourceNamingService, destNamingService);
- log.info("监听到服务{}同步结束", namingEvent.getServiceName());
+ doSync(taskId, taskDO, sourceNamingService, destNamingService);
+ log.info("Detected synchronization end for service {}", namingEvent.getServiceName());
} catch (Exception e) {
- log.error("event process fail, operationId:{}", operationId, e);
+ log.error("event process fail, taskId:{}", taskId, e);
metricsManager.recordError(MetricsStatisticsType.SYNC_ERROR);
}
}
});
sourceNamingService.subscribe(taskDO.getServiceName(), getGroupNameOrDefault(taskDO.getGroupName()),
- listenerMap.get(operationId));
+ listenerMap.get(taskId));
} catch (Exception e) {
- log.error("sync task from nacos to nacos was failed, operationId:{}", operationId, e);
+ log.error("sync task from nacos to nacos was failed, taskId:{}", taskId, e);
metricsManager.recordError(MetricsStatisticsType.SYNC_ERROR);
return false;
}
return true;
}
- /**
- * basic sync
- *
- * @param taskDO
- */
- public void timeSync(TaskDO taskDO) {
- log.debug("线程{}开始同步{}", Thread.currentThread().getId(), System.currentTimeMillis());
- String operationId = taskDO.getOperationId();
- try {
- NamingService sourceNamingService = nacosServerHolder.getSourceNamingService(taskDO.getTaskId(),
- taskDO.getSourceClusterId());
- //获取目标集群client
- NamingService destNamingService = popNamingService(taskDO);
- long startTime = System.currentTimeMillis();
- doSync(operationId, taskDO, sourceNamingService, destNamingService);
- log.info("同步一个服务注册耗时:{} ms", System.currentTimeMillis() - startTime);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- private NamingService getDestNamingService(TaskDO taskDO, Integer index) {
- String key = taskDO.getSourceClusterId() + ":" + taskDO.getDestClusterId() + ":" + index;
- return nacosServerHolder.get(key);
- }
private void doSync(String taskId, TaskDO taskDO, NamingService sourceNamingService,
NamingService destNamingService) throws NacosException {
if (syncTaskTap.putIfAbsent(taskId, 1) != null) {
- log.info("任务Id:{}上一个同步任务尚未结束", taskId);
+ log.info("Task ID:{} - the previous synchronization task has not finished yet", taskId);
return;
}
- //记录目标集群的Client
- recordNamingService(taskDO, destNamingService);
+
try {
List sourceInstances = sourceNamingService.getAllInstances(taskDO.getServiceName(),
@@ -265,14 +247,15 @@ private void doSync(String taskId, TaskDO taskDO, NamingService sourceNamingServ
int level = clusterAccessService.findClusterLevel(taskDO.getSourceClusterId());
if (CollectionUtils.isNotEmpty(sourceInstances) && sourceInstances.get(0).isEphemeral()) {
- //处临实例的批量数据同步,需要获取当前所有的服务实例,TODO,当Client为1.x的时候,执行和持久化实例一样的同步方式
+ // Handle batch data synchronization of ephemeral instances, need to get all current service instances.
+ // TODO: When the Client is version 1.x, execute the same synchronization method as persistent instances.
handlerPersistenceInstance(taskDO, destNamingService, sourceInstances, level);
} else if (CollectionUtils.isEmpty(sourceInstances)) {
- //如果当前源集群是空的 ,那么直接注销目标集群的实例
- log.debug("service {} need sync Ephemeral instance num is null: serviceName ", taskDO.getServiceName());
+ // If the current source cluster is empty, then directly deregister the instances in the target cluster.
+ log.debug("service {} needs to sync ephemeral instance num is null: serviceName ", taskDO.getServiceName());
processDeRegisterInstances(taskDO, destNamingService);
} else {
- //处临持久化实例的批量数据同步
+ // Handle batch data synchronization of persistent instances.
handlerPersistenceInstance(taskDO, destNamingService, sourceInstances, level);
}
} finally {
@@ -285,67 +268,78 @@ private void handlerPersistenceInstance(TaskDO taskDO, NamingService destNamingS
List needRegisterInstance = new ArrayList<>();
for (Instance instance : sourceInstances) {
if (needSync(instance.getMetadata(), level, taskDO.getDestClusterId())) {
- needRegisterInstance.add(instance);
+ needRegisterInstance.add(buildSyncInstance(instance, taskDO));
}
}
List destAllInstances = destNamingService.getAllInstances(taskDO.getServiceName(),
getGroupNameOrDefault(taskDO.getGroupName()), new ArrayList<>(), true);
- // 获取目标集群自己已经同步的实例
+ // Get the instances that the destination cluster has already synchronized
List destHasSyncInstances = destAllInstances.stream()
.filter(instance -> hasSync(instance, taskDO.getSourceClusterId())).collect(Collectors.toList());
- //获取新增的实例,遍历新增
- List newInstances = new ArrayList<>(needRegisterInstance);
- instanceRemove(destHasSyncInstances, newInstances);
- //注册
+ // The following two conversions are necessary because the Nacos Instance's equals method
+ // is flawed and cannot be used for direct comparison.
+ // The reason is that Instance's equals method compares Metadata using the toString method,
+ // and Metadata is of type HashMap, which does not guarantee order in its toString representation.
+
+ // Convert destHasSyncInstances to a Map with the concatenated string as key
+ Map destInstanceMap = destHasSyncInstances.stream()
+ .collect(Collectors.toMap(NacosSyncToNacosServiceImpl::getInstanceKey, instance -> instance));
+
+ // Convert newInstances to a Map with the concatenated string as key
+ Map needRegisterMap = needRegisterInstance.stream()
+ .collect(Collectors.toMap(NacosSyncToNacosServiceImpl::getInstanceKey, instance -> instance));
+
+ // Remove instances from newInstanceMap that are present in destInstanceMap
+ List newInstances = removeSyncedInstances(destInstanceMap, needRegisterMap);
+
+ // Remove instances from destInstanceMap that are present in newInstanceMap
+ List invalidInstances = getInvalidInstances(destInstanceMap, needRegisterMap);
+
+ // Register each instance one by one. Take one instance at a time.
for (Instance newInstance : newInstances) {
destNamingService.registerInstance(taskDO.getServiceName(), getGroupNameOrDefault(taskDO.getGroupName()),
- buildSyncInstance(newInstance, taskDO));
- }
-
- List notRemoveInstances = new ArrayList<>();
- for (Instance destHasSyncInstance : destHasSyncInstances) {
- for (Instance instance : needRegisterInstance) {
- if (instanceEquals(destHasSyncInstance, instance)) {
- notRemoveInstances.add(destHasSyncInstance);
- }
- }
+ newInstance);
}
- destHasSyncInstances.removeAll(notRemoveInstances);
- if (CollectionUtils.isNotEmpty(destHasSyncInstances)) {
- log.info("taskid:{},服务 {} 发生反注册,执行数量 {} ", taskDO.getTaskId(), taskDO.getServiceName(),
+ if (CollectionUtils.isNotEmpty(invalidInstances)) {
+ log.info("taskId: {}, service {} deregistered, number of executions: {}", taskDO.getTaskId(), taskDO.getServiceName(),
destHasSyncInstances.size());
}
-
- for (Instance destAllInstance : destHasSyncInstances) {
+ for (Instance instance : invalidInstances) {
destNamingService.deregisterInstance(taskDO.getServiceName(), getGroupNameOrDefault(taskDO.getGroupName()),
- destAllInstance);
+ instance);
}
}
-
- public static boolean instanceEquals(Instance ins1, Instance ins2) {
- return (ins1.getIp().equals(ins2.getIp())) && (ins1.getPort() == ins2.getPort()) && (ins1.getWeight()
- == ins2.getWeight()) && (ins1.isHealthy() == ins2.isHealthy()) && (ins1.isEphemeral()
- == ins2.isEphemeral()) && (ins1.getClusterName().equals(ins2.getClusterName()))
- && (ins1.getServiceName().equals(ins2.getServiceName()));
+ private List getInvalidInstances(Map destInstanceMap, Map needRegisterMap) {
+ Map destClone = new HashMap<>(destInstanceMap);
+
+ // Convert newInstances to a Map with the concatenated string as key
+ Map needRegisterClone = new HashMap<>(needRegisterMap);
+
+ // Remove instances from newInstanceMap that are present in destInstanceMap
+ destClone.keySet().removeAll(needRegisterClone.keySet());
+
+ return new ArrayList<>(destClone.values());
}
- private void instanceRemove(List destHasSyncInstances, List newInstances) {
- List needRemoveInstance = new ArrayList<>();
- for (Instance destHasSyncInstance : destHasSyncInstances) {
- for (Instance newInstance : newInstances) {
- if (destHasSyncInstance.equals(newInstance)) {
- //如果目标集群已经存在了源集群同步过来的实例,就不需要同步了
- needRemoveInstance.add(newInstance);
- }
- }
- }
- // eg:A Cluster 已经同步到 B Cluster的实例数据,就不需要再重复同步过来了
- newInstances.removeAll(needRemoveInstance);
+
+ public List removeSyncedInstances(Map destInstanceMap, Map needRegisterMap) {
+ // Convert destHasSyncInstances to a Map with the concatenated string as key
+
+ Map destClone = new HashMap<>(destInstanceMap);
+
+ // Convert newInstances to a Map with the concatenated string as key
+ Map needRegisterClone = new HashMap<>(needRegisterMap);
+
+ // Remove instances from newInstanceMap that are present in destInstanceMap
+ needRegisterClone.keySet().removeAll(destClone.keySet());
+
+ return new ArrayList<>(needRegisterClone.values());
}
+
private boolean hasSync(Instance instance, String sourceClusterId) {
if (instance.getMetadata() != null) {
@@ -357,23 +351,25 @@ private boolean hasSync(Instance instance, String sourceClusterId) {
/**
- * 当源集群需要同步的实例个数为0时,目标集群如果还有源集群同步的实例,执行反注册
+ * When the number of instances that the source cluster needs to synchronize is 0,
+ * if the target cluster still has instances synchronized with the source cluster,
+ * perform unregistration.
*
- * @param taskDO
* @param destNamingService
* @throws NacosException
*/
private void processDeRegisterInstances(TaskDO taskDO, NamingService destNamingService) throws NacosException {
- //如果此时sourceInstance中的实例为空,证明此时实例下线或实例不存在
+ // If the instances in sourceInstances are empty, it means the instances are offline or do not exist.
List destInstances = destNamingService.getAllInstances(taskDO.getServiceName(),
getGroupNameOrDefault(taskDO.getGroupName()), new ArrayList<>(), false);
- // 如果目标集群中的数据实例也为空了,则测试无需操作
+ // If the instances in the target cluster are also empty, then no operation is needed.
if (CollectionUtils.isEmpty(destInstances)) {
return;
}
- deRegisterFilter(destInstances, taskDO.getSourceClusterId());
+ destInstances = filterInstancesForRemoval(destInstances, taskDO.getSourceClusterId());
if (CollectionUtils.isNotEmpty(destInstances)) {
- //逐个执行反注册,拿出一个实例即可, 需要处理redo,否则会被重新注册上来
+ // Deregister each instance one by one. Take one instance at a time.
+ // Need to handle redo, otherwise, it will be registered again.
for (Instance destInstance : destInstances) {
destNamingService.deregisterInstance(taskDO.getServiceName(),
getGroupNameOrDefault(taskDO.getGroupName()), destInstance);
@@ -381,17 +377,11 @@ private void processDeRegisterInstances(TaskDO taskDO, NamingService destNamingS
}
}
- private void deRegisterFilter(List destInstances, String sourceClusterId) {
- List newDestInstance = new ArrayList<>();
- for (Instance destInstance : destInstances) {
- Map metadata = destInstance.getMetadata();
- String destSourceClusterId = metadata.get(SkyWalkerConstants.SOURCE_CLUSTERID_KEY);
- if (needDeregister(destSourceClusterId, sourceClusterId)) {
- // 需要执行反注册
- newDestInstance.add(destInstance);
- }
- }
- destInstances = newDestInstance;
+ private List filterInstancesForRemoval(List destInstances, String sourceClusterId) {
+ return destInstances.stream().filter(instance -> !instance.getMetadata().isEmpty())
+ .filter(instance -> needDeregister(instance.getMetadata().get(SOURCE_CLUSTERID_KEY), sourceClusterId))
+ .collect(Collectors.toList());
+
}
private boolean needDeregister(String destClusterId, String sourceClusterId) {
@@ -402,42 +392,31 @@ private boolean needDeregister(String destClusterId, String sourceClusterId) {
}
private boolean needSync(Map sourceMetaData, int level, String destClusterId) {
- //普通集群(默认)
+ // Regular cluster (default)
if (level == 0) {
return SyncService.super.needSync(sourceMetaData);
}
- //中心集群,只要不是目标集群传过来的实例,都需要同步(扩展功能)
- if (!destClusterId.equals(sourceMetaData.get(SOURCE_CLUSTERID_KEY))) {
- return true;
- }
- return false;
+ // Central cluster, as long as the instance is not from the target cluster,
+ // it needs to be synchronized (extended functionality)
+ return !destClusterId.equals(sourceMetaData.get(SOURCE_CLUSTERID_KEY));
}
- private void recordNamingService(TaskDO taskDO, NamingService destNamingService) {
- String key = buildClientKey(taskDO);
- serviceClient.computeIfAbsent(key, clientKey -> {
- Set hashSet = new ConcurrentHashSet<>();
- hashSet.add(destNamingService);
- return hashSet;
- });
- }
-
- public NamingService popNamingService(TaskDO taskDO) {
- String key = buildClientKey(taskDO);
- Set namingServices = serviceClient.get(key);
- if (CollectionUtils.isNotEmpty(namingServices)) {
- return namingServices.iterator().next();
- }
- log.warn("{} 无可用 namingservice", key);
- return null;
- }
- private static String buildClientKey(TaskDO taskDO) {
- return taskDO.getId() + ":" + taskDO.getServiceName();
+ private Instance buildSyncInstance(Instance instance, TaskDO taskDO) {
+ Instance temp = getInstance(instance);
+ temp.addMetadata(SkyWalkerConstants.DEST_CLUSTERID_KEY, taskDO.getDestClusterId());
+ temp.addMetadata(SkyWalkerConstants.SYNC_SOURCE_KEY,
+ skyWalkerCacheServices.getClusterType(taskDO.getSourceClusterId()).getCode());
+ temp.addMetadata(SkyWalkerConstants.SOURCE_CLUSTERID_KEY, taskDO.getSourceClusterId());
+ //The flag is a synchronous instance
+ temp.addMetadata(SkyWalkerConstants.SYNC_INSTANCE_TAG,
+ taskDO.getSourceClusterId() + "@@" + taskDO.getVersion());
+ return temp;
}
- private Instance buildSyncInstance(Instance instance, TaskDO taskDO) {
+ private static Instance getInstance(Instance instance) {
Instance temp = new Instance();
+ temp.setInstanceId(instance.getInstanceId());
temp.setIp(instance.getIp());
temp.setPort(instance.getPort());
temp.setClusterName(instance.getClusterName());
@@ -447,15 +426,18 @@ private Instance buildSyncInstance(Instance instance, TaskDO taskDO) {
temp.setWeight(instance.getWeight());
temp.setEphemeral(instance.isEphemeral());
Map metaData = new HashMap<>(instance.getMetadata());
- metaData.put(SkyWalkerConstants.DEST_CLUSTERID_KEY, taskDO.getDestClusterId());
- metaData.put(SkyWalkerConstants.SYNC_SOURCE_KEY,
- skyWalkerCacheServices.getClusterType(taskDO.getSourceClusterId()).getCode());
- metaData.put(SkyWalkerConstants.SOURCE_CLUSTERID_KEY, taskDO.getSourceClusterId());
- //标识是同步实例
- metaData.put(SkyWalkerConstants.SYNC_INSTANCE_TAG, taskDO.getSourceClusterId() + "@@" + taskDO.getVersion());
temp.setMetadata(metaData);
return temp;
}
-
+ private static String getInstanceKey(Instance instance) {
+ return String.join("|",
+ instance.getIp(),
+ String.valueOf(instance.getPort()),
+ String.valueOf(instance.getWeight()),
+ String.valueOf(instance.isHealthy()),
+ String.valueOf(instance.isEphemeral()),
+ instance.getClusterName(),
+ instance.getServiceName());
+ }
}
diff --git a/nacossync-worker/src/main/java/com/alibaba/nacossync/extension/impl/NacosSyncToZookeeperServiceImpl.java b/nacossync-worker/src/main/java/com/alibaba/nacossync/extension/impl/NacosSyncToZookeeperServiceImpl.java
index b746d2d6..da81d05c 100644
--- a/nacossync-worker/src/main/java/com/alibaba/nacossync/extension/impl/NacosSyncToZookeeperServiceImpl.java
+++ b/nacossync-worker/src/main/java/com/alibaba/nacossync/extension/impl/NacosSyncToZookeeperServiceImpl.java
@@ -12,10 +12,6 @@
*/
package com.alibaba.nacossync.extension.impl;
-import static com.alibaba.nacossync.util.NacosUtils.getGroupNameOrDefault;
-import static com.alibaba.nacossync.util.StringUtils.convertDubboFullPathForZk;
-import static com.alibaba.nacossync.util.StringUtils.convertDubboProvidersPath;
-
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.listener.EventListener;
import com.alibaba.nacos.api.naming.listener.NamingEvent;
@@ -33,6 +29,14 @@
import com.alibaba.nacossync.pojo.model.TaskDO;
import com.alibaba.nacossync.util.DubboConstants;
import com.google.common.collect.Sets;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.recipes.cache.PathChildrenCache;
+import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
+import org.apache.curator.utils.CloseableUtils;
+import org.apache.zookeeper.CreateMode;
+import org.springframework.beans.factory.annotation.Autowired;
+
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
@@ -41,13 +45,10 @@
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.curator.framework.CuratorFramework;
-import org.apache.curator.framework.recipes.cache.PathChildrenCache;
-import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
-import org.apache.curator.utils.CloseableUtils;
-import org.apache.zookeeper.CreateMode;
-import org.springframework.beans.factory.annotation.Autowired;
+
+import static com.alibaba.nacossync.util.NacosUtils.getGroupNameOrDefault;
+import static com.alibaba.nacossync.util.StringUtils.convertDubboFullPathForZk;
+import static com.alibaba.nacossync.util.StringUtils.convertDubboProvidersPath;
/**
* Nacos 同步 Zk 数据
@@ -113,8 +114,10 @@ public boolean delete(TaskDO taskDO) {
CloseableUtils.closeQuietly(pathChildrenCache);
Set instanceUrlSet = instanceBackupMap.get(taskDO.getTaskId());
CuratorFramework client = zookeeperServerHolder.get(taskDO.getDestClusterId());
- for (String instanceUrl : instanceUrlSet) {
- client.delete().quietly().forPath(instanceUrl);
+ if(!instanceUrlSet.isEmpty()){
+ for (String instanceUrl : instanceUrlSet) {
+ client.delete().quietly().forPath(instanceUrl);
+ }
}
} catch (Exception e) {
log.error("delete task from nacos to zk was failed, taskId:{}", taskDO.getTaskId(), e);
@@ -161,28 +164,45 @@ public boolean sync(TaskDO taskDO, Integer index) {
}
return true;
}
-
+
private void tryToCompensate(TaskDO taskDO, NamingService sourceNamingService, List sourceInstances) {
if (!CollectionUtils.isEmpty(sourceInstances)) {
final PathChildrenCache pathCache = getPathCache(taskDO);
- if (pathCache.getListenable().size() == 0) { // 防止重复注册
- pathCache.getListenable().addListener((zkClient, zkEvent) -> {
- if (zkEvent.getType() == PathChildrenCacheEvent.Type.CHILD_REMOVED) {
- List allInstances =
- sourceNamingService.getAllInstances(taskDO.getServiceName(),getGroupNameOrDefault(taskDO.getGroupName()));
- for (Instance instance : allInstances) {
- String instanceUrl = buildSyncInstance(instance, taskDO);
- String zkInstancePath = zkEvent.getData().getPath();
- if (zkInstancePath.equals(instanceUrl)) {
- zkClient.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL)
- .forPath(zkInstancePath);
- break;
- }
- }
- }
- });
+ // Avoiding re-registration if there is already a listener registered.
+ if (pathCache.getListenable().size() == 0) {
+ registerCompensationListener(pathCache, taskDO, sourceNamingService);
}
-
+ }
+ }
+
+ private void registerCompensationListener(PathChildrenCache pathCache, TaskDO taskDO, NamingService sourceNamingService) {
+ pathCache.getListenable().addListener((zkClient, zkEvent) -> {
+ try {
+ if (zkEvent.getType() == PathChildrenCacheEvent.Type.CHILD_REMOVED) {
+ compensateOnChildRemoval(zkClient, zkEvent, sourceNamingService, taskDO);
+ }
+ } catch (Exception e) {
+ log.error("Error processing ZooKeeper event: {}", zkEvent.getType(), e);
+ }
+ });
+ }
+
+ private void compensateOnChildRemoval(CuratorFramework zkClient, PathChildrenCacheEvent zkEvent, NamingService sourceNamingService, TaskDO taskDO) {
+ String zkInstancePath = null;
+ try {
+ List allInstances = sourceNamingService.getAllInstances(taskDO.getServiceName(), getGroupNameOrDefault(taskDO.getGroupName()));
+ zkInstancePath = zkEvent.getData().getPath();
+ for (Instance instance : allInstances) {
+ String instanceUrl = buildSyncInstance(instance, taskDO);
+ if (zkInstancePath.equals(instanceUrl)) {
+ zkClient.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL)
+ .forPath(zkInstancePath);
+ log.info("Compensated by re-creating the removed node at path: {}", zkInstancePath);
+ break;
+ }
+ }
+ } catch (Exception e) {
+ log.error("Failed to compensate for the removed node at path: {}", zkInstancePath, e);
}
}
@@ -215,8 +235,7 @@ private HashSet getWaitingToAddInstance(TaskDO taskDO, CuratorFramework
}
protected String buildSyncInstance(Instance instance, TaskDO taskDO) throws UnsupportedEncodingException {
- Map metaData = new HashMap<>();
- metaData.putAll(instance.getMetadata());
+ Map metaData = new HashMap<>(instance.getMetadata());
metaData.put(SkyWalkerConstants.DEST_CLUSTERID_KEY, taskDO.getDestClusterId());
metaData.put(SkyWalkerConstants.SYNC_SOURCE_KEY,
skyWalkerCacheServices.getClusterType(taskDO.getSourceClusterId()).getCode());
diff --git a/nacossync-worker/src/main/java/com/alibaba/nacossync/extension/impl/ZookeeperSyncToNacosServiceImpl.java b/nacossync-worker/src/main/java/com/alibaba/nacossync/extension/impl/ZookeeperSyncToNacosServiceImpl.java
index d2747723..27aef3bc 100644
--- a/nacossync-worker/src/main/java/com/alibaba/nacossync/extension/impl/ZookeeperSyncToNacosServiceImpl.java
+++ b/nacossync-worker/src/main/java/com/alibaba/nacossync/extension/impl/ZookeeperSyncToNacosServiceImpl.java
@@ -35,13 +35,14 @@
import org.springframework.beans.factory.annotation.Autowired;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
-import java.util.function.Predicate;
import static com.alibaba.nacossync.util.DubboConstants.ALL_SERVICE_NAME_PATTERN;
import static com.alibaba.nacossync.util.DubboConstants.DUBBO_PATH_FORMAT;
@@ -68,6 +69,8 @@
@NacosSyncService(sourceCluster = ClusterTypeEnum.ZK, destinationCluster = ClusterTypeEnum.NACOS)
public class ZookeeperSyncToNacosServiceImpl implements SyncService {
+ private static final String DEFAULT_WEIGHT = "1.0";
+
@Autowired
private MetricsManager metricsManager;
@@ -101,26 +104,18 @@ public boolean sync(TaskDO taskDO, Integer index) {
if (treeCacheMap.containsKey(taskDO.getTaskId())) {
return true;
}
+ if (!initializeTreeCache(taskDO)) {
+ return false;
+ }
- TreeCache treeCache = getTreeCache(taskDO);
NamingService destNamingService = nacosServerHolder.get(taskDO.getDestClusterId());
+ if (destNamingService == null) {
+ logAndRecordSyncError("Failed to obtain NamingService for destination clusterId: {}", taskDO.getDestClusterId(), null);
+ return false;
+ }
// 初次执行任务统一注册所有实例
registerAllInstances(taskDO, destNamingService);
- //注册ZK监听
- Objects.requireNonNull(treeCache).getListenable().addListener((client, event) -> {
- try {
-
- String path = event.getData().getPath();
- Map queryParam = parseQueryString(path);
- if (isMatch(taskDO, queryParam) && needSync(queryParam)) {
- processEvent(taskDO, destNamingService, event, path, queryParam);
- }
- } catch (Exception e) {
- log.error("event process from Zookeeper to Nacos was failed, taskId:{}", taskDO.getTaskId(), e);
- metricsManager.recordError(MetricsStatisticsType.SYNC_ERROR);
- }
-
- });
+ setupListener(taskDO, destNamingService);
} catch (Exception e) {
log.error("sync task from Zookeeper to Nacos was failed, taskId:{}", taskDO.getTaskId(), e);
metricsManager.recordError(MetricsStatisticsType.SYNC_ERROR);
@@ -128,6 +123,180 @@ public boolean sync(TaskDO taskDO, Integer index) {
}
return true;
}
+ private boolean initializeTreeCache(TaskDO taskDO) {
+ TreeCache treeCache = getTreeCache(taskDO);
+ if (treeCache == null) {
+ logAndRecordSyncError("Failed to obtain TreeCache for taskId: {}", taskDO.getTaskId(), null);
+ return false;
+ }
+ return true;
+ }
+ private void logAndRecordSyncError(String message, String taskId, Exception e) {
+ if (e != null) {
+ log.error(message, taskId, e);
+ } else {
+ log.error(message, taskId);
+ }
+ metricsManager.recordError(MetricsStatisticsType.SYNC_ERROR);
+ }
+
+ private void setupListener(TaskDO taskDO, NamingService destNamingService) {
+ TreeCache treeCache = Objects.requireNonNull(getTreeCache(taskDO));
+ treeCache.getListenable().addListener((client, event) -> {
+ try {
+ // INITIALIZED is a special event that is not triggered by the Zookeeper server
+ if(event.getData()==null){
+ log.warn("TreeCache event data is null, taskId:{}", taskDO.getTaskId());
+ return;
+ }
+ String path = event.getData().getPath();
+ Map queryParam = parseQueryString(path);
+ if (isMatch(taskDO, queryParam) && needSync(queryParam)) {
+ processEvent(taskDO, destNamingService, event, path, queryParam);
+ }
+ } catch (Exception e) {
+ logAndRecordSyncError("Event process from Zookeeper to Nacos was failed, taskId:{}", taskDO.getTaskId(), e);
+ }
+ });
+ }
+
+
+
+ public boolean delete(TaskDO taskDO) {
+ if (taskDO.getServiceName() == null) {
+ return true;
+ }
+
+ CloseableUtils.closeQuietly(treeCacheMap.get(taskDO.getTaskId()));
+
+ try {
+ NamingService destNamingService = nacosServerHolder.get(taskDO.getDestClusterId());
+ if (destNamingService == null) {
+ log.error("Failed to obtain NamingService for destination clusterId: {}", taskDO.getDestClusterId());
+ return false;
+ }
+
+ Set serviceNames = getServiceNamesToDelete(taskDO);
+ deleteInstances(serviceNames, destNamingService, taskDO);
+
+ } catch (Exception e) {
+ log.error("Delete task from Zookeeper to Nacos was failed, taskId:{}", taskDO.getTaskId(), e);
+ metricsManager.recordError(MetricsStatisticsType.DELETE_ERROR);
+ return false;
+ }
+
+ return true;
+ }
+
+ private Set getServiceNamesToDelete(TaskDO taskDO) {
+ if (!ALL_SERVICE_NAME_PATTERN.equals(taskDO.getServiceName())) {
+ return new HashSet<>(Collections.singleton(taskDO.getServiceName()));
+ } else {
+ return new HashSet<>(nacosServiceNameMap.keySet());
+ }
+ }
+
+ private void deleteInstances(Set serviceNames, NamingService destNamingService, TaskDO taskDO) {
+ for (String serviceName : serviceNames) {
+ try {
+ List allInstances = destNamingService.getAllInstances(serviceName,
+ getGroupNameOrDefault(taskDO.getGroupName()), new ArrayList<>(), true);
+ for (Instance instance : allInstances) {
+ if (needDelete(instance.getMetadata(), taskDO)) {
+ destNamingService.deregisterInstance(instance.getServiceName(),
+ getGroupNameOrDefault(taskDO.getGroupName()), instance.getIp(), instance.getPort());
+ }
+ }
+ nacosServiceNameMap.remove(serviceName);
+ } catch (NacosException e) {
+ log.error("Failed to deregister service instance for serviceName: {}", serviceName, e);
+ }
+ }
+ }
+
+ /**
+ * fetch the Path cache when the task sync
+ */
+ protected TreeCache getTreeCache(TaskDO taskDO) {
+ return treeCacheMap.computeIfAbsent(taskDO.getTaskId(), (key) -> {
+ try {
+ TreeCache treeCache = new TreeCache(zookeeperServerHolder.get(taskDO.getSourceClusterId()),
+ DUBBO_ROOT_PATH);
+ treeCache.start();
+ return treeCache;
+ } catch (Exception e) {
+ log.error("zookeeper path children cache start failed, taskId:{}", taskDO.getTaskId(), e);
+ return null;
+ }
+ });
+
+ }
+
+ /**
+ * Checks if the instance information needs to be synchronized based on the dubbo version, grouping name,
+ * and service name.
+ */
+ protected boolean isMatch(TaskDO taskDO, Map queryParam) {
+ return isVersionMatch(taskDO, queryParam) &&
+ isGroupMatch(taskDO, queryParam) &&
+ isServiceMatch(taskDO, queryParam) ||
+ isMatchAllServices(taskDO);
+ }
+
+ private boolean isVersionMatch(TaskDO task, Map queryParam) {
+ return StringUtils.isBlank(task.getVersion()) || StringUtils.equals(task.getVersion(), queryParam.get(VERSION_KEY));
+ }
+
+ private boolean isGroupMatch(TaskDO task, Map queryParam) {
+ return StringUtils.isBlank(task.getGroupName()) || StringUtils.equals(task.getGroupName(), queryParam.get(GROUP_KEY));
+ }
+
+ private boolean isServiceMatch(TaskDO task, Map queryParam) {
+ return StringUtils.isNotBlank(task.getServiceName()) && StringUtils.equals(task.getServiceName(), queryParam.get(INTERFACE_KEY));
+ }
+
+ private boolean isMatchAllServices(TaskDO task) {
+ return StringUtils.isNotBlank(task.getServiceName()) && StringUtils.equals(task.getServiceName(), ALL_SERVICE_NAME_PATTERN);
+ }
+
+
+ /**
+ * Builds a synchronized Nacos instance from Zookeeper data.
+ *
+ * @param queryParam Parameters obtained from the query string.
+ * @param ipAndPortMap IP and port information.
+ * @param taskDO Task details.
+ * @return A fully configured Nacos instance.
+ */
+ protected Instance buildSyncInstance(Map queryParam, Map ipAndPortMap, TaskDO taskDO) {
+ Instance instance = new Instance();
+ instance.setIp(ipAndPortMap.get(INSTANCE_IP_KEY));
+ instance.setPort(Integer.parseInt(ipAndPortMap.get(INSTANCE_PORT_KEY)));
+ instance.setServiceName(getServiceNameFromCache(taskDO.getTaskId(), queryParam));
+ instance.setWeight(parseWeight(queryParam));
+ instance.setHealthy(true);
+ instance.setMetadata(buildMetadata(queryParam, ipAndPortMap, taskDO));
+ return instance;
+ }
+
+
+ private double parseWeight(Map queryParam) {
+ try {
+ return Double.parseDouble(queryParam.getOrDefault(WEIGHT_KEY, DEFAULT_WEIGHT));
+ } catch (NumberFormatException e) {
+ log.error("Error parsing weight: {}", queryParam.get(WEIGHT_KEY), e);
+ return Double.parseDouble(DEFAULT_WEIGHT); // Default weight in case of error
+ }
+ }
+
+ private Map buildMetadata(Map queryParam, Map ipAndPortMap, TaskDO taskDO) {
+ Map metaData = new HashMap<>(queryParam);
+ metaData.put(PROTOCOL_KEY, ipAndPortMap.get(PROTOCOL_KEY));
+ metaData.put(SkyWalkerConstants.DEST_CLUSTERID_KEY, taskDO.getDestClusterId());
+ metaData.put(SkyWalkerConstants.SYNC_SOURCE_KEY, skyWalkerCacheServices.getClusterType(taskDO.getSourceClusterId()).getCode());
+ metaData.put(SkyWalkerConstants.SOURCE_CLUSTERID_KEY, taskDO.getSourceClusterId());
+ return metaData;
+ }
private void processEvent(TaskDO taskDO, NamingService destNamingService, TreeCacheEvent event, String path,
Map queryParam) throws NacosException {
@@ -136,8 +305,16 @@ private void processEvent(TaskDO taskDO, NamingService destNamingService, TreeCa
}
Map ipAndPortParam = parseIpAndPortString(path);
+ if (ipAndPortParam.isEmpty()) {
+ log.error("Invalid IP and Port data extracted from path: {}", path);
+ return;
+ }
Instance instance = buildSyncInstance(queryParam, ipAndPortParam, taskDO);
String serviceName = queryParam.get(INTERFACE_KEY);
+ if (serviceName == null || serviceName.isEmpty()) {
+ log.error("Service name is missing in the query parameters.");
+ return;
+ }
switch (event.getType()) {
case NODE_ADDED:
case NODE_UPDATED:
@@ -188,116 +365,6 @@ private void registerALLInstances0(TaskDO taskDO, NamingService destNamingServic
}
}
- @Override
- public boolean delete(TaskDO taskDO) {
- if (taskDO.getServiceName() == null) {
- return true;
- }
- try {
-
- CloseableUtils.closeQuietly(treeCacheMap.get(taskDO.getTaskId()));
- NamingService destNamingService = nacosServerHolder.get(taskDO.getDestClusterId());
- if (!ALL_SERVICE_NAME_PATTERN.equals(taskDO.getServiceName())) {
- if (nacosServiceNameMap.containsKey(taskDO.getServiceName())) {
- List allInstances = destNamingService.getAllInstances(
- nacosServiceNameMap.get(taskDO.getServiceName()),
- getGroupNameOrDefault(taskDO.getGroupName()), new ArrayList<>(), true);
- for (Instance instance : allInstances) {
- if (needDelete(instance.getMetadata(), taskDO)) {
- destNamingService.deregisterInstance(instance.getServiceName(),
- getGroupNameOrDefault(taskDO.getGroupName()), instance.getIp(), instance.getPort());
- }
- nacosServiceNameMap.remove(taskDO.getServiceName());
-
- }
- }
- } else {
- Set serviceNames = nacosServiceNameMap.keySet();
- for (String serviceName : serviceNames) {
-
- if (nacosServiceNameMap.containsKey(serviceName)) {
- List allInstances = destNamingService.getAllInstances(serviceName,
- getGroupNameOrDefault(taskDO.getGroupName()), new ArrayList<>(), true);
- for (Instance instance : allInstances) {
- if (needDelete(instance.getMetadata(), taskDO)) {
- destNamingService.deregisterInstance(instance.getServiceName(),
- getGroupNameOrDefault(taskDO.getGroupName()), instance.getIp(),
- instance.getPort());
- }
- nacosServiceNameMap.remove(serviceName);
-
- }
- }
- }
- }
-
-
- } catch (Exception e) {
- log.error("delete task from zookeeper to nacos was failed, taskId:{}", taskDO.getTaskId(), e);
- metricsManager.recordError(MetricsStatisticsType.DELETE_ERROR);
- return false;
- }
- return true;
- }
-
- /**
- * fetch the Path cache when the task sync
- */
- protected TreeCache getTreeCache(TaskDO taskDO) {
- return treeCacheMap.computeIfAbsent(taskDO.getTaskId(), (key) -> {
- try {
- TreeCache treeCache = new TreeCache(zookeeperServerHolder.get(taskDO.getSourceClusterId()),
- DUBBO_ROOT_PATH);
- treeCache.start();
- return treeCache;
- } catch (Exception e) {
- log.error("zookeeper path children cache start failed, taskId:{}", taskDO.getTaskId(), e);
- return null;
- }
- });
-
- }
-
- /**
- * The instance information that needs to be synchronized is matched based on the dubbo version and the grouping
- * name
- */
- protected boolean isMatch(TaskDO taskDO, Map queryParam) {
- Predicate isVersionEq = (task) -> StringUtils.isBlank(taskDO.getVersion()) || StringUtils.equals(
- task.getVersion(), queryParam.get(VERSION_KEY));
- Predicate isGroupEq = (task) -> StringUtils.isBlank(taskDO.getGroupName()) || StringUtils.equals(
- task.getGroupName(), queryParam.get(GROUP_KEY));
- Predicate isServiceEq = (task) -> StringUtils.isNotBlank(taskDO.getServiceName()) && StringUtils.equals(
- task.getServiceName(), queryParam.get(INTERFACE_KEY));
- Predicate isMatchAll = (task) -> StringUtils.isNotBlank(taskDO.getServiceName()) && StringUtils.equals(
- taskDO.getServiceName(), ALL_SERVICE_NAME_PATTERN);
- return isVersionEq.and(isGroupEq).and(isServiceEq).or(isMatchAll).test(taskDO);
- }
-
- /**
- * create Nacos service instance
- *
- * @param queryParam dubbo metadata
- * @param ipAndPortMap dubbo ip and address
- */
- protected Instance buildSyncInstance(Map queryParam, Map ipAndPortMap,
- TaskDO taskDO) {
- Instance temp = new Instance();
- temp.setIp(ipAndPortMap.get(INSTANCE_IP_KEY));
- temp.setPort(Integer.parseInt(ipAndPortMap.get(INSTANCE_PORT_KEY)));
- temp.setServiceName(getServiceNameFromCache(taskDO.getTaskId(), queryParam));
- temp.setWeight(Double.parseDouble(queryParam.get(WEIGHT_KEY) == null ? "1.0" : queryParam.get(WEIGHT_KEY)));
- temp.setHealthy(true);
-
- Map metaData = new HashMap<>(queryParam);
- metaData.put(PROTOCOL_KEY, ipAndPortMap.get(PROTOCOL_KEY));
- metaData.put(SkyWalkerConstants.DEST_CLUSTERID_KEY, taskDO.getDestClusterId());
- metaData.put(SkyWalkerConstants.SYNC_SOURCE_KEY,
- skyWalkerCacheServices.getClusterType(taskDO.getSourceClusterId()).getCode());
- metaData.put(SkyWalkerConstants.SOURCE_CLUSTERID_KEY, taskDO.getSourceClusterId());
- temp.setMetadata(metaData);
- return temp;
- }
/**
* cteate Dubbo service name
diff --git a/nacossync-worker/src/main/java/com/alibaba/nacossync/pojo/model/TaskDO.java b/nacossync-worker/src/main/java/com/alibaba/nacossync/pojo/model/TaskDO.java
index 7b6f0a8f..1b65993d 100644
--- a/nacossync-worker/src/main/java/com/alibaba/nacossync/pojo/model/TaskDO.java
+++ b/nacossync-worker/src/main/java/com/alibaba/nacossync/pojo/model/TaskDO.java
@@ -71,8 +71,4 @@ public class TaskDO implements Serializable {
*/
private String operationId;
- /**
- * current task status
- */
- private Integer status;
}
diff --git a/nacossync-worker/src/main/java/com/alibaba/nacossync/template/processor/ClusterAddProcessor.java b/nacossync-worker/src/main/java/com/alibaba/nacossync/template/processor/ClusterAddProcessor.java
index 970b12fe..5b99725e 100644
--- a/nacossync-worker/src/main/java/com/alibaba/nacossync/template/processor/ClusterAddProcessor.java
+++ b/nacossync-worker/src/main/java/com/alibaba/nacossync/template/processor/ClusterAddProcessor.java
@@ -53,7 +53,7 @@ public void process(ClusterAddRequest clusterAddRequest, ClusterAddResult cluste
Object... others) throws Exception {
ClusterDO clusterDO = new ClusterDO();
- if (null == clusterAddRequest.getConnectKeyList() || 0 == clusterAddRequest.getConnectKeyList().size()) {
+ if (null == clusterAddRequest.getConnectKeyList() || clusterAddRequest.getConnectKeyList().isEmpty()) {
throw new SkyWalkerException("集群列表不能为空!");
}
@@ -83,6 +83,7 @@ public void process(ClusterAddRequest clusterAddRequest, ClusterAddResult cluste
clusterDO.setUserName(clusterAddRequest.getUserName());
clusterDO.setPassword(clusterAddRequest.getPassword());
clusterDO.setNamespace(clusterAddRequest.getNamespace());
+ clusterDO.setClusterLevel(0);
clusterAccessService.insert(clusterDO);
}
}
diff --git a/nacossync-worker/src/main/java/com/alibaba/nacossync/template/processor/TaskDeleteProcessor.java b/nacossync-worker/src/main/java/com/alibaba/nacossync/template/processor/TaskDeleteProcessor.java
index 2f18186e..9cfd8e4e 100644
--- a/nacossync-worker/src/main/java/com/alibaba/nacossync/template/processor/TaskDeleteProcessor.java
+++ b/nacossync-worker/src/main/java/com/alibaba/nacossync/template/processor/TaskDeleteProcessor.java
@@ -14,9 +14,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package com.alibaba.nacossync.template.processor;
+import com.alibaba.nacossync.constant.SkyWalkerConstants;
import com.alibaba.nacossync.dao.TaskAccessService;
+import com.alibaba.nacossync.event.DeleteAllSubTaskEvent;
import com.alibaba.nacossync.event.DeleteTaskEvent;
import com.alibaba.nacossync.pojo.model.TaskDO;
import com.alibaba.nacossync.pojo.request.TaskDeleteRequest;
@@ -24,7 +27,6 @@
import com.alibaba.nacossync.template.Processor;
import com.google.common.eventbus.EventBus;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
@@ -34,18 +36,28 @@
@Slf4j
@Service
public class TaskDeleteProcessor implements Processor {
-
- @Autowired
- private TaskAccessService taskAccessService;
- @Autowired
- private EventBus eventBus;
-
+
+ private final TaskAccessService taskAccessService;
+
+ private final EventBus eventBus;
+
+ public TaskDeleteProcessor(TaskAccessService taskAccessService, EventBus eventBus) {
+ this.taskAccessService = taskAccessService;
+ this.eventBus = eventBus;
+ }
+
@Override
- public void process(TaskDeleteRequest taskDeleteRequest, BaseResult baseResult,
- Object... others) {
+ public void process(TaskDeleteRequest taskDeleteRequest, BaseResult baseResult, Object... others) {
TaskDO taskDO = taskAccessService.findByTaskId(taskDeleteRequest.getTaskId());
- eventBus.post(new DeleteTaskEvent(taskDO));
- log.info("删除同步任务数据之前,发出一个同步事件:" + taskDO);
+ // delete all sub task when ServiceName is all
+ if (SkyWalkerConstants.NACOS_ALL_SERVICE_NAME.equalsIgnoreCase(taskDO.getServiceName())) {
+ eventBus.post(new DeleteAllSubTaskEvent(taskDO));
+ } else {
+ eventBus.post(new DeleteTaskEvent(taskDO));
+ }
+ log.info("删除同步任务数据之前,发出一个同步事件:{}", taskDO);
taskAccessService.deleteTaskById(taskDeleteRequest.getTaskId());
}
+
+
}
diff --git a/nacossync-worker/src/main/java/com/alibaba/nacossync/template/processor/TaskUpdateProcessor.java b/nacossync-worker/src/main/java/com/alibaba/nacossync/template/processor/TaskUpdateProcessor.java
index 8b8d4e4a..327c7dc2 100644
--- a/nacossync-worker/src/main/java/com/alibaba/nacossync/template/processor/TaskUpdateProcessor.java
+++ b/nacossync-worker/src/main/java/com/alibaba/nacossync/template/processor/TaskUpdateProcessor.java
@@ -16,22 +16,17 @@
*/
package com.alibaba.nacossync.template.processor;
-import com.alibaba.nacossync.util.SkyWalkerUtil;
-import lombok.extern.slf4j.Slf4j;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
import com.alibaba.nacossync.constant.TaskStatusEnum;
import com.alibaba.nacossync.dao.TaskAccessService;
import com.alibaba.nacossync.exception.SkyWalkerException;
-import com.alibaba.nacossync.pojo.result.BaseResult;
import com.alibaba.nacossync.pojo.model.TaskDO;
import com.alibaba.nacossync.pojo.request.TaskUpdateRequest;
+import com.alibaba.nacossync.pojo.result.BaseResult;
import com.alibaba.nacossync.template.Processor;
-
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
+import com.alibaba.nacossync.util.SkyWalkerUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
/**
* @author NacosSync
@@ -43,8 +38,6 @@ public class TaskUpdateProcessor implements Processor taskIdAndOperationIdMap = new ConcurrentHashMap<>();
-
@Override
public void process(TaskUpdateRequest taskUpdateRequest, BaseResult baseResult,
Object... others) throws Exception {
@@ -63,15 +56,12 @@ public void process(TaskUpdateRequest taskUpdateRequest, BaseResult baseResult,
}
taskDO.setTaskStatus(taskUpdateRequest.getTaskStatus());
- //在id生成之前保存好操作id,可以在删除操作里面进行
- taskIdAndOperationIdMap.put(taskDO.getTaskId(),taskDO.getOperationId());
+
taskDO.setOperationId(SkyWalkerUtil.generateOperationId());
taskAccessService.addTask(taskDO);
}
- public String getTaskIdAndOperationIdMap(String taskId) {
- return taskIdAndOperationIdMap.remove(taskId);
- }
+
}
diff --git a/nacossync-worker/src/main/java/com/alibaba/nacossync/timer/CheckRunningStatusAllNacosThread.java b/nacossync-worker/src/main/java/com/alibaba/nacossync/timer/CheckRunningStatusAllNacosThread.java
new file mode 100644
index 00000000..c126e7bf
--- /dev/null
+++ b/nacossync-worker/src/main/java/com/alibaba/nacossync/timer/CheckRunningStatusAllNacosThread.java
@@ -0,0 +1,252 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.alibaba.nacossync.timer;
+
+import com.alibaba.nacos.api.naming.NamingService;
+import com.alibaba.nacos.api.naming.pojo.ListView;
+import com.alibaba.nacos.client.naming.utils.CollectionUtils;
+import com.alibaba.nacossync.constant.MetricsStatisticsType;
+import com.alibaba.nacossync.constant.TaskStatusEnum;
+import com.alibaba.nacossync.dao.TaskAccessService;
+import com.alibaba.nacossync.event.DeleteAllSubTaskEvent;
+import com.alibaba.nacossync.event.DeleteTaskEvent;
+import com.alibaba.nacossync.event.SyncTaskEvent;
+import com.alibaba.nacossync.extension.holder.NacosServerHolder;
+import com.alibaba.nacossync.monitor.MetricsManager;
+import com.alibaba.nacossync.pojo.model.TaskDO;
+import com.alibaba.nacossync.util.BatchTaskExecutor;
+import com.alibaba.nacossync.util.SkyWalkerUtil;
+import com.google.common.eventbus.EventBus;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeanUtils;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+
+/**
+ * when the database task service name is empty, check all the services in the cluster and create a synchronization
+ * task.
+ */
+@Slf4j
+public class CheckRunningStatusAllNacosThread implements Runnable {
+
+ private final Map> subTaskService = new ConcurrentHashMap<>();
+
+ private final MetricsManager metricsManager;
+
+ private final TaskAccessService taskAccessService;
+
+ private final NacosServerHolder nacosServerHolder;
+
+ private final EventBus eventBus;
+
+
+ public CheckRunningStatusAllNacosThread(MetricsManager metricsManager, TaskAccessService taskAccessService,
+ NacosServerHolder nacosServerHolder, EventBus eventBus) {
+ this.metricsManager = metricsManager;
+ this.taskAccessService = taskAccessService;
+ this.nacosServerHolder = nacosServerHolder;
+ this.eventBus = eventBus;
+ }
+
+ /**
+ * Synchronize data based on the ns level.
+ */
+ @Override
+ public void run() {
+
+ try {
+ List tasks = taskAccessService.findAllByServiceNameEqualAll();
+ if (CollectionUtils.isEmpty(tasks)) {
+ return;
+ }
+
+ // Get the set of all task IDs
+ Set taskIdSet = tasks.stream().map(TaskDO::getTaskId).collect(Collectors.toSet());
+
+ // Filter and handle sub-tasks that need to be deleted. This handles the case where tasks have been deleted
+ // but sub-tasks still exist.
+ subTaskService.entrySet().stream()
+ .filter(entry -> shouldDeleteSubTasks(entry, taskIdSet))
+ .forEach(entry -> postDeleteAllSubTaskEvent(entry.getKey()));
+
+ // Handle regular tasks
+ tasks.forEach(this::processTask);
+ } catch (Exception e) {
+ log.warn("CheckRunningStatusThread Exception", e);
+ metricsManager.recordError(MetricsStatisticsType.DISPATCHER_TASK);
+ }
+ }
+
+ /**
+ * Listens for the event of deleting all sub-tasks and handles the delete operation.
+ *
+ * @param deleteAllSubTaskEvent The event object containing the task information to be deleted.
+ */
+ public void listenerDeleteAllTaskEvent(DeleteAllSubTaskEvent deleteAllSubTaskEvent) {
+ // Retrieve the task object
+ TaskDO task = deleteAllSubTaskEvent.getTaskDO();
+
+ // Retrieve the task ID
+ String taskId = task.getTaskId();
+
+ // Remove the set of service names corresponding to the task ID from subTaskService
+ Set serviceNameSet = subTaskService.remove(taskId);
+
+ // If the set of service names is empty, return immediately
+ if (CollectionUtils.isEmpty(serviceNameSet)) {
+ return;
+ }
+
+ // Build the list of sub-tasks pending removal
+ List servicesPendingRemoval = serviceNameSet.stream()
+ .map(serviceName -> buildSubTaskDO(task, serviceName))
+ .collect(Collectors.toUnmodifiableList());
+
+ // Handle the removal of the pending sub-tasks
+ handleRemoval(servicesPendingRemoval, serviceNameSet);
+ }
+
+
+ private boolean shouldDeleteSubTasks(Map.Entry> entry, Set taskIdSet) {
+ return !taskIdSet.contains(entry.getKey()) && !entry.getValue().isEmpty();
+ }
+
+ private void postDeleteAllSubTaskEvent(String taskId) {
+ TaskDO taskDO = new TaskDO();
+ taskDO.setTaskId(taskId);
+ eventBus.post(new DeleteAllSubTaskEvent(taskDO));
+ }
+
+ /**
+ * Processes the given task by determining the services that need to be inserted and removed,
+ * and performs the corresponding operations.
+ *
+ * @param task The task object to be processed.
+ */
+ private void processTask(TaskDO task) {
+ // Retrieve the set of services for the task, creating a new set if it does not exist
+ Set serviceSet = subTaskService.computeIfAbsent(task.getTaskId(), k -> ConcurrentHashMap.newKeySet());
+
+ // Get the list of all service names associated with the task
+ List serviceNameList = getAllServiceName(task);
+
+ // Determine the services that need to be inserted (those not in the current service set)
+ List servicesPendingInsertion = serviceNameList.stream()
+ .filter(serviceName -> !serviceSet.contains(serviceName))
+ .map(serviceName -> buildSubTaskDO(task, serviceName))
+ .collect(Collectors.toUnmodifiableList());
+
+ // Determine the services that need to be removed (those in the current service set but not in the service name list)
+ List servicesPendingRemoval = serviceSet.stream()
+ .filter(serviceName -> !serviceNameList.contains(serviceName))
+ .map(serviceName -> buildSubTaskDO(task, serviceName))
+ .collect(Collectors.toUnmodifiableList());
+
+
+ // If all lists are empty, there is nothing to process
+ if (CollectionUtils.isEmpty(serviceNameList) && CollectionUtils.isEmpty(servicesPendingInsertion)
+ && CollectionUtils.isEmpty(servicesPendingRemoval)) {
+ log.debug("No service found for task: {}", task.getTaskId());
+ return;
+ }
+
+
+ // If the task status is SYNC, handle the insertion of services
+ if (TaskStatusEnum.SYNC.getCode().equals(task.getTaskStatus())) {
+ handleInsertion(servicesPendingInsertion, serviceSet);
+ }
+ // Handle the removal of services
+ handleRemoval(servicesPendingRemoval, serviceSet);
+
+ if (TaskStatusEnum.DELETE.getCode().equals(task.getTaskStatus())) {
+ List allSubTasks = serviceNameList.stream().map(serviceName -> buildSubTaskDO(task, serviceName))
+ .collect(Collectors.toList());
+ handleRemoval(allSubTasks, serviceSet);
+ }
+ }
+
+ /**
+ * Handles the insertion of services.
+ *
+ * @param servicesPendingInsertion The list of services to be inserted.
+ * @param serviceSet The set of services.
+ */
+ private void handleInsertion(List servicesPendingInsertion, Set serviceSet) {
+ BatchTaskExecutor.batchOperation(servicesPendingInsertion, t -> {
+ eventBus.post(new SyncTaskEvent(t));
+ serviceSet.add(t.getServiceName());
+ });
+ }
+ /**
+ * Handles the removal of services.
+ *
+ * @param servicesPendingRemoval The list of services to be removed.
+ * @param serviceSet The set of services.
+ */
+ private void handleRemoval(List servicesPendingRemoval, Set serviceSet) {
+ BatchTaskExecutor.batchOperation(servicesPendingRemoval, t -> {
+ eventBus.post(new DeleteTaskEvent(t));
+ serviceSet.remove(t.getServiceName());
+ });
+ }
+ /**
+ * Builds a sub-task object for the given task and service name.
+ *
+ * @param serviceName The service name.
+ * @return The constructed sub-task object.
+ */
+ private static TaskDO buildSubTaskDO(TaskDO taskDO, String serviceName) {
+ TaskDO task = new TaskDO();
+
+ BeanUtils.copyProperties(taskDO, task);
+ task.setTaskId(SkyWalkerUtil.generateTaskId(serviceName, taskDO.getGroupName(), taskDO.getSourceClusterId(),
+ taskDO.getDestClusterId()));
+ task.setServiceName(serviceName);
+ return task;
+ }
+
+ /**
+ * Retrieves all service names associated with the given task.
+ *
+ * @return A list of service names.
+ */
+ private List getAllServiceName(TaskDO taskDO) {
+ NamingService namingService = nacosServerHolder.get(taskDO.getSourceClusterId());
+ if (namingService == null) {
+ log.warn("naming service is null or not found, clusterId:{}", taskDO.getSourceClusterId());
+ return Collections.emptyList();
+ }
+ try {
+ ListView servicesOfServer = namingService.getServicesOfServer(0, Integer.MAX_VALUE,
+ taskDO.getGroupName());
+ return servicesOfServer.getData();
+ } catch (Exception e) {
+ log.error("query service list failure", e);
+ }
+
+ return Collections.emptyList();
+ }
+
+
+
+}
diff --git a/nacossync-worker/src/main/java/com/alibaba/nacossync/timer/CheckRunningStatusAllThread.java b/nacossync-worker/src/main/java/com/alibaba/nacossync/timer/CheckRunningStatusAllThread.java
deleted file mode 100644
index bd332220..00000000
--- a/nacossync-worker/src/main/java/com/alibaba/nacossync/timer/CheckRunningStatusAllThread.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.alibaba.nacossync.timer;
-
-import com.alibaba.nacos.api.naming.NamingService;
-import com.alibaba.nacos.api.naming.pojo.ListView;
-import com.alibaba.nacos.client.naming.utils.CollectionUtils;
-import com.alibaba.nacossync.cache.SkyWalkerCacheServices;
-import com.alibaba.nacossync.constant.MetricsStatisticsType;
-import com.alibaba.nacossync.constant.TaskStatusEnum;
-import com.alibaba.nacossync.dao.TaskAccessService;
-import com.alibaba.nacossync.extension.holder.NacosServerHolder;
-import com.alibaba.nacossync.monitor.MetricsManager;
-import com.alibaba.nacossync.pojo.model.TaskDO;
-import com.google.common.eventbus.EventBus;
-import lombok.extern.slf4j.Slf4j;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.stream.Collectors;
-
-/**
- * when the database task service name is empty, check all the services in the cluster and create a synchronization task.
- * @ClassName: CheckRunningStatusAllThread
- * @Author: ChenHao26
- * @Date: 2022/7/20 10:30
- * @Description: muti sync data
- */
-@Slf4j
-public class CheckRunningStatusAllThread implements Runnable{
-
- private MetricsManager metricsManager;
-
- private SkyWalkerCacheServices skyWalkerCacheServices;
-
- private TaskAccessService taskAccessService;
-
- private EventBus eventBus;
-
- private NacosServerHolder nacosServerHolder;
-
- private FastSyncHelper fastSyncHelper;
-
- public CheckRunningStatusAllThread(MetricsManager metricsManager, SkyWalkerCacheServices skyWalkerCacheServices,
- TaskAccessService taskAccessService, EventBus eventBus, NacosServerHolder nacosServerHolder,
- FastSyncHelper fastSyncHelper) {
- this.metricsManager = metricsManager;
- this.skyWalkerCacheServices = skyWalkerCacheServices;
- this.taskAccessService = taskAccessService;
- this.eventBus = eventBus;
- this.nacosServerHolder = nacosServerHolder;
- this.fastSyncHelper = fastSyncHelper;
- }
-
- /**
- * 根据ns级别进行数据同步
- */
- @Override
- public void run() {
- Long startTime = System.currentTimeMillis();
- try {
- List taskDOS = taskAccessService.findServiceNameIsNull()
- .stream().filter(t -> t.getStatus() == null || t.getStatus() == 0)
- .collect(Collectors.toList());
- if (CollectionUtils.isEmpty(taskDOS)) {
- return;
- }
- for (TaskDO taskDO : taskDOS) {
- List serviceNameList = getServiceNameList(taskDO);
- if (CollectionUtils.isEmpty(serviceNameList)) {
- continue;
- }
-
- //如果是null,证明此时没有处理完成
- List filterService = serviceNameList.stream()
- .filter(serviceName -> skyWalkerCacheServices.getFinishedTask(taskDO.getTaskId() + serviceName ) == null)
- .collect(Collectors.toList());
-
- if (CollectionUtils.isEmpty(filterService)) {
- continue;
- }
-
- // 当删除任务后,此时任务的状态为DELETE,不会执行数据同步
- if (TaskStatusEnum.SYNC.getCode().equals(taskDO.getTaskStatus())) {
- fastSyncHelper.syncWithThread(taskDO, filterService);
- }
- }
- }catch (Exception e) {
- log.warn("CheckRunningStatusThread Exception ", e);
- }
- metricsManager.record(MetricsStatisticsType.DISPATCHER_TASK, System.currentTimeMillis() - startTime);
- }
-
- /**
- * get serviceName list.
- * @param taskDO task info
- * @return service list or empty list
- */
- private List getServiceNameList(TaskDO taskDO) {
- NamingService namingService = nacosServerHolder.get(taskDO.getSourceClusterId());
- try {
- ListView servicesOfServer = namingService.getServicesOfServer(0, Integer.MAX_VALUE,
- taskDO.getGroupName());
- return servicesOfServer.getData();
- } catch (Exception e) {
- log.error("query service list failure",e);
- }
-
- return Collections.emptyList();
- }
-}
diff --git a/nacossync-worker/src/main/java/com/alibaba/nacossync/timer/FastSyncHelper.java b/nacossync-worker/src/main/java/com/alibaba/nacossync/timer/FastSyncHelper.java
deleted file mode 100644
index f379bf1a..00000000
--- a/nacossync-worker/src/main/java/com/alibaba/nacossync/timer/FastSyncHelper.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.alibaba.nacossync.timer;
-
-import com.alibaba.nacossync.cache.SkyWalkerCacheServices;
-import com.alibaba.nacossync.constant.MetricsStatisticsType;
-import com.alibaba.nacossync.extension.SyncManagerService;
-import com.alibaba.nacossync.monitor.MetricsManager;
-import com.alibaba.nacossync.pojo.model.TaskDO;
-import com.alibaba.nacossync.util.Tuple;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.BeanUtils;
-import org.springframework.stereotype.Service;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.function.Consumer;
-
-import static com.alibaba.nacossync.constant.SkyWalkerConstants.MAX_THREAD_NUM;
-
-/**
- * multi-threaded synchronization Task DO.
- *
- * @ClassName: FastSyncHelper
- * @Author: ChenHao26
- * @Date: 2022/7/19 17:02
- * @Description:
- */
-@Service
-@Slf4j
-public class FastSyncHelper {
-
- private final SkyWalkerCacheServices skyWalkerCacheServices;
-
- private final MetricsManager metricsManager;
-
- private final SyncManagerService syncManagerService;
-
-
- private final ExecutorService executorService = Executors.newFixedThreadPool(MAX_THREAD_NUM);
-
- public FastSyncHelper(SkyWalkerCacheServices skyWalkerCacheServices, MetricsManager metricsManager,
- SyncManagerService syncManagerService) {
- this.skyWalkerCacheServices = skyWalkerCacheServices;
- this.metricsManager = metricsManager;
- this.syncManagerService = syncManagerService;
- }
-
-
- /**
- * every 200 services start a thread to perform synchronization.
- *
- * @param taskDOS task list
- */
- public void syncWithThread(List taskDOS, Consumer timeSyncInvoke) {
- sync(taskDOS, tuple -> {
- for (TaskDO task : tuple.getT2()) {
- //执行兜底的定时同步
- timeSyncInvoke.accept(task);
- }
- });
- }
-
-
- /**
- * every 200 services start a thread to perform synchronization.
- *
- * @param taskDO task info
- * @param filterServices filterServices
- */
- public void syncWithThread(TaskDO taskDO, List filterServices) {
- sync(filterServices, tuple -> {
- // 执行数据同步
- for (String serviceName : tuple.getT2()) {
- syncByIndex(taskDO, serviceName, tuple.getT1());
- }
- });
- }
-
- public void sync(List items, Consumer>> itemConsumer) {
- long startTime = System.currentTimeMillis();
- List>> taskGroupList = averageAssign(items, MAX_THREAD_NUM);
-
- // 等待所有任务完成
- CompletableFuture allTasks = CompletableFuture.allOf(taskGroupList.stream()
- .map(tuple -> CompletableFuture.runAsync(() -> performSync(tuple, itemConsumer), executorService))
- .toArray(CompletableFuture[]::new));
- try {
- allTasks.get();
- } catch (Exception e) {
- e.printStackTrace();
- }
-
- log.info("新增同步任务数量 {}, 执行耗时:{}ms", items.size(), System.currentTimeMillis() - startTime);
- }
-
- private void performSync(Tuple> tuple, Consumer>> itemConsumer) {
- if (tuple == null || tuple.getT2() == null || tuple.getT2().isEmpty()) {
- return;
- }
- itemConsumer.accept(tuple);
-
- }
-
-
- private void syncByIndex(TaskDO taskDO, String serviceName, int index) {
- long startTime = System.currentTimeMillis();
- TaskDO task = new TaskDO();
- BeanUtils.copyProperties(taskDO, task);
- task.setServiceName(serviceName);
- task.setOperationId(taskDO.getTaskId() + serviceName);
- if (syncManagerService.sync(task, index)) {
- skyWalkerCacheServices.addFinishedTask(task);
- log.info("sync thread : {} sync finish ,time consuming :{}", Thread.currentThread().getId(),
- System.currentTimeMillis() - startTime);
- metricsManager.record(MetricsStatisticsType.SYNC_TASK_RT, System.currentTimeMillis() - startTime);
- } else {
- log.warn("listenerSyncTaskEvent sync failure.");
- }
- }
-
- /**
- * 将一个List均分成n个list,主要通过偏移量来实现的
- *
- * @param source 源集合
- * @param limit 最大值
- * @return
- */
- public static List>> averageAssign(List source, int limit) {
- if (null == source || source.isEmpty()) {
- return Collections.emptyList();
- }
- int size = source.size();
- List>> result = new ArrayList<>();
- // 通过减去1并加1,我们可以确保将多余的元素放在最后一个子列表中。在上述示例中,计算结果为 ((10 - 1) / 3 + 1) = 4,我们创建了4个子列表,其中最后一个子列表包含2个元素,而不是1个。这样可以更均匀地分配源列表的元素.
- int listCount = (int) Math.ceil((double) source.size() / limit); // 计算子列表数量,使用 Math.ceil 向上取整,确保多余的元素放在最后一个子列表中
- int remainder = source.size() % listCount; // 计算多余的元素数量
- int assigned = 0; // 记录已分配的元素索引
- for (int i = 0; i < listCount; i++) {
- int sublistSize = size / listCount + (remainder-- > 0 ? 1 : 0); // 计算子列表大小,平均分配元素,并在有多余元素时将其分配到子列表中
- List sublist = source.subList(assigned, assigned + sublistSize); // 获取子列表
- result.add(Tuple.of(i, sublist)); // 将子列表添加到结果列表
- assigned += sublistSize; // 更新已分配的元素索引
- }
-
- return result;
- }
-
-
-}
diff --git a/nacossync-worker/src/main/java/com/alibaba/nacossync/timer/QuerySyncTaskTimer.java b/nacossync-worker/src/main/java/com/alibaba/nacossync/timer/QuerySyncTaskTimer.java
index b840ac85..9977043f 100644
--- a/nacossync-worker/src/main/java/com/alibaba/nacossync/timer/QuerySyncTaskTimer.java
+++ b/nacossync-worker/src/main/java/com/alibaba/nacossync/timer/QuerySyncTaskTimer.java
@@ -22,7 +22,6 @@
import com.alibaba.nacossync.dao.TaskAccessService;
import com.alibaba.nacossync.event.DeleteTaskEvent;
import com.alibaba.nacossync.event.SyncTaskEvent;
-import com.alibaba.nacossync.extension.SyncManagerService;
import com.alibaba.nacossync.extension.holder.NacosServerHolder;
import com.alibaba.nacossync.monitor.MetricsManager;
import com.alibaba.nacossync.pojo.model.TaskDO;
@@ -32,6 +31,7 @@
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Service;
+import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@@ -59,12 +59,6 @@ public class QuerySyncTaskTimer implements CommandLineRunner {
@Autowired
private NacosServerHolder nacosServerHolder;
-
- @Autowired
- private SyncManagerService syncManagerService;
-
- @Autowired
- private FastSyncHelper fastSyncHelper;
@Override
public void run(String... args) {
@@ -72,8 +66,8 @@ public void run(String... args) {
scheduledExecutorService.scheduleWithFixedDelay(new CheckRunningStatusThread(), 0, 3000,
TimeUnit.MILLISECONDS);
- scheduledExecutorService.scheduleWithFixedDelay(new CheckRunningStatusAllThread(metricsManager,skyWalkerCacheServices,
- taskAccessService,eventBus, nacosServerHolder, fastSyncHelper), 0, 3000,
+ scheduledExecutorService.scheduleWithFixedDelay(new CheckRunningStatusAllNacosThread(metricsManager,
+ taskAccessService, nacosServerHolder, eventBus), 0, 3000,
TimeUnit.MILLISECONDS);
}
@@ -85,7 +79,7 @@ public void run() {
Long start = System.currentTimeMillis();
try {
- Iterable taskDOS = taskAccessService.findAll();
+ List taskDOS = taskAccessService.findAllByServiceNameNotEqualAll();
taskDOS.forEach(taskDO -> {
diff --git a/nacossync-worker/src/main/java/com/alibaba/nacossync/util/BatchTaskExecutor.java b/nacossync-worker/src/main/java/com/alibaba/nacossync/util/BatchTaskExecutor.java
new file mode 100644
index 00000000..74dce015
--- /dev/null
+++ b/nacossync-worker/src/main/java/com/alibaba/nacossync/util/BatchTaskExecutor.java
@@ -0,0 +1,76 @@
+package com.alibaba.nacossync.util;
+
+import com.alibaba.nacos.client.naming.utils.CollectionUtils;
+import com.alibaba.nacossync.pojo.model.TaskDO;
+import com.google.common.base.Stopwatch;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+@Slf4j
+public class BatchTaskExecutor {
+
+ private static final int MAX_THREAD_NUM = 200;
+ private static final ExecutorService executorService = Executors.newFixedThreadPool(MAX_THREAD_NUM);
+
+ /**
+ * 批量操作方法
+ *
+ * @param items 任务列表
+ * @param operation 要执行的操作
+ */
+ public static void batchOperation(List items, Consumer operation) {
+ Stopwatch stopwatch = Stopwatch.createStarted();
+
+ List>> taskGroupList = averageAssign(items, MAX_THREAD_NUM);
+
+ // 创建一个包含所有任务的 CompletableFuture
+ CompletableFuture>[] futures = taskGroupList.stream().map(tuple -> CompletableFuture.runAsync(() -> {
+ for (TaskDO taskDO : tuple.getT2()) {
+ operation.accept(taskDO);
+ }
+ }, executorService)).toArray(CompletableFuture[]::new);
+
+ try {
+ // 等待所有任务完成
+ CompletableFuture.allOf(futures).join();
+ } catch (Exception e) {
+ log.error("Error occurred during sync operation", e);
+ }
+
+ log.debug("Total sync tasks: {}, Execution time: {} ms", items.size(), stopwatch.elapsed(TimeUnit.MILLISECONDS));
+ }
+
+ /**
+ * 将一个List均分成n个list, 主要通过偏移量来实现的
+ *
+ * @param source 源集合
+ * @param limit 最大值
+ * @return 均分后的列表
+ */
+ private static List>> averageAssign(List source, int limit) {
+ if (CollectionUtils.isEmpty(source)) {
+ return Collections.emptyList();
+ }
+
+ int size = source.size();
+ int listCount = (int) Math.ceil((double) size / limit); // Calculate the number of sublist
+ int remainder = size % listCount; // Calculate the number of remaining elements after even distribution
+ List>> result = new ArrayList<>(listCount); // Initialize the result list with the expected size
+
+ for (int i = 0, assigned = 0; i < listCount; i++) {
+ int sublistSize = size / listCount + (remainder-- > 0 ? 1 : 0); // Determine the size of each sublist, distribute remaining elements
+ List sublist = new ArrayList<>(source.subList(assigned, assigned + sublistSize)); // Create the sublist
+ result.add(Tuple.of(i, sublist)); // Add the sublist to the result
+ assigned += sublistSize; // Update the assigned index
+ }
+
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/nacossync-worker/src/main/resources/static/js/main.b73436b5.js b/nacossync-worker/src/main/resources/static/js/main.b73436b5.js
index c71dada4..a597961f 100644
--- a/nacossync-worker/src/main/resources/static/js/main.b73436b5.js
+++ b/nacossync-worker/src/main/resources/static/js/main.b73436b5.js
@@ -325,4 +325,4 @@ var t;e.defineLocale("zh-tw",{months:"一月_二月_三月_四月_五月_六月_
* @author Feross Aboukhadijeh
* @license MIT
*/
-e.exports=function(e){return null!=e&&null!=e.constructor&&"function"==typeof e.constructor.isBuffer&&e.constructor.isBuffer(e)}},function(e,t,n){"use strict";var r=n(90),a=n(20),o=n(463),i=n(464);function s(e){this.defaults=e,this.interceptors={request:new o,response:new o}}s.prototype.request=function(e){"string"==typeof e&&(e=a.merge({url:arguments[0]},arguments[1])),(e=a.merge(r,{method:"get"},this.defaults,e)).method=e.method.toLowerCase();var t=[i,void 0],n=Promise.resolve(e);for(this.interceptors.request.forEach(function(e){t.unshift(e.fulfilled,e.rejected)}),this.interceptors.response.forEach(function(e){t.push(e.fulfilled,e.rejected)});t.length;)n=n.then(t.shift(),t.shift());return n},a.forEach(["delete","get","head","options"],function(n){s.prototype[n]=function(e,t){return this.request(a.merge(t||{},{method:n,url:e}))}}),a.forEach(["post","put","patch"],function(r){s.prototype[r]=function(e,t,n){return this.request(a.merge(n||{},{method:r,url:e,data:t}))}}),e.exports=s},function(e,t,n){"use strict";var a=n(20);e.exports=function(n,r){a.forEach(n,function(e,t){t!==r&&t.toUpperCase()===r.toUpperCase()&&(n[r]=e,delete n[t])})}},function(e,t,n){"use strict";var a=n(286);e.exports=function(e,t,n){var r=n.config.validateStatus;n.status&&r&&!r(n.status)?t(a("Request failed with status code "+n.status,n.config,null,n.request,n)):e(n)}},function(e,t,n){"use strict";e.exports=function(e,t,n,r,a){return e.config=t,n&&(e.code=n),e.request=r,e.response=a,e}},function(e,t,n){"use strict";var a=n(20);function o(e){return encodeURIComponent(e).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+").replace(/%5B/gi,"[").replace(/%5D/gi,"]")}e.exports=function(e,t,n){if(!t)return e;var r,t=n?n(t):a.isURLSearchParams(t)?t.toString():(r=[],a.forEach(t,function(e,t){null!=e&&(a.isArray(e)?t+="[]":e=[e],a.forEach(e,function(e){a.isDate(e)?e=e.toISOString():a.isObject(e)&&(e=JSON.stringify(e)),r.push(o(t)+"="+o(e))}))}),r.join("&"));return t&&(e+=(-1===e.indexOf("?")?"?":"&")+t),e}},function(e,t,n){"use strict";var a=n(20),o=["age","authorization","content-length","content-type","etag","expires","from","host","if-modified-since","if-unmodified-since","last-modified","location","max-forwards","proxy-authorization","referer","retry-after","user-agent"];e.exports=function(e){var t,n,r={};return e&&a.forEach(e.split("\n"),function(e){n=e.indexOf(":"),t=a.trim(e.substr(0,n)).toLowerCase(),n=a.trim(e.substr(n+1)),t&&(r[t]&&0<=o.indexOf(t)||(r[t]="set-cookie"===t?(r[t]||[]).concat([n]):r[t]?r[t]+", "+n:n))}),r}},function(e,t,n){"use strict";var r,a,o,i=n(20);function s(e){return a&&(o.setAttribute("href",e),e=o.href),o.setAttribute("href",e),{href:o.href,protocol:o.protocol?o.protocol.replace(/:$/,""):"",host:o.host,search:o.search?o.search.replace(/^\?/,""):"",hash:o.hash?o.hash.replace(/^#/,""):"",hostname:o.hostname,port:o.port,pathname:"/"===o.pathname.charAt(0)?o.pathname:"/"+o.pathname}}e.exports=i.isStandardBrowserEnv()?(a=/(msie|trident)/i.test(navigator.userAgent),o=document.createElement("a"),r=s(window.location.href),function(e){e=i.isString(e)?s(e):e;return e.protocol===r.protocol&&e.host===r.host}):function(){return!0}},function(e,t,n){"use strict";var s=n(20);e.exports=s.isStandardBrowserEnv()?{write:function(e,t,n,r,a,o){var i=[];i.push(e+"="+encodeURIComponent(t)),s.isNumber(n)&&i.push("expires="+new Date(n).toGMTString()),s.isString(r)&&i.push("path="+r),s.isString(a)&&i.push("domain="+a),!0===o&&i.push("secure"),document.cookie=i.join("; ")},read:function(e){e=document.cookie.match(new RegExp("(^|;\\s*)("+e+")=([^;]*)"));return e?decodeURIComponent(e[3]):null},remove:function(e){this.write(e,"",Date.now()-864e5)}}:{write:function(){},read:function(){return null},remove:function(){}}},function(e,t,n){"use strict";var r=n(20);function a(){this.handlers=[]}a.prototype.use=function(e,t){return this.handlers.push({fulfilled:e,rejected:t}),this.handlers.length-1},a.prototype.eject=function(e){this.handlers[e]&&(this.handlers[e]=null)},a.prototype.forEach=function(t){r.forEach(this.handlers,function(e){null!==e&&t(e)})},e.exports=a},function(e,t,n){"use strict";var r=n(20),a=n(465),o=n(287),i=n(90),s=n(466),l=n(467);function u(e){e.cancelToken&&e.cancelToken.throwIfRequested()}e.exports=function(t){return u(t),t.baseURL&&!s(t.url)&&(t.url=l(t.baseURL,t.url)),t.headers=t.headers||{},t.data=a(t.data,t.headers,t.transformRequest),t.headers=r.merge(t.headers.common||{},t.headers[t.method]||{},t.headers||{}),r.forEach(["delete","get","head","post","put","patch","common"],function(e){delete t.headers[e]}),(t.adapter||i.adapter)(t).then(function(e){return u(t),e.data=a(e.data,e.headers,t.transformResponse),e},function(e){return o(e)||(u(t),e&&e.response&&(e.response.data=a(e.response.data,e.response.headers,t.transformResponse))),Promise.reject(e)})}},function(e,t,n){"use strict";var r=n(20);e.exports=function(t,n,e){return r.forEach(e,function(e){t=e(t,n)}),t}},function(e,t,n){"use strict";e.exports=function(e){return/^([a-z][a-z\d\+\-\.]*:)?\/\//i.test(e)}},function(e,t,n){"use strict";e.exports=function(e,t){return t?e.replace(/\/+$/,"")+"/"+t.replace(/^\/+/,""):e}},function(e,t,n){"use strict";var r=n(288);function a(e){if("function"!=typeof e)throw new TypeError("executor must be a function.");var t;this.promise=new Promise(function(e){t=e});var n=this;e(function(e){n.reason||(n.reason=new r(e),t(n.reason))})}a.prototype.throwIfRequested=function(){if(this.reason)throw this.reason},a.source=function(){var t;return{token:new a(function(e){t=e}),cancel:t}},e.exports=a},function(e,t,n){"use strict";e.exports=function(t){return function(e){return t.apply(null,e)}}},function(e,t,n){"use strict";t.__esModule=!0,t.withContext=void 0;var h=d(n(3)),m=d(n(8)),o=d(n(4)),i=d(n(5)),r=d(n(6)),_=d(n(0)),l=d(n(11)),a=d(n(1)),y=d(n(27)),u=d(n(10)),s=n(7),g=d(n(289));function d(e){return e&&e.__esModule?e:{default:e}}var c,f=u.default.config,p=void 0,v={},r=(c=_.default.Component,(0,r.default)(b,c),b.prototype.componentWillUnmount=function(){var e,t=this.props.timeoutId;t in v&&(e=v[t],clearTimeout(e),delete v[t])},b.prototype.render=function(){var e=this.props,t=e.prefix,n=e.type,r=e.title,a=e.content,o=e.align,i=e.offset,s=e.hasMask,l=e.afterClose,u=e.animation,d=e.overlayProps,c=(e.timeoutId,e.className),f=e.style,p=(0,m.default)(e,["prefix","type","title","content","align","offset","hasMask","afterClose","animation","overlayProps","timeoutId","className","style"]),e=this.state.visible;return _.default.createElement(y.default,(0,h.default)({},d,{prefix:t,animation:u,visible:e,align:o,offset:i,hasMask:s,afterClose:l}),_.default.createElement(g.default,(0,h.default)({},p,{prefix:t,visible:!0,type:n,shape:"toast",title:r,style:f,className:t+"message-wrapper "+c,onClose:this.handleClose}),a))},r=n=b,n.contextTypes={prefix:a.default.string},n.propTypes={prefix:a.default.string,type:a.default.string,title:a.default.node,content:a.default.node,align:a.default.string,offset:a.default.array,hasMask:a.default.bool,afterClose:a.default.func,animation:a.default.oneOfType([a.default.object,a.default.bool]),overlayProps:a.default.object,onClose:a.default.func,timeoutId:a.default.string,style:a.default.object,className:a.default.string},n.defaultProps={prefix:"next-",align:"tc tc",offset:[0,30],hasMask:!1,animation:{in:"pulse",out:"zoomOut"},style:{},className:""},r);function b(){var e,t;(0,o.default)(this,b);for(var n=arguments.length,r=Array(n),a=0;a 16.8.0")},p.prototype.validate=function(e,t){this.validateCallback(e,t)},p.prototype.reset=function(e){var t=1e.length)&&(t=e.length);for(var n=0,r=new Array(t);n=r.length)return n;var o=r[a],a=e(t&&t[o],n,r,a+1);if(!t){var i=isNaN(o)?{}:[];return i[o]=a,i}if(Array.isArray(t)){i=[].concat(t);return i[o]=a,i}return(0,l.default)({},t,(0,s.default)({},o,a))};t=function(){};void 0!==e&&e.env;n.warning=t}.call(this,a(284))},function(e,t,n){"use strict";t.__esModule=!0,t.cloneAndAddKey=function(e){if(e&&(0,a.isValidElement)(e)){var t=e.key||"error";return(0,a.cloneElement)(e,{key:t})}return e},t.scrollToFirstError=function(e){var t=e.errorsGroup,n=e.options,r=e.instance;if(t&&n.scrollToFirstError){var a,o=void 0,i=void 0;for(a in t)if(t.hasOwnProperty(a)){var s=u.default.findDOMNode(r[a]);if(!s)return;var l=s.offsetTop;(void 0===i||l), use ), use or
instead of.'),L.default.cloneElement(e,{className:n,size:c||S(a)})}return(0,k.isValidElement)(e)?e:L.default.createElement("span",{className:r+"btn-helper"},e)}),d=d,u=(0,b.default)({},T.obj.pickOthers(Object.keys(D.propTypes),y),{type:o,disabled:p,onClick:h,className:(0,x.default)(u)});return"button"!==d&&(delete u.type,u.disabled&&(delete u.onClick,u.href&&delete u.href)),L.default.createElement(d,(0,b.default)({},u,{dir:_?"rtl":void 0,onMouseUp:this.onMouseUp,ref:this.buttonRefHandler}),t,m)},r=n=D,n.propTypes=(0,b.default)({},s.default.propTypes,{prefix:a.default.string,rtl:a.default.bool,type:a.default.oneOf(["primary","secondary","normal"]),size:a.default.oneOf(["small","medium","large"]),icons:a.default.shape({loading:a.default.node}),iconSize:a.default.oneOfType([a.default.oneOf(["xxs","xs","small","medium","large","xl","xxl","xxxl","inherit"]),a.default.number]),htmlType:a.default.oneOf(["submit","reset","button"]),component:a.default.oneOf(["button","a","div","span"]),loading:a.default.bool,ghost:a.default.oneOf([!0,!1,"light","dark"]),text:a.default.bool,warning:a.default.bool,disabled:a.default.bool,onClick:a.default.func,className:a.default.string,onMouseUp:a.default.func,children:a.default.node}),n.defaultProps={prefix:"next-",type:"normal",size:"medium",icons:{},htmlType:"button",component:"button",loading:!1,ghost:!1,text:!1,warning:!1,disabled:!1,onClick:function(){}},r);function D(){var e,t;(0,o.default)(this,D);for(var n=arguments.length,r=Array(n),a=0;as&&!u&&(e=e.slice(0,s),r=S.default.createElement(m.default,{key:"_count",type:"primary",size:c,animation:!1},l(f,p))),0x',"Tag"),"readonly"!==n&&"interactive"!==n||a.log.warning("Warning: [ shape="+n+" ] is deprecated at [ Tag ]"),"secondary"===r&&a.log.warning("Warning: [ type=secondary ] is deprecated at [ Tag ]"),["count","marked","value","onChange"].forEach(function(e){e in t&&a.log.warning("Warning: [ "+e+" ] is deprecated at [ Tag ]")}),("selected"in t||"defaultSelected"in t)&&a.log.warning("Warning: [ selected|defaultSelected ] is deprecated at [ Tag ], use [ checked|defaultChecked ] at [ Tag.Selectable ] instead of it"),"closed"in t&&a.log.warning("Warning: [ closed ] is deprecated at [ Tag ], use [ onClose ] at [ Tag.Closeable ] instead of it"),"onSelect"in t&&e("onSelect","","Tag"),"afterClose"in t&&a.log.warning("Warning: [ afterClose ] is deprecated at [ Tag ], use [ afterClose ] at [ Tag.Closeable ] instead of it"),t}});o.Group=r.default.config(i.default),o.Selectable=r.default.config(s.default),o.Closable=r.default.config(n.default),o.Closeable=o.Closable,t.default=o,e.exports=t.default},function(e,t,n){"use strict";t.__esModule=!0;var o=f(n(3)),i=f(n(8)),r=f(n(4)),a=f(n(5)),s=f(n(6)),l=n(0),u=f(l),d=f(n(1)),c=f(n(9));function f(e){return e&&e.__esModule?e:{default:e}}var p,s=(p=l.Component,(0,s.default)(h,p),h.prototype.render=function(){var e=this.props,t=e.className,n=e.prefix,r=e.children,a=e.rtl,e=(0,i.default)(e,["className","prefix","children","rtl"]),t=(0,c.default)((n||"next-")+"tag-group",t);return u.default.createElement("div",(0,o.default)({className:t,dir:a?"rtl":void 0},e),r)},s=l=h,l.propTypes={prefix:d.default.string,className:d.default.any,children:d.default.node,rtl:d.default.bool},l.defaultProps={prefix:"next-",rtl:!1},s);function h(){return(0,r.default)(this,h),(0,a.default)(this,p.apply(this,arguments))}s.displayName="Group",t.default=s,e.exports=t.default},function(e,t,n){"use strict";t.__esModule=!0;var r=h(n(3)),a=h(n(4)),o=h(n(5)),i=h(n(6)),s=n(0),l=h(s),u=h(n(1)),d=h(n(9)),c=n(13),f=n(7),p=h(n(94));function h(e){return e&&e.__esModule?e:{default:e}}var m,n=f.func.noop,_=f.func.bindCtx,i=(m=s.Component,(0,i.default)(y,m),y.getDerivedStateFromProps=function(e,t){return void 0!==e.checked&&e.checked!==t.checked?{checked:e.checked}:null},y.prototype.handleClick=function(e){if(e&&e.preventDefault(),this.props.disabled)return!1;var t=this.state.checked;this.setState({checked:!t}),this.props.onChange(!t,e)},y.prototype.render=function(){var e=f.obj.pickOthers(["checked","defaultChecked","onChange","className","_shape","closable"],this.props),t=("checked"in this.props?this.props:this.state).checked,n=(0,d.default)(this.props.className,{checked:t});return l.default.createElement(p.default,(0,r.default)({},e,{role:"checkbox",_shape:"checkable","aria-checked":t,className:n,onClick:this.handleClick}))},i=s=y,s.propTypes={checked:u.default.bool,defaultChecked:u.default.bool,onChange:u.default.func,disabled:u.default.bool,className:u.default.any},s.defaultProps={onChange:n},i);function y(e){(0,a.default)(this,y);var t=(0,o.default)(this,m.call(this,e));return t.state={checked:"checked"in e?e.checked:e.defaultChecked||!1},_(t,["handleClick"]),t}i.displayName="Selectable",t.default=(0,c.polyfill)(i),e.exports=t.default},function(e,t,n){"use strict";t.__esModule=!0;var c=l(n(3)),f=l(n(8)),r=l(n(4)),a=l(n(5)),o=l(n(6)),i=n(0),p=l(i),s=l(n(1)),h=l(n(94));function l(e){return e&&e.__esModule?e:{default:e}}var u,o=(u=i.Component,(0,o.default)(d,u),d.prototype.render=function(){var e=this.props,t=e.disabled,n=e.className,r=e.closeArea,a=e.onClose,o=e.afterClose,i=e.onClick,s=e.type,l=e.size,u=e.children,d=e.rtl,e=(0,f.default)(e,["disabled","className","closeArea","onClose","afterClose","onClick","type","size","children","rtl"]);return p.default.createElement(h.default,(0,c.default)({},e,{rtl:d,disabled:t,className:n,closeArea:r,onClose:a,afterClose:o,onClick:i,type:s,size:l,closable:!0}),u)},o=i=d,i.propTypes={disabled:s.default.bool,className:s.default.any,closeArea:s.default.oneOf(["tag","tail"]),onClose:s.default.func,afterClose:s.default.func,onClick:s.default.func,type:s.default.oneOf(["normal","primary"]),size:s.default.oneOf(["small","medium","large"]),children:s.default.any,rtl:s.default.bool},i.defaultProps={disabled:!1,type:"normal"},o);function d(){return(0,r.default)(this,d),(0,a.default)(this,u.apply(this,arguments))}o.displayName="Closeable",t.default=o,e.exports=t.default},function(e,t,n){"use strict";t.__esModule=!0,t.default=void 0;var a=f(n(3)),o=f(n(8)),i=f(n(4)),s=f(n(5)),r=f(n(6)),l=f(n(0)),u=f(n(1)),d=f(n(297)),c=f(n(14));function f(e){return e&&e.__esModule?e:{default:e}}function p(e){e.preventDefault()}var h,r=(h=d.default,(0,r.default)(m,h),m.prototype.render=function(){var e=this.props,t=e.showToggle,n=(0,o.default)(e,["showToggle"]),r=this.state,e=r.hint,r=r.htmlType,e=t?l.default.createElement(c.default,{type:e,onClick:this.toggleEye,onMouseDown:p}):null;return l.default.createElement(d.default,(0,a.default)({},n,{extra:e,htmlType:r}))},r=n=m,n.getDerivedStateFromProps=d.default.getDerivedStateFromProps,n.propTypes=(0,a.default)({},d.default.propTypes,{showToggle:u.default.bool}),n.defaultProps=(0,a.default)({},d.default.defaultProps,{showToggle:!0}),r);function m(){var e,t;(0,i.default)(this,m);for(var n=arguments.length,r=Array(n),a=0;a, as child."),r.push(t),e.props.children&&(t.children=n(e.props.children)))}),r}(e.children):t},O.prototype.fetchInfoFromBinaryChildren=function(e){function o(e,t){return t=t||0,e.forEach(function(e){e.children?t=o(e.children,t):t+=1}),t}var r=!1,a=[],i=[];(function t(){var e=0e.clientHeight,e.scrollWidth,e.clientWidth,(e={})[a]=n,e=e,i||(e[r]=n),t||(e[r]=0,e[a]=0),+n&&(e.marginBottom=-n,e.paddingBottom=n,t&&(e[a]=n)),m.dom.setStyle(this.headerNode,e))},o.prototype.render=function(){var e=this.props,t=e.components,n=e.className,r=e.prefix,a=e.fixedHeader,o=e.lockType,i=e.dataSource,e=(e.maxBodyHeight,(0,u.default)(e,["components","className","prefix","fixedHeader","lockType","dataSource","maxBodyHeight"]));return a&&((t=(0,l.default)({},t)).Header||(t.Header=_.default),t.Body||(t.Body=y.default),t.Wrapper||(t.Wrapper=g.default),n=(0,h.default)(((a={})[r+"table-fixed"]=!0,a[r+"table-wrap-empty"]=!i.length,a[n]=n,a))),f.default.createElement(s,(0,l.default)({},e,{dataSource:i,lockType:o,components:t,className:n,prefix:r}))},o}(f.default.Component),e.FixedHeader=_.default,e.FixedBody=y.default,e.FixedWrapper=g.default,e.propTypes=(0,l.default)({hasHeader:a.default.bool,fixedHeader:a.default.bool,maxBodyHeight:a.default.oneOfType([a.default.number,a.default.string])},s.propTypes),e.defaultProps=(0,l.default)({},s.defaultProps,{hasHeader:!0,fixedHeader:!1,maxBodyHeight:200,components:{},refs:{},prefix:"next-"}),e.childContextTypes={fixedHeader:a.default.bool,getNode:a.default.func,onFixedScrollSync:a.default.func,getTableInstanceForFixed:a.default.func,maxBodyHeight:a.default.oneOfType([a.default.number,a.default.string])},t);return t.displayName="FixedTable",(0,o.statics)(t,s),t};var f=i(n(0)),a=i(n(1)),p=n(11),h=i(n(9)),m=n(7),_=i(n(64)),y=i(n(308)),g=i(n(65)),o=n(25);function i(e){return e&&e.__esModule?e:{default:e}}e.exports=t.default},function(e,t,n){"use strict";t.__esModule=!0;var i=o(n(8)),f=o(n(3)),a=o(n(4)),s=o(n(5)),l=o(n(6));t.default=function(o){var e,t=(t=e=function(n){function r(e,t){(0,a.default)(this,r);var c=(0,s.default)(this,n.call(this,e,t));return c.addSelection=function(e){var t=c.props,n=t.prefix,r=t.rowSelection,t=t.size,r=r.columnProps&&r.columnProps()||{};e.find(function(e){return"selection"===e.key})||e.unshift((0,f.default)({key:"selection",title:c.renderSelectionHeader.bind(c),cell:c.renderSelectionBody.bind(c),width:"small"===t?34:50,className:n+"table-selection "+n+"table-prerow",__normalized:!0},r))},c.renderSelectionHeader=function(){var e=c.selectAllRow,t={},n=c.props,r=n.rowSelection,a=n.primaryKey,o=n.dataSource,i=n.entireDataSource,s=n.locale,l=c.state.selectedRowKeys,n=r.mode||"multiple",u=!!l.length,d=!1;c.flatDataSource(i||o).filter(function(e,t){return!r.getProps||!(r.getProps(e,t)||{}).disabled}).map(function(e){return e[a]}).forEach(function(e){-1===l.indexOf(e)?u=!1:d=!0}),t.onClick=b(function(e){e.stopPropagation()},t.onClick);o=r.titleProps&&r.titleProps()||{};return u&&(d=!1),["multiple"===n?p.default.createElement(h.default,(0,f.default)({key:"_total",indeterminate:d,"aria-label":s.selectAll,checked:u,onChange:e},t,o)):null,r.titleAddons&&r.titleAddons()]},c.renderSelectionBody=function(e,t,n){var r=c.props,a=r.rowSelection,o=r.primaryKey,i=c.state.selectedRowKeys,r=a.mode||"multiple",i=-1c.clientHeight;this.isLock()?(e=this.bodyLeftNode,t=this.bodyRightNode,r=this.getWrapperNode("right"),n=f?u:0,c=c.offsetHeight-u,f||(d[s]=0,d[l]=0),+u?(d.marginBottom=-u,d.paddingBottom=u):(d.marginBottom=-20,d.paddingBottom=20),c={"max-height":c},o||+u||(c[l]=0),+u&&(c[l]=-u),e&&_.dom.setStyle(e,c),t&&_.dom.setStyle(t,c),r&&+u&&_.dom.setStyle(r,a?"left":"right",n+"px")):(d.marginBottom=-u,d.paddingBottom=u,d[l]=0,f||(d[s]=0)),i&&_.dom.setStyle(i,d)},r.prototype.adjustHeaderSize=function(){var o=this;this.isLock()&&this.tableInc.groupChildren.forEach(function(e,t){var n=o.tableInc.groupChildren[t].length-1,r=o.getHeaderCellNode(t,n),a=o.getHeaderCellNode(t,0),n=o.getHeaderCellNode(t,0,"right"),t=o.getHeaderCellNode(t,0,"left");r&&n&&(r=r.offsetHeight,_.dom.setStyle(n,"height",r),setTimeout(function(){var e=o.tableRightInc.affixRef;return e&&e.getInstance()&&e.getInstance().updatePosition()})),a&&t&&(a=a.offsetHeight,_.dom.setStyle(t,"height",a),setTimeout(function(){var e=o.tableLeftInc.affixRef;return e&&e.getInstance()&&e.getInstance().updatePosition()}))})},r.prototype.adjustRowHeight=function(){var n=this;this.isLock()&&this.tableInc.props.dataSource.forEach(function(e,t){e=("object"===(void 0===e?"undefined":(0,a.default)(e))&&"__rowIndex"in e?e.__rowIndex:t)+(e.__expanded?"_expanded":"");n.setRowHeight(e,"left"),n.setRowHeight(e,"right")})},r.prototype.setRowHeight=function(e,t){var n=this.getRowNode(e,t),t=this.getRowNode(e),e=(w?t&&t.offsetHeight:t&&parseFloat(getComputedStyle(t).height))||"auto",t=(w?n&&n.offsetHeight:n&&parseFloat(getComputedStyle(n).height))||"auto";n&&e!==t&&_.dom.setStyle(n,"height",e)},r.prototype.getWrapperNode=function(e){e=e?e.charAt(0).toUpperCase()+e.substr(1):"";try{return(0,u.findDOMNode)(this["lock"+e+"El"])}catch(e){return null}},r.prototype.getRowNode=function(e,t){t=this["table"+(t=t?t.charAt(0).toUpperCase()+t.substr(1):"")+"Inc"];try{return(0,u.findDOMNode)(t.getRowRef(e))}catch(e){return null}},r.prototype.getHeaderCellNode=function(e,t,n){n=this["table"+(n=n?n.charAt(0).toUpperCase()+n.substr(1):"")+"Inc"];try{return(0,u.findDOMNode)(n.getHeaderCellRef(e,t))}catch(e){return null}},r.prototype.getCellNode=function(e,t,n){n=this["table"+(n=n?n.charAt(0).toUpperCase()+n.substr(1):"")+"Inc"];try{return(0,u.findDOMNode)(n.getCellRef(e,t))}catch(e){return null}},r.prototype.render=function(){var e=this.props,t=(e.children,e.columns,e.prefix),n=e.components,r=e.className,a=e.dataSource,o=e.tableWidth,i=(0,f.default)(e,["children","columns","prefix","components","className","dataSource","tableWidth"]),s=this.normalizeChildrenState(this.props),l=s.lockLeftChildren,u=s.lockRightChildren,d=s.children,e={left:this.getFlatenChildrenLength(l),right:this.getFlatenChildrenLength(u),origin:this.getFlatenChildrenLength(d)};if(this._notNeedAdjustLockLeft&&(l=[]),this._notNeedAdjustLockRight&&(u=[]),this.lockLeftChildren=l,this.lockRightChildren=u,this.isOriginLock()){(n=(0,p.default)({},n)).Body=n.Body||g.default,n.Header=n.Header||v.default,n.Wrapper=n.Wrapper||b.default,n.Row=n.Row||y.default;r=(0,m.default)(((s={})[t+"table-lock"]=!0,s[t+"table-wrap-empty"]=!a.length,s[r]=r,s)),u=[h.default.createElement(c,(0,p.default)({},i,{dataSource:a,key:"lock-left",columns:l,className:t+"table-lock-left",lengths:e,prefix:t,lockType:"left",components:n,ref:this.saveLockLeftRef,loading:!1,"aria-hidden":!0})),h.default.createElement(c,(0,p.default)({},i,{dataSource:a,key:"lock-right",columns:u,className:t+"table-lock-right",lengths:e,prefix:t,lockType:"right",components:n,ref:this.saveLockRightRef,loading:!1,"aria-hidden":!0}))];return h.default.createElement(c,(0,p.default)({},i,{tableWidth:o,dataSource:a,columns:d,prefix:t,lengths:e,wrapperContent:u,components:n,className:r}))}return h.default.createElement(c,this.props)},r}(h.default.Component),e.LockRow=y.default,e.LockBody=g.default,e.LockHeader=v.default,e.propTypes=(0,p.default)({scrollToCol:r.default.number,scrollToRow:r.default.number},c.propTypes),e.defaultProps=(0,p.default)({},c.defaultProps),e.childContextTypes={getTableInstance:r.default.func,getLockNode:r.default.func,onLockBodyScroll:r.default.func,onRowMouseEnter:r.default.func,onRowMouseLeave:r.default.func},t);return t.displayName="LockTable",(0,M.statics)(t,c),t};var l=n(0),h=c(l),u=n(11),r=c(n(1)),m=c(n(9)),d=c(n(96)),_=n(7),y=c(n(98)),g=c(n(309)),v=c(n(310)),b=c(n(65)),M=n(25);function c(e){return e&&e.__esModule?e:{default:e}}var w=_.env.ieVersion;function k(e){return function n(e){return e.map(function(e){var t=(0,p.default)({},e);return e.children&&(e.children=n(e.children)),t})}(e)}e.exports=t.default},function(e,t,n){"use strict";t.__esModule=!0;var l=s(n(8)),u=s(n(3)),a=s(n(4)),o=s(n(5)),i=s(n(6));t.default=function(s){var e,t=(t=e=function(n){function r(e,t){(0,a.default)(this,r);var d=(0,o.default)(this,n.call(this,e));return d.state={},d.updateOffsetArr=function(){var e=d.splitChildren||{},t=e.lockLeftChildren,n=e.lockRightChildren,r=e.originChildren,a=d.getFlatenChildren(t).length,e=d.getFlatenChildren(n).length,r=a+e+d.getFlatenChildren(r).length,a=0i.top-e.offset?(r?(a.position="absolute",a.top=o-(i.top-e.offset),n.position="relative"):(a.position="fixed",a.top=e.offset+t.top),u._setAffixStyle(a,!0),u._setContainerStyle(n)):e.bottom&&on&&(t.current=n),this.setState(t),this.props.onPageSizeChange(e)},H.prototype.renderPageTotal=function(){var e=this.props,t=e.prefix,n=e.total,r=e.totalRender,a=this.state,e=a.currentPageSize,a=a.current;return O.default.createElement("div",{className:t+"pagination-total"},r(n,[(a-1)*e+1,a*e]))},H.prototype.renderPageItem=function(e){var t=this.props,n=t.prefix,r=t.size,a=t.link,o=t.pageNumberRender,i=t.total,s=t.pageSize,l=t.locale,t=this.state.current,s=j(i,s),t=parseInt(e,10)===t,t={size:r,className:(0,N.default)(((r={})[n+"pagination-item"]=!0,r[n+"current"]=t,r)),onClick:t?m:this.onPageItemClick.bind(this,e)};return a&&(t.component="a",t.href=a.replace("{page}",e)),O.default.createElement(c.default,(0,E.default)({"aria-label":P.str.template(l.total,{current:e,total:s})},t,{key:e}),o(e))},H.prototype.renderPageFirst=function(e){var t=this.props,n=t.prefix,r=t.size,a=t.shape,t=t.locale,r={disabled:e<=1,size:r,className:(0,N.default)(((r={})[n+"pagination-item"]=!0,r[n+"prev"]=!0,r)),onClick:this.onPageItemClick.bind(this,e-1)},n=O.default.createElement(d.default,{type:"arrow-left",className:n+"pagination-icon-prev"});return O.default.createElement(c.default,(0,E.default)({},r,{"aria-label":P.str.template(t.labelPrev,{current:e})}),n,"arrow-only"===a||"arrow-prev-only"===a||"no-border"===a?"":t.prev)},H.prototype.renderPageLast=function(e,t){var n=this.props,r=n.prefix,a=n.size,o=n.shape,n=n.locale,a={disabled:t<=e,size:a,className:(0,N.default)(((a={})[r+"pagination-item"]=!0,a[r+"next"]=!0,a)),onClick:this.onPageItemClick.bind(this,e+1)},r=O.default.createElement(d.default,{type:"arrow-right",className:r+"pagination-icon-next"});return O.default.createElement(c.default,(0,E.default)({},a,{"aria-label":P.str.template(n.labelNext,{current:e})}),"arrow-only"===o||"no-border"===o?"":n.next,r)},H.prototype.renderPageEllipsis=function(e){var t=this.props.prefix;return O.default.createElement(d.default,{className:t+"pagination-ellipsis "+t+"pagination-icon-ellipsis",type:"ellipsis",key:"ellipsis-"+e})},H.prototype.renderPageJump=function(){var t=this,e=this.props,n=e.prefix,r=e.size,a=e.locale,e=this.state.inputValue;return[O.default.createElement("span",{className:n+"pagination-jump-text"},a.goTo),O.default.createElement(f.default,{className:n+"pagination-jump-input",type:"text","aria-label":a.inputAriaLabel,size:r,value:e,onChange:this.onInputChange.bind(this),onKeyDown:function(e){e.keyCode===P.KEYCODE.ENTER&&t.handleJump(e)}}),O.default.createElement("span",{className:n+"pagination-jump-text"},a.page),O.default.createElement(c.default,{className:n+"pagination-jump-go",size:r,onClick:this.handleJump},a.go)]},H.prototype.renderPageDisplay=function(e,t){var n=this.props,r=n.prefix,n=n.pageNumberRender;return O.default.createElement("span",{className:r+"pagination-display"},O.default.createElement("em",null,n(e)),"/",n(t))},H.prototype.renderPageList=function(e,t){var n=this.props,r=n.prefix,a=n.pageShowCount,o=[];if(t<=a)for(var i=1;i<=t;i++)o.push(this.renderPageItem(i));else{var s=a-3,n=parseInt(s/2,10),a=void 0,l=void 0;o.push(this.renderPageItem(1)),l=e+n,(a=e-n)<=1&&(l=(a=2)+s),2, or explicitly pass "'+d+'" as a prop to "'+a+'".'),n.initSelector(),n.initSubscription(),n}P(e,r);var t=e.prototype;return t.getChildContext=function(){var e=this.propsMode?null:this.subscription,t={};return t[p]=e||this.context[p],t},t.componentDidMount=function(){u&&(this.subscription.trySubscribe(),this.selector.run(this.props),this.selector.shouldComponentUpdate&&this.forceUpdate())},t.componentWillReceiveProps=function(e){this.selector.run(e)},t.shouldComponentUpdate=function(){return this.selector.shouldComponentUpdate},t.componentWillUnmount=function(){this.subscription&&this.subscription.tryUnsubscribe(),this.subscription=null,this.notifyNestedSubs=re,this.store=null,this.selector.run=re,this.selector.shouldComponentUpdate=!1},t.getWrappedInstance=function(){return q()(c,"To access the wrapped instance, you need to specify { withRef: true } in the options argument of the "+s+"() call."),this.wrappedInstance},t.setWrappedInstance=function(e){this.wrappedInstance=e},t.initSelector=function(){var n,r,a,e=i(this.store.dispatch,o);this.selector=(n=e,r=this.store,a={run:function(e){try{var t=n(r.getState(),e);t===a.props&&!a.error||(a.shouldComponentUpdate=!0,a.props=t,a.error=null)}catch(e){a.shouldComponentUpdate=!0,a.error=e}}}),this.selector.run(this.props)},t.initSubscription=function(){var e;u&&(e=(this.propsMode?this.props:this.context)[p],this.subscription=new X(this.store,e,this.onStateChange.bind(this)),this.notifyNestedSubs=this.subscription.notifyNestedSubs.bind(this.subscription))},t.onStateChange=function(){this.selector.run(this.props),this.selector.shouldComponentUpdate?(this.componentDidUpdate=this.notifyNestedSubsOnComponentDidUpdate,this.setState(ne)):this.notifyNestedSubs()},t.notifyNestedSubsOnComponentDidUpdate=function(){this.componentDidUpdate=void 0,this.notifyNestedSubs()},t.isSubscribed=function(){return Boolean(this.subscription)&&this.subscription.isSubscribed()},t.addExtraProps=function(e){if(!(c||l||this.propsMode&&this.subscription))return e;e=U({},e);return c&&(e.ref=this.setWrappedInstance),l&&(e[l]=this.renderCount++),this.propsMode&&this.subscription&&(e[p]=this.subscription),e},t.render=function(){var e=this.selector;if(e.shouldComponentUpdate=!1,e.error)throw e.error;return Object(y.createElement)(n,this.addExtraProps(e.props))},e}(y.Component);return ee&&(e.prototype.UNSAFE_componentWillReceiveProps=e.prototype.componentWillReceiveProps,delete e.prototype.componentWillReceiveProps),e.WrappedComponent=n,e.displayName=a,e.childContextTypes=_,e.contextTypes=m,e.propTypes=m,$()(e,n)}}var oe=Object.prototype.hasOwnProperty;function ie(e,t){return e===t?0!==e||0!==t||1/e==1/t:e!=e&&t!=t}function se(e,t){if(ie(e,t))return!0;if("object"!=typeof e||null===e||"object"!=typeof t||null===t)return!1;var n=Object.keys(e),r=Object.keys(t);if(n.length!==r.length)return!1;for(var a=0;a outside a "),this.isStatic()&&this.perform()},tt.prototype.componentDidMount=function(){this.isStatic()||this.perform()},tt.prototype.componentDidUpdate=function(e){var t=Re(e.to),n=Re(this.props.to);e=n,(t=t).pathname===e.pathname&&t.search===e.search&&t.hash===e.hash&&t.key===e.key&&Ce(t.state,e.state)?xe()(!1,"You tried to redirect to the same route you're currently on: \""+n.pathname+n.search+'"'):this.perform()},tt.prototype.computeTo=function(e){var t=e.computedMatch,e=e.to;return t?"string"==typeof e?Ze(e,t.params):Xe({},e,{pathname:Ze(e.pathname,t.params)}):e},tt.prototype.perform=function(){var e=this.context.router.history,t=this.props.push,n=this.computeTo(this.props);t?e.push(n):e.replace(n)},tt.prototype.render=function(){return null},tt);function tt(){return function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,tt),function(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}(this,et.apply(this,arguments))}E.propTypes={computedMatch:H.a.object,push:H.a.bool,from:H.a.string,to:H.a.oneOfType([H.a.string,H.a.object]).isRequired},E.defaultProps={push:!1},E.contextTypes={router:H.a.shape({history:H.a.shape({push:H.a.func.isRequired,replace:H.a.func.isRequired}).isRequired,staticContext:H.a.object}).isRequired};var nt=E,rt=Object.assign||function(e){for(var t=1;t may have only one child element"),this.unlisten=r.listen(function(){e.setState({match:e.computeMatch(r.location.pathname)})})},it.prototype.componentWillReceiveProps=function(e){xe()(this.props.history===e.history,"You cannot change ")},it.prototype.componentWillUnmount=function(){this.unlisten()},it.prototype.render=function(){var e=this.props.children;return e?_.a.Children.only(e):null},it);function it(){var e,t;!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,it);for(var n=arguments.length,r=Array(n),a=0;a ignores the history prop. To use a custom history, use `import { Router }` instead of `import { HashRouter as Router }`.")},dt.prototype.render=function(){return _.a.createElement(st,{history:this.history,children:this.props.children})},dt);function dt(){var e,t;!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,dt);for(var n=arguments.length,r=Array(n),a=0;a outside a ")},yt.prototype.componentWillReceiveProps=function(e){xe()(!(e.location&&!this.props.location),' elements should not change from uncontrolled to controlled (or vice versa). You initially used no "location" prop and then provided one on a subsequent render.'),xe()(!(!e.location&&this.props.location),' elements should not change from controlled to uncontrolled (or vice versa). You provided a "location" prop initially but omitted it on a subsequent render.')},yt.prototype.render=function(){var i=this.context.router.route,e=this.props.children,s=this.props.location||i.location,l=void 0,u=void 0;return _.a.Children.forEach(e,function(e){var t,n,r,a,o;null==l&&_.a.isValidElement(e)&&(t=(o=e.props).path,n=o.exact,r=o.strict,a=o.sensitive,o=o.from,u=e,l=mt(s.pathname,{path:t||o,exact:n,strict:r,sensitive:a},i.match))}),l?_.a.cloneElement(u,{location:s,computedMatch:l}):null},yt);function yt(){return function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,yt),function(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}(this,_t.apply(this,arguments))}J.contextTypes={router:H.a.shape({route:H.a.object.isRequired}).isRequired},J.propTypes={children:H.a.node,location:H.a.object};var gt=J,vt=Object.assign||function(e){for(var t=1;t or withRouter() outside a ");t=t.route,r=(r||t.location).pathname;return mt(r,{path:a,strict:o,exact:i,sensitive:e},t.match)},kt.prototype.componentWillMount=function(){xe()(!(this.props.component&&this.props.render),"You should not use and in the same route; will be ignored"),xe()(!(this.props.component&&this.props.children&&!Mt(this.props.children)),"You should not use and in the same route; will be ignored"),xe()(!(this.props.render&&this.props.children&&!Mt(this.props.children)),"You should not use and in the same route; will be ignored")},kt.prototype.componentWillReceiveProps=function(e,t){xe()(!(e.location&&!this.props.location),' elements should not change from uncontrolled to controlled (or vice versa). You initially used no "location" prop and then provided one on a subsequent render.'),xe()(!(!e.location&&this.props.location),' elements should not change from controlled to uncontrolled (or vice versa). You provided a "location" prop initially but omitted it on a subsequent render.'),this.setState({match:this.computeMatch(e,t.router)})},kt.prototype.render=function(){var e=this.state.match,t=this.props,n=t.children,r=t.component,a=t.render,o=this.context.router,i=o.history,t=o.route,o=o.staticContext,o={match:e,location:this.props.location||t.location,history:i,staticContext:o};return r?e?_.a.createElement(r,o):null:a?e?a(o):null:"function"==typeof n?n(o):n&&!Mt(n)?_.a.Children.only(n):null},kt);function kt(){var e,t;!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,kt);for(var n=arguments.length,r=Array(n),a=0;a list = new ArrayList<>();
- list.add(taskDO);
- try {
- fastSyncHelper.syncWithThread(list, nacosSyncToNacosService::timeSync);
- } catch (Exception e) {
- Assert.assertEquals(e, InterruptedException.class);
- e.printStackTrace();
- }
- }
-
- @Test
- public void testAverageAssign() {
- int limit = 2;
- List sourceList = new ArrayList<>();
- sourceList.add("1");
- sourceList.add("2");
- sourceList.add("3");
- List>> lists = FastSyncHelper.averageAssign(sourceList, limit);
- Assert.assertEquals(lists.get(0).getT2().size(), limit);
- Assert.assertNotEquals(lists.get(0).getT2().size(), 3);
- }
-}
diff --git a/pom.xml b/pom.xml
index 539b3a45..824aa8ff 100644
--- a/pom.xml
+++ b/pom.xml
@@ -25,19 +25,18 @@
pom
- 0.4.9
- 2.5.14
- 2020.0.2
+ 0.5.0
+ 2.7.17
+ 2021.0.3
UTF-8
- 3.4.9
- 4.1.0
+ 3.4.14
+ 4.3.0
1.10.19
- 1.4.2
+ 1.4.7
1.18.2
- 3.0.0
1.3.1
3.12.0
- 30.1-jre
+ 33.2.0-jre
2.2
11
11
@@ -57,6 +56,7 @@
1.0.2
1.0-beta-4
1.7.17
+ 1.8.0
@@ -110,14 +110,9 @@
test
- io.springfox
- springfox-swagger2
- ${swagger.verison}
-
-
- io.springfox
- springfox-swagger-ui
- ${swagger.verison}
+ org.springdoc
+ springdoc-openapi-ui
+ ${swagger.version}
com.alibaba.nacos