From 276ade59086c6c0a190f173612eacf0cdb6c0ee3 Mon Sep 17 00:00:00 2001 From: chenyc55879 Date: Mon, 7 Jul 2025 08:10:19 +0800 Subject: [PATCH 01/21] add adminclient e.t.c --- dependencies/pom.xml | 14 ++++ pom.xml | 1 + sdk/pom.xml | 32 ++++++++ .../dromara/dynamictp/sdk/AdminClient.java | 62 +++++++++++++++ .../sdk/AdminClientUserProcessor.java | 77 +++++++++++++++++++ .../sdk/AdminConnectEventProcessor.java | 11 +++ .../dynamictp/sdk/AdminRequestBody.java | 30 ++++++++ .../dynamictp/sdk/AdminRequestTypeEnum.java | 5 ++ sdk/src/main/resources/application.yml | 4 + spring/pom.xml | 6 ++ .../spring/DtpBaseBeanConfiguration.java | 6 ++ 11 files changed, 248 insertions(+) create mode 100644 sdk/pom.xml create mode 100644 sdk/src/main/java/org/dromara/dynamictp/sdk/AdminClient.java create mode 100644 sdk/src/main/java/org/dromara/dynamictp/sdk/AdminClientUserProcessor.java create mode 100644 sdk/src/main/java/org/dromara/dynamictp/sdk/AdminConnectEventProcessor.java create mode 100644 sdk/src/main/java/org/dromara/dynamictp/sdk/AdminRequestBody.java create mode 100644 sdk/src/main/java/org/dromara/dynamictp/sdk/AdminRequestTypeEnum.java create mode 100644 sdk/src/main/resources/application.yml diff --git a/dependencies/pom.xml b/dependencies/pom.xml index f29b7f59d..4443d7168 100644 --- a/dependencies/pom.xml +++ b/dependencies/pom.xml @@ -36,6 +36,8 @@ 2.6.10 2.0.0 2.15.0.RELEASE + 1.6.12 + 1.4.0 1.5.18 1.2.0 3.14.9 @@ -184,6 +186,18 @@ ${rocketmq.version} + + com.alipay.sofa + bolt + ${sofa-bolt.version} + + + + com.alipay.sofa.common + sofa-common-tools + 1.4.0 + + com.aliyun.openservices ons-client diff --git a/pom.xml b/pom.xml index 3520a6f68..cc1fcdaf4 100644 --- a/pom.xml +++ b/pom.xml @@ -48,6 +48,7 @@ dependencies spring benchmark + sdk diff --git a/sdk/pom.xml b/sdk/pom.xml new file mode 100644 index 000000000..0d3977e9f --- /dev/null +++ b/sdk/pom.xml @@ -0,0 +1,32 @@ + + + 4.0.0 + + org.dromara.dynamictp + dynamic-tp-all + ${revision} + ../pom.xml + + dynamic-tp-sdk + + + + org.dromara.dynamictp + dynamic-tp-core + + + org.dromara.dynamictp + dynamic-tp-spring + + + com.alipay.sofa + bolt + + + com.alipay.sofa.common + sofa-common-tools + + + + diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/AdminClient.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/AdminClient.java new file mode 100644 index 000000000..526fe06a8 --- /dev/null +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/AdminClient.java @@ -0,0 +1,62 @@ +/* + * 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 org.dromara.dynamictp.sdk; + +import cn.hutool.core.lang.generator.SnowflakeGenerator; +import com.alipay.remoting.Connection; +import com.alipay.remoting.ConnectionEventType; +import com.alipay.remoting.exception.RemotingException; +import com.alipay.remoting.rpc.RpcClient; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; + +@Slf4j +public class AdminClient { + + @Value("${dynamictp.admin.ip}") + private String adminIp; + + @Value("${dynamictp.admin.port}") + private int port; + + private final RpcClient client = new RpcClient(); + + private Connection connection; + + private final SnowflakeGenerator idGenerator = new SnowflakeGenerator(); + + public AdminClient() { + client.addConnectionEventProcessor(ConnectionEventType.CONNECT, new AdminConnectEventProcessor()); + client.registerUserProcessor(new AdminClientUserProcessor()); + client.startup(); + try { + connection = client.createStandaloneConnection(adminIp, port, 30000); + } catch (RemotingException e) { + throw new RuntimeException(e); + } finally { + client.closeStandaloneConnection(connection); + client.shutdown(); + } + } + + public Object requestToServer(AdminRequestTypeEnum requestType) throws RemotingException, InterruptedException { + AdminRequestBody requestBody = new AdminRequestBody(idGenerator.next(), requestType); + return client.invokeSync(connection, requestBody, 30000); + } + +} diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/AdminClientUserProcessor.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/AdminClientUserProcessor.java new file mode 100644 index 000000000..8ca8aed24 --- /dev/null +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/AdminClientUserProcessor.java @@ -0,0 +1,77 @@ +package org.dromara.dynamictp.sdk; + +import com.alipay.remoting.AsyncContext; +import com.alipay.remoting.BizContext; +import com.alipay.remoting.LifeCycleException; +import com.alipay.remoting.RemotingContext; +import com.alipay.remoting.rpc.protocol.UserProcessor; + +import java.util.concurrent.Executor; + +public class AdminClientUserProcessor implements UserProcessor { + + @Override + public BizContext preHandleRequest(RemotingContext remotingCtx, AdminRequestBody request) { + return null; + } + + @Override + public void handleRequest(BizContext bizCtx, AsyncContext asyncCtx, AdminRequestBody request) { + + } + + @Override + public Object handleRequest(BizContext bizCtx, AdminRequestBody request) throws Exception { + return null; + } + + @Override + public String interest() { + return ""; + } + + @Override + public Executor getExecutor() { + return null; + } + + @Override + public ClassLoader getBizClassLoader() { + return null; + } + + @Override + public boolean processInIOThread() { + return false; + } + + @Override + public boolean timeoutDiscard() { + return false; + } + + @Override + public void setExecutorSelector(ExecutorSelector executorSelector) { + + } + + @Override + public ExecutorSelector getExecutorSelector() { + return null; + } + + @Override + public void startup() throws LifeCycleException { + + } + + @Override + public void shutdown() throws LifeCycleException { + + } + + @Override + public boolean isStarted() { + return false; + } +} diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/AdminConnectEventProcessor.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/AdminConnectEventProcessor.java new file mode 100644 index 000000000..0435207e8 --- /dev/null +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/AdminConnectEventProcessor.java @@ -0,0 +1,11 @@ +package org.dromara.dynamictp.sdk; + +import com.alipay.remoting.Connection; +import com.alipay.remoting.ConnectionEventProcessor; + +public class AdminConnectEventProcessor implements ConnectionEventProcessor { + @Override + public void onEvent(String remoteAddress, Connection connection) { + + } +} diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/AdminRequestBody.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/AdminRequestBody.java new file mode 100644 index 000000000..b54047f1b --- /dev/null +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/AdminRequestBody.java @@ -0,0 +1,30 @@ +package org.dromara.dynamictp.sdk; + +import lombok.Getter; + +import java.io.Serializable; +import java.util.concurrent.ThreadLocalRandom; + +public class AdminRequestBody implements Serializable { + + private static final long serialVersionUID = -1288207208017808618L; + + @Getter + private final long id; + + private AdminRequestTypeEnum requestType; + + private byte[] body; + + public AdminRequestBody(long id, AdminRequestTypeEnum requestType) { + this.id = id; + this.requestType = requestType; + } + + public AdminRequestBody(int id, int size) { + this.id = id; + this.body = new byte[size]; + ThreadLocalRandom.current().nextBytes(this.body); + } + +} diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/AdminRequestTypeEnum.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/AdminRequestTypeEnum.java new file mode 100644 index 000000000..bcd363088 --- /dev/null +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/AdminRequestTypeEnum.java @@ -0,0 +1,5 @@ +package org.dromara.dynamictp.sdk; + +public enum AdminRequestTypeEnum { + +} diff --git a/sdk/src/main/resources/application.yml b/sdk/src/main/resources/application.yml new file mode 100644 index 000000000..8667e7dc6 --- /dev/null +++ b/sdk/src/main/resources/application.yml @@ -0,0 +1,4 @@ +dynamictp: + admin: + ip: 127.0.0.1 + port: 8989 \ No newline at end of file diff --git a/spring/pom.xml b/spring/pom.xml index 5492eef02..4d669103d 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -20,6 +20,12 @@ org.dromara.dynamictp dynamic-tp-core + + org.dromara.dynamictp + dynamic-tp-sdk + 1.2.2 + compile + diff --git a/spring/src/main/java/org/dromara/dynamictp/spring/DtpBaseBeanConfiguration.java b/spring/src/main/java/org/dromara/dynamictp/spring/DtpBaseBeanConfiguration.java index e3ea07088..70097a98e 100644 --- a/spring/src/main/java/org/dromara/dynamictp/spring/DtpBaseBeanConfiguration.java +++ b/spring/src/main/java/org/dromara/dynamictp/spring/DtpBaseBeanConfiguration.java @@ -23,6 +23,7 @@ import org.dromara.dynamictp.core.lifecycle.LifeCycleManagement; import org.dromara.dynamictp.core.monitor.DtpMonitor; import org.dromara.dynamictp.core.support.DtpBannerPrinter; +import org.dromara.dynamictp.sdk.AdminClient; import org.dromara.dynamictp.spring.lifecycle.DtpLifecycleSpringAdapter; import org.dromara.dynamictp.spring.listener.DtpApplicationListener; import org.springframework.beans.factory.config.BeanDefinition; @@ -74,4 +75,9 @@ public DtpLifecycleSpringAdapter dtpLifecycleSpringAdapter(LifeCycleManagement l public DtpApplicationListener dtpApplicationListener() { return new DtpApplicationListener(); } + + @Bean + public AdminClient adminClient() { + return new AdminClient(); + } } From 116830a7f60baaf8efaad4c3c9c54d163515669a Mon Sep 17 00:00:00 2001 From: eachannchan Date: Mon, 7 Jul 2025 15:56:18 +0800 Subject: [PATCH 02/21] add refresher related --- .../sdk/AdminClientUserProcessor.java | 77 ------------------- .../dynamictp/sdk/AdminRequestTypeEnum.java | 5 -- .../sdk/{ => client}/AdminClient.java | 2 +- .../sdk/client/AdminClientUserProcessor.java | 76 ++++++++++++++++++ .../AdminConnectEventProcessor.java | 2 +- .../sdk/{ => client}/AdminRequestBody.java | 11 +-- .../sdk/client/AdminRequestTypeEnum.java | 28 +++++++ .../handler/refresher/AdminConfigEvent.java | 16 ++++ .../sdk/handler/refresher/AdminRefresher.java | 25 ++++++ .../spring/DtpBaseBeanConfiguration.java | 2 +- 10 files changed, 154 insertions(+), 90 deletions(-) delete mode 100644 sdk/src/main/java/org/dromara/dynamictp/sdk/AdminClientUserProcessor.java delete mode 100644 sdk/src/main/java/org/dromara/dynamictp/sdk/AdminRequestTypeEnum.java rename sdk/src/main/java/org/dromara/dynamictp/sdk/{ => client}/AdminClient.java (98%) create mode 100644 sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClientUserProcessor.java rename sdk/src/main/java/org/dromara/dynamictp/sdk/{ => client}/AdminConnectEventProcessor.java (86%) rename sdk/src/main/java/org/dromara/dynamictp/sdk/{ => client}/AdminRequestBody.java (70%) create mode 100644 sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminRequestTypeEnum.java create mode 100644 sdk/src/main/java/org/dromara/dynamictp/sdk/handler/refresher/AdminConfigEvent.java create mode 100644 sdk/src/main/java/org/dromara/dynamictp/sdk/handler/refresher/AdminRefresher.java diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/AdminClientUserProcessor.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/AdminClientUserProcessor.java deleted file mode 100644 index 8ca8aed24..000000000 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/AdminClientUserProcessor.java +++ /dev/null @@ -1,77 +0,0 @@ -package org.dromara.dynamictp.sdk; - -import com.alipay.remoting.AsyncContext; -import com.alipay.remoting.BizContext; -import com.alipay.remoting.LifeCycleException; -import com.alipay.remoting.RemotingContext; -import com.alipay.remoting.rpc.protocol.UserProcessor; - -import java.util.concurrent.Executor; - -public class AdminClientUserProcessor implements UserProcessor { - - @Override - public BizContext preHandleRequest(RemotingContext remotingCtx, AdminRequestBody request) { - return null; - } - - @Override - public void handleRequest(BizContext bizCtx, AsyncContext asyncCtx, AdminRequestBody request) { - - } - - @Override - public Object handleRequest(BizContext bizCtx, AdminRequestBody request) throws Exception { - return null; - } - - @Override - public String interest() { - return ""; - } - - @Override - public Executor getExecutor() { - return null; - } - - @Override - public ClassLoader getBizClassLoader() { - return null; - } - - @Override - public boolean processInIOThread() { - return false; - } - - @Override - public boolean timeoutDiscard() { - return false; - } - - @Override - public void setExecutorSelector(ExecutorSelector executorSelector) { - - } - - @Override - public ExecutorSelector getExecutorSelector() { - return null; - } - - @Override - public void startup() throws LifeCycleException { - - } - - @Override - public void shutdown() throws LifeCycleException { - - } - - @Override - public boolean isStarted() { - return false; - } -} diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/AdminRequestTypeEnum.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/AdminRequestTypeEnum.java deleted file mode 100644 index bcd363088..000000000 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/AdminRequestTypeEnum.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.dromara.dynamictp.sdk; - -public enum AdminRequestTypeEnum { - -} diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/AdminClient.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java similarity index 98% rename from sdk/src/main/java/org/dromara/dynamictp/sdk/AdminClient.java rename to sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java index 526fe06a8..96832f2ff 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/AdminClient.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.dromara.dynamictp.sdk; +package org.dromara.dynamictp.sdk.client; import cn.hutool.core.lang.generator.SnowflakeGenerator; import com.alipay.remoting.Connection; diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClientUserProcessor.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClientUserProcessor.java new file mode 100644 index 000000000..2dc1bc19a --- /dev/null +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClientUserProcessor.java @@ -0,0 +1,76 @@ +package org.dromara.dynamictp.sdk.client; + +import com.alipay.remoting.BizContext; +import com.alipay.remoting.rpc.protocol.SyncUserProcessor; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +@Slf4j +public class AdminClientUserProcessor extends SyncUserProcessor { + + private final ExecutorService executor; + + @Getter + private String remoteAddress = "NOT-CONNECT"; + + public AdminClientUserProcessor() { + this.executor = Executors.newSingleThreadExecutor(); + } + + @Override + public Object handleRequest(BizContext bizContext, AdminRequestBody adminRequestBody) throws Exception { + log.info("DynamicTp admin request received:{}",adminRequestBody.getRequestType().getValue()); + if(bizContext.isRequestTimeout()) { + log.warn("DynamicTp admin request timeout:{}s",bizContext.getClientTimeout()); + } + this.remoteAddress = bizContext.getRemoteAddress(); + return doHandleRequest(adminRequestBody); + } + + private Object doHandleRequest(AdminRequestBody adminRequestBody) { + switch (adminRequestBody.getRequestType()) { + case EXECUTOR_MONITOR: + return handleExecutorMonitorRequest(adminRequestBody); + case EXECUTOR_REFRESH: + return handleExecutorRefreshRequest(adminRequestBody); + case ALARM_MANAGE: + return handleAlarmManageRequest(adminRequestBody); + case LOG_MANAGE: + return handleLogManageRequest(adminRequestBody); + default: + throw new IllegalArgumentException("DynamicTp admin request type " + adminRequestBody.getRequestType().getValue() + " is not supported"); + } + } + + @Override + public String interest() { + return AdminRequestBody.class.getName(); + } + + + @Override + public Executor getExecutor() { + return executor; + } + + private Object handleExecutorMonitorRequest(AdminRequestBody adminRequestBody) { + return null; + } + + private Object handleExecutorRefreshRequest(AdminRequestBody adminRequestBody) { + return null; + } + + private Object handleAlarmManageRequest(AdminRequestBody adminRequestBody) { + return null; + } + + private Object handleLogManageRequest(AdminRequestBody adminRequestBody) { + return null; + } + +} diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/AdminConnectEventProcessor.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminConnectEventProcessor.java similarity index 86% rename from sdk/src/main/java/org/dromara/dynamictp/sdk/AdminConnectEventProcessor.java rename to sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminConnectEventProcessor.java index 0435207e8..6390d86b7 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/AdminConnectEventProcessor.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminConnectEventProcessor.java @@ -1,4 +1,4 @@ -package org.dromara.dynamictp.sdk; +package org.dromara.dynamictp.sdk.client; import com.alipay.remoting.Connection; import com.alipay.remoting.ConnectionEventProcessor; diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/AdminRequestBody.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminRequestBody.java similarity index 70% rename from sdk/src/main/java/org/dromara/dynamictp/sdk/AdminRequestBody.java rename to sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminRequestBody.java index b54047f1b..9de652595 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/AdminRequestBody.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminRequestBody.java @@ -1,4 +1,4 @@ -package org.dromara.dynamictp.sdk; +package org.dromara.dynamictp.sdk.client; import lombok.Getter; @@ -12,19 +12,20 @@ public class AdminRequestBody implements Serializable { @Getter private final long id; - private AdminRequestTypeEnum requestType; + @Getter + private final AdminRequestTypeEnum requestType; private byte[] body; public AdminRequestBody(long id, AdminRequestTypeEnum requestType) { - this.id = id; - this.requestType = requestType; + this(id, requestType, 1024); } - public AdminRequestBody(int id, int size) { + public AdminRequestBody(long id, AdminRequestTypeEnum requestType, int size) { this.id = id; this.body = new byte[size]; ThreadLocalRandom.current().nextBytes(this.body); + this.requestType = requestType; } } diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminRequestTypeEnum.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminRequestTypeEnum.java new file mode 100644 index 000000000..029af87f2 --- /dev/null +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminRequestTypeEnum.java @@ -0,0 +1,28 @@ +package org.dromara.dynamictp.sdk.client; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum AdminRequestTypeEnum { + + EXECUTOR_MONITOR("executor_monitor"), + + EXECUTOR_REFRESH("executor_refresh"), + + ALARM_MANAGE("alarm_manage"), + + LOG_MANAGE("log_manage"); + + private final String value; + + public static AdminRequestTypeEnum of(String value) { + for (AdminRequestTypeEnum adminRequestType : AdminRequestTypeEnum.values()) { + if (adminRequestType.value.equals(value)) { + return adminRequestType; + } + } + return null; + } +} diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/handler/refresher/AdminConfigEvent.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/handler/refresher/AdminConfigEvent.java new file mode 100644 index 000000000..a60e3c46c --- /dev/null +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/handler/refresher/AdminConfigEvent.java @@ -0,0 +1,16 @@ +package org.dromara.dynamictp.sdk.handler.refresher; + +import org.springframework.context.ApplicationEvent; + +import java.time.Clock; + +public abstract class AdminConfigEvent extends ApplicationEvent { + public AdminConfigEvent(Object source) { + super(source); + } + + public AdminConfigEvent(Object source, Clock clock) { + super(source, clock); + } + +} diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/handler/refresher/AdminRefresher.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/handler/refresher/AdminRefresher.java new file mode 100644 index 000000000..4312d48b5 --- /dev/null +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/handler/refresher/AdminRefresher.java @@ -0,0 +1,25 @@ +package org.dromara.dynamictp.sdk.handler.refresher; + +import org.dromara.dynamictp.common.properties.DtpProperties; +import org.dromara.dynamictp.spring.AbstractSpringRefresher; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.event.SmartApplicationListener; + +public class AdminRefresher extends AbstractSpringRefresher implements SmartApplicationListener { + + protected AdminRefresher(DtpProperties dtpProperties) { + super(dtpProperties); + } + + @Override + public boolean supportsEventType(Class eventType) { + return false; + } + + @Override + public void onApplicationEvent(ApplicationEvent event) { + if (event instanceof AdminConfigEvent) { + refresh(environment); + } + } +} diff --git a/spring/src/main/java/org/dromara/dynamictp/spring/DtpBaseBeanConfiguration.java b/spring/src/main/java/org/dromara/dynamictp/spring/DtpBaseBeanConfiguration.java index 70097a98e..22851edef 100644 --- a/spring/src/main/java/org/dromara/dynamictp/spring/DtpBaseBeanConfiguration.java +++ b/spring/src/main/java/org/dromara/dynamictp/spring/DtpBaseBeanConfiguration.java @@ -23,7 +23,7 @@ import org.dromara.dynamictp.core.lifecycle.LifeCycleManagement; import org.dromara.dynamictp.core.monitor.DtpMonitor; import org.dromara.dynamictp.core.support.DtpBannerPrinter; -import org.dromara.dynamictp.sdk.AdminClient; +import org.dromara.dynamictp.sdk.client.AdminClient; import org.dromara.dynamictp.spring.lifecycle.DtpLifecycleSpringAdapter; import org.dromara.dynamictp.spring.listener.DtpApplicationListener; import org.springframework.beans.factory.config.BeanDefinition; From 2b4eeec24f7596f505a993917721bc79d553aa91 Mon Sep 17 00:00:00 2001 From: eachannchan Date: Wed, 9 Jul 2025 14:14:44 +0800 Subject: [PATCH 03/21] refresh related --- .../sdk/client/AdminClientUserProcessor.java | 10 +++++++-- .../sdk/client/AdminRequestBody.java | 21 ++++++++++++++++++- .../sdk/handler/refresher/AdminRefresher.java | 2 ++ 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClientUserProcessor.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClientUserProcessor.java index 2dc1bc19a..078a73d75 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClientUserProcessor.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClientUserProcessor.java @@ -4,11 +4,15 @@ import com.alipay.remoting.rpc.protocol.SyncUserProcessor; import lombok.Getter; import lombok.extern.slf4j.Slf4j; +import org.dromara.dynamictp.common.properties.DtpProperties; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import static org.dromara.dynamictp.core.DtpRegistry.refresh; + + @Slf4j public class AdminClientUserProcessor extends SyncUserProcessor { @@ -22,7 +26,7 @@ public AdminClientUserProcessor() { } @Override - public Object handleRequest(BizContext bizContext, AdminRequestBody adminRequestBody) throws Exception { + public Object handleRequest(BizContext bizContext, AdminRequestBody adminRequestBody) { log.info("DynamicTp admin request received:{}",adminRequestBody.getRequestType().getValue()); if(bizContext.isRequestTimeout()) { log.warn("DynamicTp admin request timeout:{}s",bizContext.getClientTimeout()); @@ -62,7 +66,9 @@ private Object handleExecutorMonitorRequest(AdminRequestBody adminRequestBody) { } private Object handleExecutorRefreshRequest(AdminRequestBody adminRequestBody) { - return null; + DtpProperties dtpProperties = (DtpProperties) adminRequestBody.bytesToObject(); + refresh(dtpProperties); + return adminRequestBody; } private Object handleAlarmManageRequest(AdminRequestBody adminRequestBody) { diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminRequestBody.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminRequestBody.java index 9de652595..8a12dc843 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminRequestBody.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminRequestBody.java @@ -2,7 +2,7 @@ import lombok.Getter; -import java.io.Serializable; +import java.io.*; import java.util.concurrent.ThreadLocalRandom; public class AdminRequestBody implements Serializable { @@ -28,4 +28,23 @@ public AdminRequestBody(long id, AdminRequestTypeEnum requestType, int size) { this.requestType = requestType; } + public void objectToBytes(Object object) { + try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream)) { + objectOutputStream.writeObject(object); + this.body = byteArrayOutputStream.toByteArray(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public Object bytesToObject() { + try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body); + ObjectInputStream objectOutputStream = new ObjectInputStream(byteArrayInputStream)) { + return objectOutputStream.readObject(); + } catch (IOException | ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + } diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/handler/refresher/AdminRefresher.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/handler/refresher/AdminRefresher.java index 4312d48b5..0afeda8a1 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/handler/refresher/AdminRefresher.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/handler/refresher/AdminRefresher.java @@ -1,10 +1,12 @@ package org.dromara.dynamictp.sdk.handler.refresher; +import lombok.extern.slf4j.Slf4j; import org.dromara.dynamictp.common.properties.DtpProperties; import org.dromara.dynamictp.spring.AbstractSpringRefresher; import org.springframework.context.ApplicationEvent; import org.springframework.context.event.SmartApplicationListener; +@Slf4j public class AdminRefresher extends AbstractSpringRefresher implements SmartApplicationListener { protected AdminRefresher(DtpProperties dtpProperties) { From 7444e29822ddc93b92919f87f8919ead6759b872 Mon Sep 17 00:00:00 2001 From: chenyc55879 Date: Fri, 11 Jul 2025 09:58:35 +0800 Subject: [PATCH 04/21] add adminclient related and admin example --- dependencies/pom.xml | 2 +- example/example-admin/pom.xml | 38 ++++ .../example/AdminExampleApplication.java | 34 ++++ .../dynamictp/example/collector/EsClient.java | 34 ++++ .../example/collector/EsCollector.java | 47 +++++ .../config/ThreadPoolConfiguration.java | 144 ++++++++++++++ .../example/controller/TestController.java | 71 +++++++ .../dynamictp/example/notifier/SmsClient.java | 34 ++++ .../example/notifier/SmsDtpNotifier.java | 94 ++++++++++ .../example/notifier/SmsNotifier.java | 47 +++++ .../example/notifier/SmsNotifyConst.java | 76 ++++++++ .../example/service/TestService.java | 57 ++++++ .../example/service/impl/TestServiceImpl.java | 175 ++++++++++++++++++ .../example/wrapper/CustomTaskWrapper.java | 57 ++++++ example/pom.xml | 2 + sdk/pom.xml | 4 - .../dynamictp/sdk/client/AdminClient.java | 12 +- .../sdk/client/AdminClientUserProcessor.java | 23 ++- .../sdk/client/AdminCloseEventProcessor.java | 31 ++++ .../client/AdminConnectEventProcessor.java | 21 ++- .../sdk/client/AdminRequestBody.java | 17 ++ .../sdk/client/AdminRequestTypeEnum.java | 17 ++ .../handler/refresher/AdminConfigEvent.java | 16 -- .../sdk/handler/refresher/AdminRefresher.java | 25 --- 24 files changed, 1022 insertions(+), 56 deletions(-) create mode 100644 example/example-admin/pom.xml create mode 100644 example/example-admin/src/main/java/org/dromara/dynamictp/example/AdminExampleApplication.java create mode 100644 example/example-admin/src/main/java/org/dromara/dynamictp/example/collector/EsClient.java create mode 100644 example/example-admin/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java create mode 100644 example/example-admin/src/main/java/org/dromara/dynamictp/example/config/ThreadPoolConfiguration.java create mode 100644 example/example-admin/src/main/java/org/dromara/dynamictp/example/controller/TestController.java create mode 100644 example/example-admin/src/main/java/org/dromara/dynamictp/example/notifier/SmsClient.java create mode 100644 example/example-admin/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java create mode 100644 example/example-admin/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifier.java create mode 100644 example/example-admin/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java create mode 100644 example/example-admin/src/main/java/org/dromara/dynamictp/example/service/TestService.java create mode 100644 example/example-admin/src/main/java/org/dromara/dynamictp/example/service/impl/TestServiceImpl.java create mode 100644 example/example-admin/src/main/java/org/dromara/dynamictp/example/wrapper/CustomTaskWrapper.java create mode 100644 sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminCloseEventProcessor.java delete mode 100644 sdk/src/main/java/org/dromara/dynamictp/sdk/handler/refresher/AdminConfigEvent.java delete mode 100644 sdk/src/main/java/org/dromara/dynamictp/sdk/handler/refresher/AdminRefresher.java diff --git a/dependencies/pom.xml b/dependencies/pom.xml index 4443d7168..c92027d38 100644 --- a/dependencies/pom.xml +++ b/dependencies/pom.xml @@ -195,7 +195,7 @@ com.alipay.sofa.common sofa-common-tools - 1.4.0 + ${sofa-common-tools.version} diff --git a/example/example-admin/pom.xml b/example/example-admin/pom.xml new file mode 100644 index 000000000..9568eb471 --- /dev/null +++ b/example/example-admin/pom.xml @@ -0,0 +1,38 @@ + + + 4.0.0 + + org.dromara.dynamictp + dynamic-tp-example + ${revision} + ../pom.xml + + + dynamic-tp-example-admin + + + + + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.dromara.dynamictp + dynamic-tp-spring-boot-starter-adapter-webserver + ${revision} + + + + + + \ No newline at end of file diff --git a/example/example-admin/src/main/java/org/dromara/dynamictp/example/AdminExampleApplication.java b/example/example-admin/src/main/java/org/dromara/dynamictp/example/AdminExampleApplication.java new file mode 100644 index 000000000..de813439b --- /dev/null +++ b/example/example-admin/src/main/java/org/dromara/dynamictp/example/AdminExampleApplication.java @@ -0,0 +1,34 @@ +/* + * 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 org.dromara.dynamictp.example; + +import org.dromara.dynamictp.spring.annotation.EnableDynamicTp; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * @author Redick01 + */ +@SpringBootApplication +@EnableDynamicTp +public class AdminExampleApplication { + + public static void main(String[] args) { + SpringApplication.run(AdminExampleApplication.class, args); + } +} diff --git a/example/example-admin/src/main/java/org/dromara/dynamictp/example/collector/EsClient.java b/example/example-admin/src/main/java/org/dromara/dynamictp/example/collector/EsClient.java new file mode 100644 index 000000000..8a6f6fd95 --- /dev/null +++ b/example/example-admin/src/main/java/org/dromara/dynamictp/example/collector/EsClient.java @@ -0,0 +1,34 @@ +/* + * 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 org.dromara.dynamictp.example.collector; + +import lombok.extern.slf4j.Slf4j; + +/** + * EsClient related + * + * @author yanhom + * @since 1.1.0 + */ +@Slf4j +public class EsClient { + + public void save(String json) { + log.info("save to es, json: {}", json); + } +} diff --git a/example/example-admin/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java b/example/example-admin/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java new file mode 100644 index 000000000..0dd2c4334 --- /dev/null +++ b/example/example-admin/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java @@ -0,0 +1,47 @@ +/* + * 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 org.dromara.dynamictp.example.collector; + +import org.dromara.dynamictp.common.entity.ThreadPoolStats; +import org.dromara.dynamictp.common.util.JsonUtil; +import org.dromara.dynamictp.core.monitor.collector.AbstractCollector; + +/** + * EsCollector related + * + * @author yanhom + * @since 1.1.0 + */ +public class EsCollector extends AbstractCollector { + + private final EsClient esClient; + + public EsCollector() { + this.esClient = new EsClient(); + } + + @Override + public void collect(ThreadPoolStats poolStats) { + esClient.save(JsonUtil.toJson(poolStats)); + } + + @Override + public String type() { + return "es"; + } +} diff --git a/example/example-admin/src/main/java/org/dromara/dynamictp/example/config/ThreadPoolConfiguration.java b/example/example-admin/src/main/java/org/dromara/dynamictp/example/config/ThreadPoolConfiguration.java new file mode 100644 index 000000000..ff51f8d24 --- /dev/null +++ b/example/example-admin/src/main/java/org/dromara/dynamictp/example/config/ThreadPoolConfiguration.java @@ -0,0 +1,144 @@ +/* + * 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 org.dromara.dynamictp.example.config; + +import org.dromara.dynamictp.core.executor.DtpExecutor; +import org.dromara.dynamictp.core.executor.OrderedDtpExecutor; +import org.dromara.dynamictp.core.support.DynamicTp; +import org.dromara.dynamictp.core.support.ThreadPoolBuilder; +import org.dromara.dynamictp.core.support.ThreadPoolCreator; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import static org.dromara.dynamictp.common.em.QueueTypeEnum.MEMORY_SAFE_LINKED_BLOCKING_QUEUE; +import static org.dromara.dynamictp.common.em.RejectedTypeEnum.CALLER_RUNS_POLICY; + +/** + * @author Redick01 + */ +@Configuration +public class ThreadPoolConfiguration { + + /** + * 通过{@link DynamicTp} 注解定义普通juc线程池,会享受到该框架增强能力,注解名称优先级高于方法名 + * + * @return 线程池实例 + */ + @DynamicTp("jucThreadPoolExecutor") + @Bean + public ThreadPoolExecutor jucThreadPoolExecutor() { + return (ThreadPoolExecutor) Executors.newFixedThreadPool(1); + } + + /** + * 通过{@link DynamicTp} 注解定义spring线程池,会享受到该框架增强能力,注解名称优先级高于方法名 + * + * @return 线程池实例 + */ + @DynamicTp("threadPoolTaskExecutor") + @Bean + public ThreadPoolTaskExecutor threadPoolTaskExecutor() { + return new ThreadPoolTaskExecutor(); + } + + /** + * 通过{@link ThreadPoolCreator} 快速创建一些简单配置的线程池,使用默认参数 + * tips: 建议直接在配置中心配置就行,不用@Bean声明 + * + * @return 线程池实例 + */ + @Bean + public DtpExecutor dtpExecutor0() { + return ThreadPoolCreator.createDynamicFast("dtpExecutor0"); + } + + /** + * 通过{@link ThreadPoolBuilder} 设置详细参数创建动态线程池 + * tips: 建议直接在配置中心配置就行,不用@Bean声明 + * @return 线程池实例 + */ + @Bean + public ThreadPoolExecutor dtpExecutor1() { + return ThreadPoolBuilder.newBuilder() + .threadPoolName("dtpExecutor1") + .threadFactory("test-dtp-common") + .corePoolSize(10) + .maximumPoolSize(15) + .keepAliveTime(40) + .timeUnit(TimeUnit.SECONDS) + .workQueue(MEMORY_SAFE_LINKED_BLOCKING_QUEUE.getName(), 2000) + .buildDynamic(); + } + + /** + * 通过{@link ThreadPoolBuilder} 设置详细参数创建动态线程池 + * eager,参考tomcat线程池设计,适用于处理io密集型任务场景,具体参数可以看代码注释 + * tips: 建议直接在配置中心配置就行,不用@Bean声明 + * @return 线程池实例 + */ + @Bean + public DtpExecutor eagerDtpExecutor() { + return ThreadPoolBuilder.newBuilder() + .threadPoolName("eagerDtpExecutor") + .threadFactory("test-eager") + .corePoolSize(2) + .maximumPoolSize(4) + .queueCapacity(2000) + .eager() + .buildDynamic(); + } + + /** + * 通过{@link ThreadPoolBuilder} 设置详细参数创建动态线程池 + * ordered,适用于处理有序任务场景,任务要实现Ordered接口,具体参数可以看代码注释 + * tips: 建议直接在配置中心配置就行,不用@Bean声明 + * @return 线程池实例 + */ + @Bean + public OrderedDtpExecutor orderedDtpExecutor() { + return ThreadPoolBuilder.newBuilder() + .threadPoolName("orderedDtpExecutor") + .threadFactory("test-ordered") + .corePoolSize(4) + .maximumPoolSize(4) + .queueCapacity(2000) + .buildOrdered(); + } + + /** + * 通过{@link ThreadPoolBuilder} 设置详细参数创建线程池 + * scheduled,适用于处理定时任务场景,具体参数可以看代码注释 + * tips: 建议直接在配置中心配置就行,不用@Bean声明 + * @return 线程池实例 + */ + @Bean + public ScheduledExecutorService scheduledDtpExecutor() { + return ThreadPoolBuilder.newBuilder() + .threadPoolName("scheduledDtpExecutor") + .corePoolSize(2) + .threadFactory("test-scheduled") + .rejectedExecutionHandler(CALLER_RUNS_POLICY.getName()) + .buildScheduled(); + } +} diff --git a/example/example-admin/src/main/java/org/dromara/dynamictp/example/controller/TestController.java b/example/example-admin/src/main/java/org/dromara/dynamictp/example/controller/TestController.java new file mode 100644 index 000000000..3b69416df --- /dev/null +++ b/example/example-admin/src/main/java/org/dromara/dynamictp/example/controller/TestController.java @@ -0,0 +1,71 @@ +/* + * 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 org.dromara.dynamictp.example.controller; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.dynamictp.example.service.TestService; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author Redick01 + */ +@Slf4j +@RestController +@AllArgsConstructor +public class TestController { + + private final TestService testService; + + @GetMapping("/dtp-nacos-example/testJucTp") + public String testJuc() { + testService.testJucTp(); + return "testJucTp success"; + } + + @GetMapping("/dtp-nacos-example/testSpringTp") + public String testSpring() { + testService.testSpringTp(); + return "testSpringTp success"; + } + + @GetMapping("/dtp-nacos-example/testCommonDtp") + public String testCommon() { + testService.testCommonDtp(); + return "testCommonDtp success"; + } + + @GetMapping("/dtp-nacos-example/testEagerDtp") + public String testEager() { + testService.testEagerDtp(); + return "testEagerDtp success"; + } + + @GetMapping("/dtp-nacos-example/testScheduledDtp") + public String testScheduled() { + testService.testScheduledDtp(); + return "testScheduledDtp success"; + } + + @GetMapping("/dtp-nacos-example/testOrderedDtp") + public String testOrdered() { + testService.testOrderedDtp(); + return "testOrderedDtp success"; + } +} diff --git a/example/example-admin/src/main/java/org/dromara/dynamictp/example/notifier/SmsClient.java b/example/example-admin/src/main/java/org/dromara/dynamictp/example/notifier/SmsClient.java new file mode 100644 index 000000000..61c3a7b48 --- /dev/null +++ b/example/example-admin/src/main/java/org/dromara/dynamictp/example/notifier/SmsClient.java @@ -0,0 +1,34 @@ +/* + * 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 org.dromara.dynamictp.example.notifier; + +import lombok.extern.slf4j.Slf4j; + +/** + * SmsClient related + * + * @author yanhom + * @since 1.1.0 + */ +@Slf4j +public class SmsClient { + + public void send(String secret, String[] receivers, String content) { + log.info("send sms, secret: {}, receivers: {}, content: {}", secret, receivers, content); + } +} diff --git a/example/example-admin/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java b/example/example-admin/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java new file mode 100644 index 000000000..761568164 --- /dev/null +++ b/example/example-admin/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java @@ -0,0 +1,94 @@ +/* + * 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 org.dromara.dynamictp.example.notifier; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; +import org.dromara.dynamictp.core.notifier.AbstractDtpNotifier; +import org.slf4j.MDC; + +import static org.dromara.dynamictp.common.constant.DynamicTpConst.TRACE_ID; +import static org.dromara.dynamictp.common.constant.DynamicTpConst.UNKNOWN; + +/** + * SmsDtpNotifier related + * + * @author yanhom + * @since 1.1.0 + */ +public class SmsDtpNotifier extends AbstractDtpNotifier { + + public SmsDtpNotifier() { + super(new SmsNotifier(new SmsClient())); + } + + @Override + public String platform() { + return "sms"; + } + + @Override + protected String getNoticeTemplate() { + return SmsNotifyConst.SMS_NOTICE_TEMPLATE; + } + + @Override + protected String getAlarmTemplate() { + return SmsNotifyConst.SMS_ALARM_TEMPLATE; + } + + @Override + protected Pair getColors() { + return null; + } + + @Override + protected String getTraceInfo() { + if (StringUtils.isBlank(MDC.get(TRACE_ID))) { + return UNKNOWN; + } + return "[跳转详情](" + getKibanaUrl(MDC.get(TRACE_ID)) + ")"; + } + + @Override + protected String getExtInfo() { + String extInfo = super.getExtInfo(); + String memoryMetrics = getMemoryMetrics(); + if (StringUtils.isBlank(extInfo)) { + return memoryMetrics; + } + return extInfo + "\n" + memoryMetrics; + } + + private String getKibanaUrl(String traceId) { + return "https://kibana.com/app/kibana#/discover?_g=()&_a=(columns:!(_source),index:'logstash-*',interval:auto,query:(language:lucene,query:'traceId:" + traceId + "'),sort:!('@timestamp',desc))"; + } + + private String getMemoryMetrics() { + int heapInit = 1024; + int heapUsed = 521; + int heapCommitted = 1000; + int heapMax = 1024; + return "MemoryMetrics{" + + "heapInit=" + heapInit + + ", heapUsed=" + heapUsed + + ", heapCommitted=" + heapCommitted + + ", heapMax=" + heapMax + + "}"; + } +} diff --git a/example/example-admin/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifier.java b/example/example-admin/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifier.java new file mode 100644 index 000000000..29c512124 --- /dev/null +++ b/example/example-admin/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifier.java @@ -0,0 +1,47 @@ +/* + * 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 org.dromara.dynamictp.example.notifier; + +import org.dromara.dynamictp.common.entity.NotifyPlatform; +import org.dromara.dynamictp.common.notifier.AbstractNotifier; + +/** + * SmsNotifier related + * + * @author yanhom + * @since 1.1.0 + */ +public class SmsNotifier extends AbstractNotifier { + + private final SmsClient smsClient; + + public SmsNotifier(SmsClient smsClient) { + this.smsClient = smsClient; + } + + @Override + public String platform() { + return "sms"; + } + + @Override + protected void send0(NotifyPlatform platform, String content) { + String[] receivers = platform.getReceivers().split(","); + smsClient.send(platform.getSecret(), receivers, content); + } +} diff --git a/example/example-admin/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java b/example/example-admin/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java new file mode 100644 index 000000000..c7807ffea --- /dev/null +++ b/example/example-admin/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java @@ -0,0 +1,76 @@ +/* + * 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 org.dromara.dynamictp.example.notifier; + +/** + * SmsNotifyConst related + * + * @author yanhom + * @since 1.1.0 + */ +public class SmsNotifyConst { + + private SmsNotifyConst() { } + + public static final String SMS_ALARM_TEMPLATE = + "服务名称:%s \n" + + "实例信息:%s \n" + + "环境:%s \n" + + "线程池名称:%s \n" + + "报警项:%s \n" + + "报警阈值 / 当前值:%s \n" + + "核心线程数:%s \n" + + "最大线程数:%s \n" + + "当前线程数:%s \n" + + "活跃线程数:%s \n" + + "历史最大线程数:%s \n" + + "任务总数:%s \n" + + "执行完成任务数:%s \n" + + "等待执行任务数:%s \n" + + "队列类型:%s \n" + + "队列容量:%s \n" + + "队列任务数量:%s \n" + + "队列剩余容量:%s \n" + + "拒绝策略:%s \n" + + "总拒绝任务数量:%s \n" + + "总执行超时任务数量:%s \n" + + "总等待超时任务数量:%s \n" + + "上次报警时间:%s \n" + + "报警时间:%s \n" + + "接收人:@%s \n" + + "统计周期:%ss \n" + + "静默时长:%ss \n" + + "trace 信息:%s \n" + + "扩展信息:%s \n"; + + public static final String SMS_NOTICE_TEMPLATE = + "服务名称:%s \n" + + "实例信息:%s \n" + + "环境:%s \n" + + "线程池名称:%s \n" + + "核心线程数:%s => %s \n" + + "最大线程数:%s => %s \n" + + "允许核心线程超时:%s => %s \n" + + "线程存活时间:%ss => %ss \n" + + "队列类型:%s \n" + + "队列容量:%s => %s \n" + + "拒绝策略:%s => %s \n" + + "接收人:@%s \n" + + "通知时间:%s \n"; +} + diff --git a/example/example-admin/src/main/java/org/dromara/dynamictp/example/service/TestService.java b/example/example-admin/src/main/java/org/dromara/dynamictp/example/service/TestService.java new file mode 100644 index 000000000..dc96fec65 --- /dev/null +++ b/example/example-admin/src/main/java/org/dromara/dynamictp/example/service/TestService.java @@ -0,0 +1,57 @@ +/* + * 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 org.dromara.dynamictp.example.service; + +/** + * TestService related + * + * @author yanhom + * @since 1.1.0 + */ +public interface TestService { + + /** + * Test juc tp. + */ + void testJucTp(); + + /** + * Test spring tp. + */ + void testSpringTp(); + + /** + * Test common dtp. + */ + void testCommonDtp(); + + /** + * Test eager dtp. + */ + void testEagerDtp(); + + /** + * Test scheduled dtp. + */ + void testScheduledDtp(); + + /** + * Test ordered dtp. + */ + void testOrderedDtp(); +} diff --git a/example/example-admin/src/main/java/org/dromara/dynamictp/example/service/impl/TestServiceImpl.java b/example/example-admin/src/main/java/org/dromara/dynamictp/example/service/impl/TestServiceImpl.java new file mode 100644 index 000000000..047661457 --- /dev/null +++ b/example/example-admin/src/main/java/org/dromara/dynamictp/example/service/impl/TestServiceImpl.java @@ -0,0 +1,175 @@ +/* + * 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 org.dromara.dynamictp.example.service.impl; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.dromara.dynamictp.core.DtpRegistry; +import org.dromara.dynamictp.core.executor.DtpExecutor; +import org.dromara.dynamictp.core.executor.OrderedDtpExecutor; +import org.dromara.dynamictp.core.support.task.runnable.NamedRunnable; +import org.dromara.dynamictp.core.support.task.runnable.OrderedRunnable; +import org.dromara.dynamictp.example.service.TestService; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.stereotype.Service; + +import java.util.concurrent.Executor; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * TestServiceImpl related + * + * @author yanhom + * @since 1.1.0 + */ +@Slf4j +@Service +public class TestServiceImpl implements TestService { + + private final ThreadPoolExecutor jucThreadPoolExecutor; + + private final ThreadPoolTaskExecutor threadPoolTaskExecutor; + + private final DtpExecutor eagerDtpExecutor; + + private final ScheduledExecutorService scheduledDtpExecutor; + + private final OrderedDtpExecutor orderedDtpExecutor; + + public TestServiceImpl(ThreadPoolExecutor jucThreadPoolExecutor, + ThreadPoolTaskExecutor threadPoolTaskExecutor, + DtpExecutor eagerDtpExecutor, + ScheduledExecutorService scheduledDtpExecutor, + OrderedDtpExecutor orderedDtpExecutor) { + this.jucThreadPoolExecutor = jucThreadPoolExecutor; + this.threadPoolTaskExecutor = threadPoolTaskExecutor; + this.eagerDtpExecutor = eagerDtpExecutor; + this.scheduledDtpExecutor = scheduledDtpExecutor; + this.orderedDtpExecutor = orderedDtpExecutor; + } + + @Override + public void testJucTp() { + for (int i = 0; i < 10; i++) { + jucThreadPoolExecutor.execute(() -> { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + log.info("i am a jucThreadPoolExecutor's task"); + }); + } + } + + @Override + public void testSpringTp() { + for (int i = 0; i < 10; i++) { + threadPoolTaskExecutor.execute(() -> { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + log.info("i am a threadPoolTaskExecutor's task"); + }); + } + } + + @Override + public void testCommonDtp() { + Executor dtpExecutor1 = DtpRegistry.getExecutor("dtpExecutor1"); + for (int i = 0; i < 10; i++) { + dtpExecutor1.execute(NamedRunnable.of(() -> { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + log.info("i am a dtpExecutor's task"); + }, "task" + i)); + } + } + + @Override + public void testEagerDtp() { + for (int i = 0; i < 10; i++) { + eagerDtpExecutor.execute(() -> { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + log.info("i am a eagerDtpExecutor's task"); + }); + } + } + + @Override + public void testScheduledDtp() { + scheduledDtpExecutor.scheduleAtFixedRate(() -> { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + log.info("i am a scheduledDtpExecutor's task"); + }, 0, 2, TimeUnit.SECONDS); + } + + @Override + public void testOrderedDtp() { + for (int i = 0; i < 10; i++) { + orderedDtpExecutor.execute(new TestOrderedRunnable(new UserInfo(i, "dtp" + i))); + } + } + + public static class TestOrderedRunnable implements OrderedRunnable { + + private final UserInfo userInfo; + + public TestOrderedRunnable(UserInfo userInfo) { + this.userInfo = userInfo; + } + + @Override + public Object hashKey() { + return userInfo.getUid(); + } + + @Override + public void run() { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + log.info("i am a orderedDtpExecutor's task, userInfo: {}", userInfo); + } + } + + @Data + @AllArgsConstructor + public static class UserInfo { + private long uid; + private String name; + } +} diff --git a/example/example-admin/src/main/java/org/dromara/dynamictp/example/wrapper/CustomTaskWrapper.java b/example/example-admin/src/main/java/org/dromara/dynamictp/example/wrapper/CustomTaskWrapper.java new file mode 100644 index 000000000..b884643b8 --- /dev/null +++ b/example/example-admin/src/main/java/org/dromara/dynamictp/example/wrapper/CustomTaskWrapper.java @@ -0,0 +1,57 @@ +/* + * 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 org.dromara.dynamictp.example.wrapper; + +import lombok.extern.slf4j.Slf4j; +import org.dromara.dynamictp.core.support.task.wrapper.TaskWrapper; + +/** + * CustomTaskWrapper related + * + * @author yanhom + * @since 1.1.0 + */ +@Slf4j +public class CustomTaskWrapper implements TaskWrapper { + + @Override + public String name() { + return "custom"; + } + + @Override + public Runnable wrap(Runnable runnable) { + return new MyRunnable(runnable); + } + + public static class MyRunnable implements Runnable { + + private final Runnable runnable; + + public MyRunnable(Runnable runnable) { + this.runnable = runnable; + } + + @Override + public void run() { + log.info("before run"); + runnable.run(); + log.info("after run"); + } + } +} diff --git a/example/pom.xml b/example/pom.xml index 75ea8f54b..9b220254d 100644 --- a/example/pom.xml +++ b/example/pom.xml @@ -16,6 +16,7 @@ + example-admin example-nacos example-nacos-cloud example-apollo @@ -26,6 +27,7 @@ example-adapter example-polaris-cloud example-huawei-cloud + example-admin diff --git a/sdk/pom.xml b/sdk/pom.xml index 0d3977e9f..002311009 100644 --- a/sdk/pom.xml +++ b/sdk/pom.xml @@ -15,10 +15,6 @@ org.dromara.dynamictp dynamic-tp-core - - org.dromara.dynamictp - dynamic-tp-spring - com.alipay.sofa bolt diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java index 96832f2ff..8a3d73b66 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java @@ -23,16 +23,13 @@ import com.alipay.remoting.exception.RemotingException; import com.alipay.remoting.rpc.RpcClient; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Value; @Slf4j public class AdminClient { - @Value("${dynamictp.admin.ip}") - private String adminIp; + private final String adminIp = "127.0.0.1"; - @Value("${dynamictp.admin.port}") - private int port; + private final int port = 8989; private final RpcClient client = new RpcClient(); @@ -42,12 +39,15 @@ public class AdminClient { public AdminClient() { client.addConnectionEventProcessor(ConnectionEventType.CONNECT, new AdminConnectEventProcessor()); + client.addConnectionEventProcessor(ConnectionEventType.CLOSE, new AdminCloseEventProcessor()); client.registerUserProcessor(new AdminClientUserProcessor()); + client.enableReconnectSwitch(); client.startup(); + log.info("DynamicTp admin client started, admin ip: {}, port: {}", adminIp, port); try { connection = client.createStandaloneConnection(adminIp, port, 30000); } catch (RemotingException e) { - throw new RuntimeException(e); + log.info("DynamicTp admin client is not connected, admin ip: {}, port: {}", adminIp, port); } finally { client.closeStandaloneConnection(connection); client.shutdown(); diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClientUserProcessor.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClientUserProcessor.java index 2dc1bc19a..48b65f3c3 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClientUserProcessor.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClientUserProcessor.java @@ -1,3 +1,20 @@ +/* + * 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 org.dromara.dynamictp.sdk.client; import com.alipay.remoting.BizContext; @@ -23,9 +40,9 @@ public AdminClientUserProcessor() { @Override public Object handleRequest(BizContext bizContext, AdminRequestBody adminRequestBody) throws Exception { - log.info("DynamicTp admin request received:{}",adminRequestBody.getRequestType().getValue()); - if(bizContext.isRequestTimeout()) { - log.warn("DynamicTp admin request timeout:{}s",bizContext.getClientTimeout()); + log.info("DynamicTp admin request received:{}", adminRequestBody.getRequestType().getValue()); + if (bizContext.isRequestTimeout()) { + log.warn("DynamicTp admin request timeout:{}s", bizContext.getClientTimeout()); } this.remoteAddress = bizContext.getRemoteAddress(); return doHandleRequest(adminRequestBody); diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminCloseEventProcessor.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminCloseEventProcessor.java new file mode 100644 index 000000000..9b1dcc08b --- /dev/null +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminCloseEventProcessor.java @@ -0,0 +1,31 @@ +/* + * 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 org.dromara.dynamictp.sdk.client; + +import com.alipay.remoting.Connection; +import com.alipay.remoting.ConnectionEventProcessor; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class AdminCloseEventProcessor implements ConnectionEventProcessor { + @Override + public void onEvent(String remoteAddress, Connection connection) { + log.info("DynamicTp admin client is disconnected, admin ip: {}, port: {}", connection.getRemoteAddress(), connection.getRemotePort()); + + } +} diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminConnectEventProcessor.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminConnectEventProcessor.java index 6390d86b7..50d102acd 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminConnectEventProcessor.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminConnectEventProcessor.java @@ -1,11 +1,30 @@ +/* + * 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 org.dromara.dynamictp.sdk.client; import com.alipay.remoting.Connection; import com.alipay.remoting.ConnectionEventProcessor; +import lombok.extern.slf4j.Slf4j; +@Slf4j public class AdminConnectEventProcessor implements ConnectionEventProcessor { @Override public void onEvent(String remoteAddress, Connection connection) { - + log.info("DynamicTp admin client connected, admin address: {}", remoteAddress); } } diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminRequestBody.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminRequestBody.java index 9de652595..6092375fd 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminRequestBody.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminRequestBody.java @@ -1,3 +1,20 @@ +/* + * 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 org.dromara.dynamictp.sdk.client; import lombok.Getter; diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminRequestTypeEnum.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminRequestTypeEnum.java index 029af87f2..c5b33ce05 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminRequestTypeEnum.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminRequestTypeEnum.java @@ -1,3 +1,20 @@ +/* + * 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 org.dromara.dynamictp.sdk.client; import lombok.AllArgsConstructor; diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/handler/refresher/AdminConfigEvent.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/handler/refresher/AdminConfigEvent.java deleted file mode 100644 index a60e3c46c..000000000 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/handler/refresher/AdminConfigEvent.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.dromara.dynamictp.sdk.handler.refresher; - -import org.springframework.context.ApplicationEvent; - -import java.time.Clock; - -public abstract class AdminConfigEvent extends ApplicationEvent { - public AdminConfigEvent(Object source) { - super(source); - } - - public AdminConfigEvent(Object source, Clock clock) { - super(source, clock); - } - -} diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/handler/refresher/AdminRefresher.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/handler/refresher/AdminRefresher.java deleted file mode 100644 index 4312d48b5..000000000 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/handler/refresher/AdminRefresher.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.dromara.dynamictp.sdk.handler.refresher; - -import org.dromara.dynamictp.common.properties.DtpProperties; -import org.dromara.dynamictp.spring.AbstractSpringRefresher; -import org.springframework.context.ApplicationEvent; -import org.springframework.context.event.SmartApplicationListener; - -public class AdminRefresher extends AbstractSpringRefresher implements SmartApplicationListener { - - protected AdminRefresher(DtpProperties dtpProperties) { - super(dtpProperties); - } - - @Override - public boolean supportsEventType(Class eventType) { - return false; - } - - @Override - public void onApplicationEvent(ApplicationEvent event) { - if (event instanceof AdminConfigEvent) { - refresh(environment); - } - } -} From f9253af5fbd14c4af94170ae3582923c9fe1a16f Mon Sep 17 00:00:00 2001 From: eachannchan Date: Fri, 11 Jul 2025 17:34:27 +0800 Subject: [PATCH 05/21] update --- .../dromara/dynamictp/sdk/client/handler/AdminRefresher.java | 2 ++ .../sdk/client/{ => processor}/AdminClientUserProcessor.java | 0 .../sdk/client/{ => processor}/AdminCloseEventProcessor.java | 0 .../sdk/client/{ => processor}/AdminConnectEventProcessor.java | 0 4 files changed, 2 insertions(+) create mode 100644 sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/AdminRefresher.java rename sdk/src/main/java/org/dromara/dynamictp/sdk/client/{ => processor}/AdminClientUserProcessor.java (100%) rename sdk/src/main/java/org/dromara/dynamictp/sdk/client/{ => processor}/AdminCloseEventProcessor.java (100%) rename sdk/src/main/java/org/dromara/dynamictp/sdk/client/{ => processor}/AdminConnectEventProcessor.java (100%) diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/AdminRefresher.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/AdminRefresher.java new file mode 100644 index 000000000..f0e02dadb --- /dev/null +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/AdminRefresher.java @@ -0,0 +1,2 @@ +package org.dromara.dynamictp.sdk.client.handler;public class AdminRefresher { +} diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClientUserProcessor.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminClientUserProcessor.java similarity index 100% rename from sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClientUserProcessor.java rename to sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminClientUserProcessor.java diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminCloseEventProcessor.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminCloseEventProcessor.java similarity index 100% rename from sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminCloseEventProcessor.java rename to sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminCloseEventProcessor.java diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminConnectEventProcessor.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminConnectEventProcessor.java similarity index 100% rename from sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminConnectEventProcessor.java rename to sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminConnectEventProcessor.java From 2dc29c64d2cf0db90fa50d27cf1751331c9d9009 Mon Sep 17 00:00:00 2001 From: eachannchan Date: Fri, 11 Jul 2025 17:36:17 +0800 Subject: [PATCH 06/21] update --- sdk/pom.xml | 4 ++ .../dynamictp/sdk/client/AdminClient.java | 3 ++ .../sdk/client/AdminRequestBody.java | 38 +++++++++++++------ .../sdk/client/handler/AdminRefresher.java | 24 +++++++++++- .../processor/AdminClientUserProcessor.java | 31 ++++++++++++--- .../processor/AdminCloseEventProcessor.java | 2 +- .../processor/AdminConnectEventProcessor.java | 2 +- .../spring/DtpBaseBeanConfiguration.java | 6 +++ 8 files changed, 90 insertions(+), 20 deletions(-) diff --git a/sdk/pom.xml b/sdk/pom.xml index 002311009..5e834f00d 100644 --- a/sdk/pom.xml +++ b/sdk/pom.xml @@ -11,6 +11,10 @@ dynamic-tp-sdk + + org.springframework + spring-context + org.dromara.dynamictp dynamic-tp-core diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java index 8a3d73b66..411448470 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java @@ -23,6 +23,9 @@ import com.alipay.remoting.exception.RemotingException; import com.alipay.remoting.rpc.RpcClient; import lombok.extern.slf4j.Slf4j; +import org.dromara.dynamictp.sdk.client.processor.AdminClientUserProcessor; +import org.dromara.dynamictp.sdk.client.processor.AdminCloseEventProcessor; +import org.dromara.dynamictp.sdk.client.processor.AdminConnectEventProcessor; @Slf4j public class AdminClient { diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminRequestBody.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminRequestBody.java index e769537ac..46f229f8a 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminRequestBody.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminRequestBody.java @@ -17,15 +17,24 @@ package org.dromara.dynamictp.sdk.client; +import com.caucho.hessian.io.Hessian2Input; +import com.caucho.hessian.io.Hessian2Output; import lombok.Getter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -import java.io.*; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.Serializable; import java.util.concurrent.ThreadLocalRandom; public class AdminRequestBody implements Serializable { private static final long serialVersionUID = -1288207208017808618L; + private static final Logger log = LoggerFactory.getLogger(AdminRequestBody.class); + @Getter private final long id; @@ -45,23 +54,28 @@ public AdminRequestBody(long id, AdminRequestTypeEnum requestType, int size) { this.requestType = requestType; } - public void objectToBytes(Object object) { - try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream)) { + public void serialize(Object object) { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + Hessian2Output objectOutputStream = new Hessian2Output(byteArrayOutputStream); + try { objectOutputStream.writeObject(object); - this.body = byteArrayOutputStream.toByteArray(); + objectOutputStream.flush(); } catch (IOException e) { - throw new RuntimeException(e); + log.warn("DynamicTp admin client serialize failed."); } + this.body = byteArrayOutputStream.toByteArray(); } - public Object bytesToObject() { - try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body); - ObjectInputStream objectOutputStream = new ObjectInputStream(byteArrayInputStream)) { - return objectOutputStream.readObject(); - } catch (IOException | ClassNotFoundException e) { - throw new RuntimeException(e); + public Object deserialize() { + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body); + Hessian2Input objectOutputStream = new Hessian2Input(byteArrayInputStream); + Object object = null; + try { + object = objectOutputStream.readObject(); + } catch (IOException e) { + log.warn("DynamicTp admin client deserialize failed."); } + return object; } } diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/AdminRefresher.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/AdminRefresher.java index f0e02dadb..31e2349bb 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/AdminRefresher.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/AdminRefresher.java @@ -1,2 +1,24 @@ -package org.dromara.dynamictp.sdk.client.handler;public class AdminRefresher { +package org.dromara.dynamictp.sdk.client.handler; + + +import org.dromara.dynamictp.common.properties.DtpProperties; +import org.dromara.dynamictp.core.refresher.AbstractRefresher; +import org.omg.CORBA.Environment; + +import java.util.Map; + +public class AdminRefresher extends AbstractRefresher { + + public AdminRefresher(DtpProperties dtpProperties) { + super(dtpProperties); + } + + @Override + public void refresh(Map properties) { + super.refresh(properties); + } + + public void refresh(Environment environment) { + super.refresh(environment); + } } diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminClientUserProcessor.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminClientUserProcessor.java index 48b65f3c3..9a0d01365 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminClientUserProcessor.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminClientUserProcessor.java @@ -15,18 +15,27 @@ * limitations under the License. */ -package org.dromara.dynamictp.sdk.client; +package org.dromara.dynamictp.sdk.client.processor; import com.alipay.remoting.BizContext; import com.alipay.remoting.rpc.protocol.SyncUserProcessor; import lombok.Getter; import lombok.extern.slf4j.Slf4j; +import org.dromara.dynamictp.common.properties.DtpProperties; +import org.dromara.dynamictp.sdk.client.AdminRequestBody; +import org.dromara.dynamictp.sdk.client.handler.AdminRefresher; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import java.util.Map; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import static org.dromara.dynamictp.core.DtpRegistry.refresh; + @Slf4j +@Component public class AdminClientUserProcessor extends SyncUserProcessor { private final ExecutorService executor; @@ -34,6 +43,9 @@ public class AdminClientUserProcessor extends SyncUserProcessor properties = (Map) adminRequestBody.deserialize(); + if (properties == null) { + log.error("DynamicTp admin request refresh failed, properties is null"); + return null; + } + adminRefresher.refresh(properties); + return adminRequestBody; } private Object handleAlarmManageRequest(AdminRequestBody adminRequestBody) { - return null; + + return adminRequestBody; } private Object handleLogManageRequest(AdminRequestBody adminRequestBody) { - return null; + + return adminRequestBody; } } diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminCloseEventProcessor.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminCloseEventProcessor.java index 9b1dcc08b..3592b395e 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminCloseEventProcessor.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminCloseEventProcessor.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.dromara.dynamictp.sdk.client; +package org.dromara.dynamictp.sdk.client.processor; import com.alipay.remoting.Connection; import com.alipay.remoting.ConnectionEventProcessor; diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminConnectEventProcessor.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminConnectEventProcessor.java index 50d102acd..c32aac576 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminConnectEventProcessor.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminConnectEventProcessor.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.dromara.dynamictp.sdk.client; +package org.dromara.dynamictp.sdk.client.processor; import com.alipay.remoting.Connection; import com.alipay.remoting.ConnectionEventProcessor; diff --git a/spring/src/main/java/org/dromara/dynamictp/spring/DtpBaseBeanConfiguration.java b/spring/src/main/java/org/dromara/dynamictp/spring/DtpBaseBeanConfiguration.java index 22851edef..4f49a27a4 100644 --- a/spring/src/main/java/org/dromara/dynamictp/spring/DtpBaseBeanConfiguration.java +++ b/spring/src/main/java/org/dromara/dynamictp/spring/DtpBaseBeanConfiguration.java @@ -24,6 +24,7 @@ import org.dromara.dynamictp.core.monitor.DtpMonitor; import org.dromara.dynamictp.core.support.DtpBannerPrinter; import org.dromara.dynamictp.sdk.client.AdminClient; +import org.dromara.dynamictp.sdk.client.handler.AdminRefresher; import org.dromara.dynamictp.spring.lifecycle.DtpLifecycleSpringAdapter; import org.dromara.dynamictp.spring.listener.DtpApplicationListener; import org.springframework.beans.factory.config.BeanDefinition; @@ -80,4 +81,9 @@ public DtpApplicationListener dtpApplicationListener() { public AdminClient adminClient() { return new AdminClient(); } + + @Bean + public AdminRefresher adminRefresher(DtpProperties dtpProperties) { + return new AdminRefresher(dtpProperties); + } } From 4b783750738230fe5a5b716ac429b10ba7a9fff1 Mon Sep 17 00:00:00 2001 From: chenyc55879 Date: Sun, 13 Jul 2025 14:11:18 +0800 Subject: [PATCH 07/21] Admin config and dependency related --- sdk/pom.xml | 20 ++++--- .../autoconfigure/AdminAutoConfiguration.java | 52 +++++++++++++++++++ .../dynamictp/sdk/client/AdminClient.java | 34 ++++++------ .../sdk/client/AdminRequestBody.java | 23 ++++---- .../sdk/client/handler/AdminRefresher.java | 24 --------- .../handler/refresh/AdminRefresher.java | 37 +++++++++++++ .../processor/AdminClientUserProcessor.java | 8 ++- .../main/resources/META-INF/spring.factories | 2 + spring/pom.xml | 6 --- .../spring/DtpBaseBeanConfiguration.java | 11 ---- 10 files changed, 133 insertions(+), 84 deletions(-) create mode 100644 sdk/src/main/java/org/dromara/dynamictp/sdk/autoconfigure/AdminAutoConfiguration.java delete mode 100644 sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/AdminRefresher.java create mode 100644 sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/refresh/AdminRefresher.java create mode 100644 sdk/src/main/resources/META-INF/spring.factories diff --git a/sdk/pom.xml b/sdk/pom.xml index 5e834f00d..92548f477 100644 --- a/sdk/pom.xml +++ b/sdk/pom.xml @@ -11,22 +11,26 @@ dynamic-tp-sdk - - org.springframework - spring-context - - - org.dromara.dynamictp - dynamic-tp-core - com.alipay.sofa bolt + com.alipay.sofa.common sofa-common-tools + + + org.dromara.dynamictp + dynamic-tp-spring-boot-starter-common + + + + org.dromara.dynamictp + dynamic-tp-core + + diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/autoconfigure/AdminAutoConfiguration.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/autoconfigure/AdminAutoConfiguration.java new file mode 100644 index 000000000..7c8ff1b4c --- /dev/null +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/autoconfigure/AdminAutoConfiguration.java @@ -0,0 +1,52 @@ +/* + * 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 org.dromara.dynamictp.sdk.autoconfigure; + +import org.dromara.dynamictp.common.properties.DtpProperties; +import org.dromara.dynamictp.sdk.client.AdminClient; +import org.dromara.dynamictp.sdk.client.handler.refresh.AdminRefresher; +import org.dromara.dynamictp.spring.DtpBaseBeanConfiguration; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Lazy; + +/** + * AdminAutoConfiguration related + * + * @author eachann + */ +@Configuration +@ConditionalOnBean({DtpBaseBeanConfiguration.class}) +@AutoConfigureAfter({DtpBaseBeanConfiguration.class}) +public class AdminAutoConfiguration { + + @Bean + @Lazy(false) + public AdminClient adminClient() { + return new AdminClient(); + } + + @Bean + @ConditionalOnMissingBean() + public AdminRefresher adminRefresher(DtpProperties dtpProperties) { + return new AdminRefresher(dtpProperties); + } +} diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java index 411448470..4c296333e 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java @@ -17,7 +17,6 @@ package org.dromara.dynamictp.sdk.client; -import cn.hutool.core.lang.generator.SnowflakeGenerator; import com.alipay.remoting.Connection; import com.alipay.remoting.ConnectionEventType; import com.alipay.remoting.exception.RemotingException; @@ -27,39 +26,42 @@ import org.dromara.dynamictp.sdk.client.processor.AdminCloseEventProcessor; import org.dromara.dynamictp.sdk.client.processor.AdminConnectEventProcessor; +/** + * AdminClient related + * + * @author eachannchan + */ @Slf4j -public class AdminClient { +public class AdminClient extends RpcClient { private final String adminIp = "127.0.0.1"; private final int port = 8989; - private final RpcClient client = new RpcClient(); - private Connection connection; - private final SnowflakeGenerator idGenerator = new SnowflakeGenerator(); public AdminClient() { - client.addConnectionEventProcessor(ConnectionEventType.CONNECT, new AdminConnectEventProcessor()); - client.addConnectionEventProcessor(ConnectionEventType.CLOSE, new AdminCloseEventProcessor()); - client.registerUserProcessor(new AdminClientUserProcessor()); - client.enableReconnectSwitch(); - client.startup(); + super(); + super.addConnectionEventProcessor(ConnectionEventType.CONNECT, new AdminConnectEventProcessor()); + super.addConnectionEventProcessor(ConnectionEventType.CLOSE, new AdminCloseEventProcessor()); + super.registerUserProcessor(new AdminClientUserProcessor()); + super.enableReconnectSwitch(); + super.startup(); log.info("DynamicTp admin client started, admin ip: {}, port: {}", adminIp, port); try { - connection = client.createStandaloneConnection(adminIp, port, 30000); + connection = super.createStandaloneConnection(adminIp, port, 30000); } catch (RemotingException e) { log.info("DynamicTp admin client is not connected, admin ip: {}, port: {}", adminIp, port); } finally { - client.closeStandaloneConnection(connection); - client.shutdown(); + super.closeStandaloneConnection(connection); + super.shutdown(); } } - public Object requestToServer(AdminRequestTypeEnum requestType) throws RemotingException, InterruptedException { - AdminRequestBody requestBody = new AdminRequestBody(idGenerator.next(), requestType); - return client.invokeSync(connection, requestBody, 30000); + public Object requestToServer(AdminRequestTypeEnum requestType, Object body) throws RemotingException, InterruptedException { + AdminRequestBody requestBody = new AdminRequestBody(requestType, body); + return super.invokeSync(connection, requestBody, 30000); } } diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminRequestBody.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminRequestBody.java index 46f229f8a..ed74e72b7 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminRequestBody.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminRequestBody.java @@ -17,24 +17,22 @@ package org.dromara.dynamictp.sdk.client; +import cn.hutool.core.lang.generator.SnowflakeGenerator; import com.caucho.hessian.io.Hessian2Input; import com.caucho.hessian.io.Hessian2Output; import lombok.Getter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import lombok.extern.slf4j.Slf4j; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.Serializable; -import java.util.concurrent.ThreadLocalRandom; +@Slf4j public class AdminRequestBody implements Serializable { private static final long serialVersionUID = -1288207208017808618L; - private static final Logger log = LoggerFactory.getLogger(AdminRequestBody.class); - @Getter private final long id; @@ -43,18 +41,15 @@ public class AdminRequestBody implements Serializable { private byte[] body; - public AdminRequestBody(long id, AdminRequestTypeEnum requestType) { - this(id, requestType, 1024); - } + private final SnowflakeGenerator idGenerator = new SnowflakeGenerator(); - public AdminRequestBody(long id, AdminRequestTypeEnum requestType, int size) { - this.id = id; - this.body = new byte[size]; - ThreadLocalRandom.current().nextBytes(this.body); + public AdminRequestBody(AdminRequestTypeEnum requestType, Object body) { + this.id = idGenerator.next(); + serializeBody(body); this.requestType = requestType; } - public void serialize(Object object) { + private void serializeBody(Object object) { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); Hessian2Output objectOutputStream = new Hessian2Output(byteArrayOutputStream); try { @@ -66,7 +61,7 @@ public void serialize(Object object) { this.body = byteArrayOutputStream.toByteArray(); } - public Object deserialize() { + public Object deserializeBody() { ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body); Hessian2Input objectOutputStream = new Hessian2Input(byteArrayInputStream); Object object = null; diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/AdminRefresher.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/AdminRefresher.java deleted file mode 100644 index 31e2349bb..000000000 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/AdminRefresher.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.dromara.dynamictp.sdk.client.handler; - - -import org.dromara.dynamictp.common.properties.DtpProperties; -import org.dromara.dynamictp.core.refresher.AbstractRefresher; -import org.omg.CORBA.Environment; - -import java.util.Map; - -public class AdminRefresher extends AbstractRefresher { - - public AdminRefresher(DtpProperties dtpProperties) { - super(dtpProperties); - } - - @Override - public void refresh(Map properties) { - super.refresh(properties); - } - - public void refresh(Environment environment) { - super.refresh(environment); - } -} diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/refresh/AdminRefresher.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/refresh/AdminRefresher.java new file mode 100644 index 000000000..488d1eead --- /dev/null +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/refresh/AdminRefresher.java @@ -0,0 +1,37 @@ +/* + * 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 org.dromara.dynamictp.sdk.client.handler.refresh; + + +import org.dromara.dynamictp.common.properties.DtpProperties; +import org.dromara.dynamictp.core.refresher.AbstractRefresher; + +import java.util.Map; + +public class AdminRefresher extends AbstractRefresher { + + public AdminRefresher(DtpProperties dtpProperties) { + super(dtpProperties); + } + + @Override + public void refresh(Map properties) { + super.refresh(properties); + } + +} diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminClientUserProcessor.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminClientUserProcessor.java index 9a0d01365..a87ac9896 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminClientUserProcessor.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminClientUserProcessor.java @@ -21,9 +21,8 @@ import com.alipay.remoting.rpc.protocol.SyncUserProcessor; import lombok.Getter; import lombok.extern.slf4j.Slf4j; -import org.dromara.dynamictp.common.properties.DtpProperties; import org.dromara.dynamictp.sdk.client.AdminRequestBody; -import org.dromara.dynamictp.sdk.client.handler.AdminRefresher; +import org.dromara.dynamictp.sdk.client.handler.refresh.AdminRefresher; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -32,7 +31,6 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import static org.dromara.dynamictp.core.DtpRegistry.refresh; @Slf4j @Component @@ -44,7 +42,7 @@ public class AdminClientUserProcessor extends SyncUserProcessor properties = (Map) adminRequestBody.deserialize(); + Map properties = (Map) adminRequestBody.deserializeBody(); if (properties == null) { log.error("DynamicTp admin request refresh failed, properties is null"); return null; diff --git a/sdk/src/main/resources/META-INF/spring.factories b/sdk/src/main/resources/META-INF/spring.factories new file mode 100644 index 000000000..13372fb9b --- /dev/null +++ b/sdk/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + org.dromara.dynamictp.sdk.autoconfigure.AdminAutoConfiguration \ No newline at end of file diff --git a/spring/pom.xml b/spring/pom.xml index 4d669103d..5492eef02 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -20,12 +20,6 @@ org.dromara.dynamictp dynamic-tp-core - - org.dromara.dynamictp - dynamic-tp-sdk - 1.2.2 - compile - diff --git a/spring/src/main/java/org/dromara/dynamictp/spring/DtpBaseBeanConfiguration.java b/spring/src/main/java/org/dromara/dynamictp/spring/DtpBaseBeanConfiguration.java index 4f49a27a4..d0d7c8302 100644 --- a/spring/src/main/java/org/dromara/dynamictp/spring/DtpBaseBeanConfiguration.java +++ b/spring/src/main/java/org/dromara/dynamictp/spring/DtpBaseBeanConfiguration.java @@ -23,8 +23,6 @@ import org.dromara.dynamictp.core.lifecycle.LifeCycleManagement; import org.dromara.dynamictp.core.monitor.DtpMonitor; import org.dromara.dynamictp.core.support.DtpBannerPrinter; -import org.dromara.dynamictp.sdk.client.AdminClient; -import org.dromara.dynamictp.sdk.client.handler.AdminRefresher; import org.dromara.dynamictp.spring.lifecycle.DtpLifecycleSpringAdapter; import org.dromara.dynamictp.spring.listener.DtpApplicationListener; import org.springframework.beans.factory.config.BeanDefinition; @@ -77,13 +75,4 @@ public DtpApplicationListener dtpApplicationListener() { return new DtpApplicationListener(); } - @Bean - public AdminClient adminClient() { - return new AdminClient(); - } - - @Bean - public AdminRefresher adminRefresher(DtpProperties dtpProperties) { - return new AdminRefresher(dtpProperties); - } } From 31aada854d605fbc60a14c2840302de8fa4f373a Mon Sep 17 00:00:00 2001 From: chenyc55879 Date: Sun, 13 Jul 2025 16:41:04 +0800 Subject: [PATCH 08/21] handle monitor --- .../autoconfigure/AdminAutoConfiguration.java | 8 +++- .../dynamictp/sdk/client/AdminClient.java | 44 ++++++++++--------- .../sdk/client/AdminRequestBody.java | 7 ++- .../handler/collector/AdminCollector.java | 42 ++++++++++++++++++ .../handler/refresh/AdminRefresher.java | 5 +++ .../processor/AdminClientUserProcessor.java | 2 - 6 files changed, 83 insertions(+), 25 deletions(-) create mode 100644 sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/collector/AdminCollector.java diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/autoconfigure/AdminAutoConfiguration.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/autoconfigure/AdminAutoConfiguration.java index 7c8ff1b4c..2a4138cef 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/autoconfigure/AdminAutoConfiguration.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/autoconfigure/AdminAutoConfiguration.java @@ -19,6 +19,7 @@ import org.dromara.dynamictp.common.properties.DtpProperties; import org.dromara.dynamictp.sdk.client.AdminClient; +import org.dromara.dynamictp.sdk.client.handler.collector.AdminCollector; import org.dromara.dynamictp.sdk.client.handler.refresh.AdminRefresher; import org.dromara.dynamictp.spring.DtpBaseBeanConfiguration; import org.springframework.boot.autoconfigure.AutoConfigureAfter; @@ -26,7 +27,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Lazy; /** * AdminAutoConfiguration related @@ -39,7 +39,6 @@ public class AdminAutoConfiguration { @Bean - @Lazy(false) public AdminClient adminClient() { return new AdminClient(); } @@ -49,4 +48,9 @@ public AdminClient adminClient() { public AdminRefresher adminRefresher(DtpProperties dtpProperties) { return new AdminRefresher(dtpProperties); } + + @Bean + public AdminCollector adminCollector() { + return new AdminCollector(); + } } diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java index 4c296333e..76b7fb562 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java @@ -26,42 +26,46 @@ import org.dromara.dynamictp.sdk.client.processor.AdminCloseEventProcessor; import org.dromara.dynamictp.sdk.client.processor.AdminConnectEventProcessor; -/** - * AdminClient related - * - * @author eachannchan - */ @Slf4j -public class AdminClient extends RpcClient { +public class AdminClient { private final String adminIp = "127.0.0.1"; private final int port = 8989; - private Connection connection; + private final RpcClient client = new RpcClient(); + private Connection connection; public AdminClient() { - super(); - super.addConnectionEventProcessor(ConnectionEventType.CONNECT, new AdminConnectEventProcessor()); - super.addConnectionEventProcessor(ConnectionEventType.CLOSE, new AdminCloseEventProcessor()); - super.registerUserProcessor(new AdminClientUserProcessor()); - super.enableReconnectSwitch(); - super.startup(); + client.addConnectionEventProcessor(ConnectionEventType.CONNECT, new AdminConnectEventProcessor()); + client.addConnectionEventProcessor(ConnectionEventType.CLOSE, new AdminCloseEventProcessor()); + client.registerUserProcessor(new AdminClientUserProcessor()); + client.enableReconnectSwitch(); + client.startup(); log.info("DynamicTp admin client started, admin ip: {}, port: {}", adminIp, port); try { - connection = super.createStandaloneConnection(adminIp, port, 30000); + connection = client.createStandaloneConnection(adminIp, port, 30000); } catch (RemotingException e) { - log.info("DynamicTp admin client is not connected, admin ip: {}, port: {}", adminIp, port); + log.info("DynamicTp admin is not connected, admin ip: {}, port: {}", adminIp, port); } finally { - super.closeStandaloneConnection(connection); - super.shutdown(); + client.closeStandaloneConnection(connection); + client.shutdown(); } } - public Object requestToServer(AdminRequestTypeEnum requestType, Object body) throws RemotingException, InterruptedException { - AdminRequestBody requestBody = new AdminRequestBody(requestType, body); - return super.invokeSync(connection, requestBody, 30000); + public Object requestToServer(AdminRequestTypeEnum requestType) throws RemotingException, InterruptedException { + AdminRequestBody requestBody = new AdminRequestBody(requestType); + return client.invokeSync(connection, requestBody, 30000); } + public Object invokeSync(AdminRequestBody adminRequestBody) { + Object object = null; + try { + object = client.invokeSync(connection, adminRequestBody, 5000); + } catch (RemotingException | InterruptedException e) { + log.warn("DynamicTp admin client invoke failed, admin ip: {}, port: {}", adminIp, port); + } + return object; + } } diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminRequestBody.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminRequestBody.java index ed74e72b7..7ff4844c3 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminRequestBody.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminRequestBody.java @@ -43,13 +43,18 @@ public class AdminRequestBody implements Serializable { private final SnowflakeGenerator idGenerator = new SnowflakeGenerator(); + public AdminRequestBody(AdminRequestTypeEnum requestType) { + this.id = idGenerator.next(); + this.requestType = requestType; + } + public AdminRequestBody(AdminRequestTypeEnum requestType, Object body) { this.id = idGenerator.next(); serializeBody(body); this.requestType = requestType; } - private void serializeBody(Object object) { + public void serializeBody(Object object) { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); Hessian2Output objectOutputStream = new Hessian2Output(byteArrayOutputStream); try { diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/collector/AdminCollector.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/collector/AdminCollector.java new file mode 100644 index 000000000..98eef7257 --- /dev/null +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/collector/AdminCollector.java @@ -0,0 +1,42 @@ +/* + * 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 org.dromara.dynamictp.sdk.client.handler.collector; + +import org.dromara.dynamictp.common.entity.ThreadPoolStats; +import org.dromara.dynamictp.core.monitor.collector.AbstractCollector; +import org.dromara.dynamictp.sdk.client.AdminClient; +import org.dromara.dynamictp.sdk.client.AdminRequestBody; +import org.dromara.dynamictp.sdk.client.AdminRequestTypeEnum; +import org.springframework.beans.factory.annotation.Autowired; + +public class AdminCollector extends AbstractCollector { + + @Autowired + private AdminClient adminClient; + + @Override + public void collect(ThreadPoolStats poolStats) { + AdminRequestBody adminRequestBody = new AdminRequestBody(AdminRequestTypeEnum.EXECUTOR_MONITOR, poolStats); + adminClient.invokeSync(adminRequestBody); + } + + @Override + public String type() { + return "admin"; + } +} diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/refresh/AdminRefresher.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/refresh/AdminRefresher.java index 488d1eead..5f83b630b 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/refresh/AdminRefresher.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/refresh/AdminRefresher.java @@ -23,6 +23,11 @@ import java.util.Map; +/** + * AdminRefresher related + * + * @author eachann + */ public class AdminRefresher extends AbstractRefresher { public AdminRefresher(DtpProperties dtpProperties) { diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminClientUserProcessor.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminClientUserProcessor.java index a87ac9896..32c7c7a85 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminClientUserProcessor.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminClientUserProcessor.java @@ -43,7 +43,6 @@ public class AdminClientUserProcessor extends SyncUserProcessor Date: Sun, 13 Jul 2025 20:40:43 +0800 Subject: [PATCH 09/21] update --- dependencies/pom.xml | 6 ++++++ .../src/main/resources/application.yml | 6 ++++++ pom.xml | 2 +- sdk/pom.xml | 16 +++++----------- .../dynamictp/sdk/client/AdminClient.java | 5 ++++- sdk/src/main/resources/application.yml | 4 ---- 6 files changed, 22 insertions(+), 17 deletions(-) create mode 100644 example/example-admin/src/main/resources/application.yml delete mode 100644 sdk/src/main/resources/application.yml diff --git a/dependencies/pom.xml b/dependencies/pom.xml index c92027d38..85a164fa6 100644 --- a/dependencies/pom.xml +++ b/dependencies/pom.xml @@ -389,6 +389,12 @@ ${revision} + + org.dromara.dynamictp + dynamic-tp-sdk + ${revision} + + org.dromara.dynamictp dynamic-tp-spring diff --git a/example/example-admin/src/main/resources/application.yml b/example/example-admin/src/main/resources/application.yml new file mode 100644 index 000000000..4d98230fc --- /dev/null +++ b/example/example-admin/src/main/resources/application.yml @@ -0,0 +1,6 @@ +logging: + level: + org: + springframework: + boot: + autoconfigure: DEBUG \ No newline at end of file diff --git a/pom.xml b/pom.xml index cc1fcdaf4..9d74dd053 100644 --- a/pom.xml +++ b/pom.xml @@ -39,6 +39,7 @@ adapter core common + sdk starter logging example @@ -48,7 +49,6 @@ dependencies spring benchmark - sdk diff --git a/sdk/pom.xml b/sdk/pom.xml index 92548f477..4534e979b 100644 --- a/sdk/pom.xml +++ b/sdk/pom.xml @@ -11,6 +11,11 @@ dynamic-tp-sdk + + org.dromara.dynamictp + dynamic-tp-spring-boot-starter-common + + com.alipay.sofa bolt @@ -20,17 +25,6 @@ com.alipay.sofa.common sofa-common-tools - - - org.dromara.dynamictp - dynamic-tp-spring-boot-starter-common - - - - org.dromara.dynamictp - dynamic-tp-core - - diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java index 76b7fb562..18b0d17c1 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java @@ -19,6 +19,7 @@ import com.alipay.remoting.Connection; import com.alipay.remoting.ConnectionEventType; +import com.alipay.remoting.Url; import com.alipay.remoting.exception.RemotingException; import com.alipay.remoting.rpc.RpcClient; import lombok.extern.slf4j.Slf4j; @@ -33,6 +34,8 @@ public class AdminClient { private final int port = 8989; + private final Url url = new Url(adminIp, port); + private final RpcClient client = new RpcClient(); private Connection connection; @@ -45,7 +48,7 @@ public AdminClient() { client.startup(); log.info("DynamicTp admin client started, admin ip: {}, port: {}", adminIp, port); try { - connection = client.createStandaloneConnection(adminIp, port, 30000); + connection = client.createStandaloneConnection(url.getOriginUrl(), 30000); } catch (RemotingException e) { log.info("DynamicTp admin is not connected, admin ip: {}, port: {}", adminIp, port); } finally { diff --git a/sdk/src/main/resources/application.yml b/sdk/src/main/resources/application.yml deleted file mode 100644 index 8667e7dc6..000000000 --- a/sdk/src/main/resources/application.yml +++ /dev/null @@ -1,4 +0,0 @@ -dynamictp: - admin: - ip: 127.0.0.1 - port: 8989 \ No newline at end of file From 63445a3f616b091c46256e71617d5ffd989aabbc Mon Sep 17 00:00:00 2001 From: chenyc55879 Date: Sun, 27 Jul 2025 00:02:56 +0800 Subject: [PATCH 10/21] complete c/s trans --- common/pom.xml | 5 ++ .../common/em}/AdminRequestTypeEnum.java | 7 +- .../common/entity}/AdminRequestBody.java | 43 +++++------ dependencies/pom.xml | 28 ++++---- example/example-admin/pom.xml | 9 ++- .../example/controller/TestController.java | 7 ++ .../example/service/TestService.java | 4 ++ .../example/service/impl/TestServiceImpl.java | 14 +++- .../src/main/resources/application.yml | 16 +++-- pom.xml | 28 ++++---- .../dynamictp/sdk/client/AdminClient.java | 72 +++++++++++++++---- .../handler/collector/AdminCollector.java | 8 +-- .../processor/AdminClientUserProcessor.java | 7 +- .../processor/AdminCloseEventProcessor.java | 7 +- .../processor/AdminConnectEventProcessor.java | 7 ++ 15 files changed, 176 insertions(+), 86 deletions(-) rename {sdk/src/main/java/org/dromara/dynamictp/sdk/client => common/src/main/java/org/dromara/dynamictp/common/em}/AdminRequestTypeEnum.java (93%) rename {sdk/src/main/java/org/dromara/dynamictp/sdk/client => common/src/main/java/org/dromara/dynamictp/common/entity}/AdminRequestBody.java (51%) diff --git a/common/pom.xml b/common/pom.xml index 9bddaabb5..a80614a49 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -56,6 +56,11 @@ byte-buddy + + com.alipay.sofa + bolt + + org.yaml snakeyaml diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminRequestTypeEnum.java b/common/src/main/java/org/dromara/dynamictp/common/em/AdminRequestTypeEnum.java similarity index 93% rename from sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminRequestTypeEnum.java rename to common/src/main/java/org/dromara/dynamictp/common/em/AdminRequestTypeEnum.java index c5b33ce05..0187e0062 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminRequestTypeEnum.java +++ b/common/src/main/java/org/dromara/dynamictp/common/em/AdminRequestTypeEnum.java @@ -15,11 +15,16 @@ * limitations under the License. */ -package org.dromara.dynamictp.sdk.client; +package org.dromara.dynamictp.common.em; import lombok.AllArgsConstructor; import lombok.Getter; +/** + * Admin request type enum. + * + * @author eachann + */ @Getter @AllArgsConstructor public enum AdminRequestTypeEnum { diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminRequestBody.java b/common/src/main/java/org/dromara/dynamictp/common/entity/AdminRequestBody.java similarity index 51% rename from sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminRequestBody.java rename to common/src/main/java/org/dromara/dynamictp/common/entity/AdminRequestBody.java index 7ff4844c3..df728b451 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminRequestBody.java +++ b/common/src/main/java/org/dromara/dynamictp/common/entity/AdminRequestBody.java @@ -15,17 +15,14 @@ * limitations under the License. */ -package org.dromara.dynamictp.sdk.client; +package org.dromara.dynamictp.common.entity; -import cn.hutool.core.lang.generator.SnowflakeGenerator; -import com.caucho.hessian.io.Hessian2Input; -import com.caucho.hessian.io.Hessian2Output; +import com.alipay.remoting.exception.CodecException; +import com.alipay.remoting.serialization.HessianSerializer; import lombok.Getter; import lombok.extern.slf4j.Slf4j; +import org.dromara.dynamictp.common.em.AdminRequestTypeEnum; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; import java.io.Serializable; @Slf4j @@ -41,39 +38,33 @@ public class AdminRequestBody implements Serializable { private byte[] body; - private final SnowflakeGenerator idGenerator = new SnowflakeGenerator(); - - public AdminRequestBody(AdminRequestTypeEnum requestType) { - this.id = idGenerator.next(); + public AdminRequestBody(long id, AdminRequestTypeEnum requestType) { + this.id = id; this.requestType = requestType; } - public AdminRequestBody(AdminRequestTypeEnum requestType, Object body) { - this.id = idGenerator.next(); + public AdminRequestBody(long id, AdminRequestTypeEnum requestType, Object body) { + this.id = id; serializeBody(body); this.requestType = requestType; } - public void serializeBody(Object object) { - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - Hessian2Output objectOutputStream = new Hessian2Output(byteArrayOutputStream); + private void serializeBody(Object object) { + HessianSerializer serializer = new HessianSerializer(); try { - objectOutputStream.writeObject(object); - objectOutputStream.flush(); - } catch (IOException e) { - log.warn("DynamicTp admin client serialize failed."); + this.body = serializer.serialize(object); + } catch (CodecException e) { + log.error("DynamicTp admin client serialize failed.", e); } - this.body = byteArrayOutputStream.toByteArray(); } public Object deserializeBody() { - ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body); - Hessian2Input objectOutputStream = new Hessian2Input(byteArrayInputStream); + HessianSerializer serializer = new HessianSerializer(); Object object = null; try { - object = objectOutputStream.readObject(); - } catch (IOException e) { - log.warn("DynamicTp admin client deserialize failed."); + object = serializer.deserialize(this.body, null); + } catch (CodecException e) { + log.error("DynamicTp admin client deserialize failed.", e); } return object; } diff --git a/dependencies/pom.xml b/dependencies/pom.xml index 85a164fa6..81bce9729 100644 --- a/dependencies/pom.xml +++ b/dependencies/pom.xml @@ -12,7 +12,7 @@ https://github.com/yanhom1314/dynamic-tp - 1.2.2 + 1.2.3 UTF-8 1.18.24 @@ -727,19 +727,19 @@ - - org.apache.maven.plugins - maven-gpg-plugin - 1.6 - - - verify - - sign - - - - + + + + + + + + + + + + + org.sonatype.central diff --git a/example/example-admin/pom.xml b/example/example-admin/pom.xml index 9568eb471..337fe5629 100644 --- a/example/example-admin/pom.xml +++ b/example/example-admin/pom.xml @@ -4,16 +4,15 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - org.dromara.dynamictp dynamic-tp-example + org.dromara.dynamictp ${revision} ../pom.xml - dynamic-tp-example-admin - + true @@ -32,6 +31,10 @@ ${revision} + + org.dromara.dynamictp + dynamic-tp-sdk + diff --git a/example/example-admin/src/main/java/org/dromara/dynamictp/example/controller/TestController.java b/example/example-admin/src/main/java/org/dromara/dynamictp/example/controller/TestController.java index 3b69416df..5f4d1c196 100644 --- a/example/example-admin/src/main/java/org/dromara/dynamictp/example/controller/TestController.java +++ b/example/example-admin/src/main/java/org/dromara/dynamictp/example/controller/TestController.java @@ -17,6 +17,7 @@ package org.dromara.dynamictp.example.controller; +import com.alipay.remoting.exception.RemotingException; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.dromara.dynamictp.example.service.TestService; @@ -33,6 +34,12 @@ public class TestController { private final TestService testService; + @GetMapping("/dtp-nacos-example/testAdminClient") + public String testAdminClient() throws RemotingException, InterruptedException { + testService.testAdminClient(); + return "testAdminClient success"; + } + @GetMapping("/dtp-nacos-example/testJucTp") public String testJuc() { testService.testJucTp(); diff --git a/example/example-admin/src/main/java/org/dromara/dynamictp/example/service/TestService.java b/example/example-admin/src/main/java/org/dromara/dynamictp/example/service/TestService.java index dc96fec65..dcc11e8b6 100644 --- a/example/example-admin/src/main/java/org/dromara/dynamictp/example/service/TestService.java +++ b/example/example-admin/src/main/java/org/dromara/dynamictp/example/service/TestService.java @@ -17,6 +17,8 @@ package org.dromara.dynamictp.example.service; +import com.alipay.remoting.exception.RemotingException; + /** * TestService related * @@ -25,6 +27,8 @@ */ public interface TestService { + void testAdminClient() throws RemotingException, InterruptedException; + /** * Test juc tp. */ diff --git a/example/example-admin/src/main/java/org/dromara/dynamictp/example/service/impl/TestServiceImpl.java b/example/example-admin/src/main/java/org/dromara/dynamictp/example/service/impl/TestServiceImpl.java index 047661457..50ca53aed 100644 --- a/example/example-admin/src/main/java/org/dromara/dynamictp/example/service/impl/TestServiceImpl.java +++ b/example/example-admin/src/main/java/org/dromara/dynamictp/example/service/impl/TestServiceImpl.java @@ -26,6 +26,8 @@ import org.dromara.dynamictp.core.support.task.runnable.NamedRunnable; import org.dromara.dynamictp.core.support.task.runnable.OrderedRunnable; import org.dromara.dynamictp.example.service.TestService; +import org.dromara.dynamictp.sdk.client.AdminClient; +import org.dromara.dynamictp.common.em.AdminRequestTypeEnum; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Service; @@ -54,16 +56,26 @@ public class TestServiceImpl implements TestService { private final OrderedDtpExecutor orderedDtpExecutor; + private AdminClient adminClient; + public TestServiceImpl(ThreadPoolExecutor jucThreadPoolExecutor, ThreadPoolTaskExecutor threadPoolTaskExecutor, DtpExecutor eagerDtpExecutor, ScheduledExecutorService scheduledDtpExecutor, - OrderedDtpExecutor orderedDtpExecutor) { + OrderedDtpExecutor orderedDtpExecutor, + AdminClient adminClient) { this.jucThreadPoolExecutor = jucThreadPoolExecutor; this.threadPoolTaskExecutor = threadPoolTaskExecutor; this.eagerDtpExecutor = eagerDtpExecutor; this.scheduledDtpExecutor = scheduledDtpExecutor; this.orderedDtpExecutor = orderedDtpExecutor; + this.adminClient = adminClient; + } + + @Override + public void testAdminClient() { + adminClient.requestToServer(AdminRequestTypeEnum.ALARM_MANAGE); + log.info("testAdminClient,remoteAddress:{}", adminClient.getConnection().getRemoteAddress()); } @Override diff --git a/example/example-admin/src/main/resources/application.yml b/example/example-admin/src/main/resources/application.yml index 4d98230fc..2c2970764 100644 --- a/example/example-admin/src/main/resources/application.yml +++ b/example/example-admin/src/main/resources/application.yml @@ -1,6 +1,10 @@ -logging: - level: - org: - springframework: - boot: - autoconfigure: DEBUG \ No newline at end of file +server: + port: 9100 + + +#logging: +# level: +# org: +# springframework: +# boot: +# autoconfigure: DEBUG \ No newline at end of file diff --git a/pom.xml b/pom.xml index 9d74dd053..df35f90d5 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ https://github.com/yanhom1314/dynamic-tp - 1.2.2 + 1.2.3 8 8 @@ -243,19 +243,19 @@ - - org.apache.maven.plugins - maven-gpg-plugin - 1.6 - - - verify - - sign - - - - + + + + + + + + + + + + + org.sonatype.central diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java index 18b0d17c1..cd57a9027 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java @@ -17,12 +17,20 @@ package org.dromara.dynamictp.sdk.client; +import cn.hutool.core.lang.generator.SnowflakeGenerator; import com.alipay.remoting.Connection; import com.alipay.remoting.ConnectionEventType; import com.alipay.remoting.Url; +import com.alipay.remoting.config.Configs; import com.alipay.remoting.exception.RemotingException; import com.alipay.remoting.rpc.RpcClient; +import com.alipay.remoting.serialization.HessianSerializer; +import com.alipay.remoting.serialization.SerializerManager; +import lombok.Getter; +import lombok.Setter; import lombok.extern.slf4j.Slf4j; +import org.dromara.dynamictp.common.entity.AdminRequestBody; +import org.dromara.dynamictp.common.em.AdminRequestTypeEnum; import org.dromara.dynamictp.sdk.client.processor.AdminClientUserProcessor; import org.dromara.dynamictp.sdk.client.processor.AdminCloseEventProcessor; import org.dromara.dynamictp.sdk.client.processor.AdminConnectEventProcessor; @@ -36,9 +44,17 @@ public class AdminClient { private final Url url = new Url(adminIp, port); + @Getter + private static final SnowflakeGenerator SNOWFLAKE_GENERATOR = new SnowflakeGenerator(); + private final RpcClient client = new RpcClient(); - private Connection connection; + @Getter + private static final HessianSerializer SERIALIZER = new HessianSerializer(); + + @Getter + @Setter + private static Connection connection; public AdminClient() { client.addConnectionEventProcessor(ConnectionEventType.CONNECT, new AdminConnectEventProcessor()); @@ -46,29 +62,55 @@ public AdminClient() { client.registerUserProcessor(new AdminClientUserProcessor()); client.enableReconnectSwitch(); client.startup(); - log.info("DynamicTp admin client started, admin ip: {}, port: {}", adminIp, port); - try { - connection = client.createStandaloneConnection(url.getOriginUrl(), 30000); - } catch (RemotingException e) { - log.info("DynamicTp admin is not connected, admin ip: {}, port: {}", adminIp, port); - } finally { - client.closeStandaloneConnection(connection); - client.shutdown(); - } + SerializerManager.addSerializer(1, SERIALIZER); + System.setProperty(Configs.SERIALIZER, String.valueOf(SERIALIZER)); + createConnection(); } - public Object requestToServer(AdminRequestTypeEnum requestType) throws RemotingException, InterruptedException { - AdminRequestBody requestBody = new AdminRequestBody(requestType); - return client.invokeSync(connection, requestBody, 30000); + public Object requestToServer(AdminRequestTypeEnum requestType) { + if (!client.checkConnection(url.getOriginUrl(), true)) { + if (!createConnection()) { + return null; + } + } + AdminRequestBody requestBody = new AdminRequestBody(SNOWFLAKE_GENERATOR.next(), requestType); + + Object object = null; + try { + object = client.invokeSync(connection, requestBody, 30000); + } catch (RemotingException | InterruptedException e) { + log.warn("DynamicTp admin client invoke failed, admin ip: {}, port: {}, exception:", adminIp, port, e); + } + return object; } - public Object invokeSync(AdminRequestBody adminRequestBody) { + public Object requestToServer(AdminRequestBody adminRequestBody) { + if (!client.checkConnection(url.getOriginUrl(), true)) { + if (!createConnection()) { + return null; + } + } Object object = null; try { object = client.invokeSync(connection, adminRequestBody, 5000); } catch (RemotingException | InterruptedException e) { - log.warn("DynamicTp admin client invoke failed, admin ip: {}, port: {}", adminIp, port); + log.warn("DynamicTp admin client invoke failed, admin ip: {}, port: {}, exception:", adminIp, port, e); } return object; } + + private boolean createConnection() { + try { + connection = client.createStandaloneConnection(url.getOriginUrl(), 30000); + } catch (RemotingException e) { + log.warn("DynamicTp admin create connection failed, admin ip: {}, port: {}", adminIp, port, e); + return false; + } + return true; + } + + public void close() { + client.closeStandaloneConnection(connection); + client.shutdown(); + } } diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/collector/AdminCollector.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/collector/AdminCollector.java index 98eef7257..380f5c68f 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/collector/AdminCollector.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/collector/AdminCollector.java @@ -20,8 +20,8 @@ import org.dromara.dynamictp.common.entity.ThreadPoolStats; import org.dromara.dynamictp.core.monitor.collector.AbstractCollector; import org.dromara.dynamictp.sdk.client.AdminClient; -import org.dromara.dynamictp.sdk.client.AdminRequestBody; -import org.dromara.dynamictp.sdk.client.AdminRequestTypeEnum; +import org.dromara.dynamictp.common.entity.AdminRequestBody; +import org.dromara.dynamictp.common.em.AdminRequestTypeEnum; import org.springframework.beans.factory.annotation.Autowired; public class AdminCollector extends AbstractCollector { @@ -31,8 +31,8 @@ public class AdminCollector extends AbstractCollector { @Override public void collect(ThreadPoolStats poolStats) { - AdminRequestBody adminRequestBody = new AdminRequestBody(AdminRequestTypeEnum.EXECUTOR_MONITOR, poolStats); - adminClient.invokeSync(adminRequestBody); + AdminRequestBody adminRequestBody = new AdminRequestBody(AdminClient.getSNOWFLAKE_GENERATOR().next(), AdminRequestTypeEnum.EXECUTOR_MONITOR, poolStats); + adminClient.requestToServer(adminRequestBody); } @Override diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminClientUserProcessor.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminClientUserProcessor.java index 32c7c7a85..a3f3918e0 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminClientUserProcessor.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminClientUserProcessor.java @@ -21,7 +21,7 @@ import com.alipay.remoting.rpc.protocol.SyncUserProcessor; import lombok.Getter; import lombok.extern.slf4j.Slf4j; -import org.dromara.dynamictp.sdk.client.AdminRequestBody; +import org.dromara.dynamictp.common.entity.AdminRequestBody; import org.dromara.dynamictp.sdk.client.handler.refresh.AdminRefresher; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -32,6 +32,11 @@ import java.util.concurrent.Executors; +/** + * AdminClientUserProcessor related + * + * @author eachann + */ @Slf4j @Component public class AdminClientUserProcessor extends SyncUserProcessor { diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminCloseEventProcessor.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminCloseEventProcessor.java index 3592b395e..5eaf03f5f 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminCloseEventProcessor.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminCloseEventProcessor.java @@ -21,11 +21,16 @@ import com.alipay.remoting.ConnectionEventProcessor; import lombok.extern.slf4j.Slf4j; +/** + * AdminCloseEventProcessor related + * + * @author eachann + */ @Slf4j public class AdminCloseEventProcessor implements ConnectionEventProcessor { + @Override public void onEvent(String remoteAddress, Connection connection) { log.info("DynamicTp admin client is disconnected, admin ip: {}, port: {}", connection.getRemoteAddress(), connection.getRemotePort()); - } } diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminConnectEventProcessor.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminConnectEventProcessor.java index c32aac576..72b2ea1ca 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminConnectEventProcessor.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminConnectEventProcessor.java @@ -20,11 +20,18 @@ import com.alipay.remoting.Connection; import com.alipay.remoting.ConnectionEventProcessor; import lombok.extern.slf4j.Slf4j; +import org.dromara.dynamictp.sdk.client.AdminClient; +/** + * AdminConnectEventProcessor related + * + * @author eachann + */ @Slf4j public class AdminConnectEventProcessor implements ConnectionEventProcessor { @Override public void onEvent(String remoteAddress, Connection connection) { + AdminClient.setConnection(connection); log.info("DynamicTp admin client connected, admin address: {}", remoteAddress); } } From 93d842315d7b706485178bc4cc097e2c664beabf Mon Sep 17 00:00:00 2001 From: chenyc55879 Date: Tue, 29 Jul 2025 22:51:52 +0800 Subject: [PATCH 11/21] cpmlete tp metric logic and rebuild c/s connnect logic --- .../common/entity/AdminRequestBody.java | 2 +- .../common/entity/ThreadPoolStats.java | 4 +- .../example-adapter-thrift/pom.xml | 1 - .../src/main/resources/application.yml | 9 ++ .../autoconfigure/AdminAutoConfiguration.java | 1 + .../dynamictp/sdk/client/AdminClient.java | 152 ++++++++++++++++-- .../handler/collector/AdminCollector.java | 80 ++++++++- .../processor/AdminClientUserProcessor.java | 12 +- .../processor/AdminCloseEventProcessor.java | 13 +- .../processor/AdminConnectEventProcessor.java | 8 + 10 files changed, 254 insertions(+), 28 deletions(-) diff --git a/common/src/main/java/org/dromara/dynamictp/common/entity/AdminRequestBody.java b/common/src/main/java/org/dromara/dynamictp/common/entity/AdminRequestBody.java index df728b451..181174ed3 100644 --- a/common/src/main/java/org/dromara/dynamictp/common/entity/AdminRequestBody.java +++ b/common/src/main/java/org/dromara/dynamictp/common/entity/AdminRequestBody.java @@ -49,7 +49,7 @@ public AdminRequestBody(long id, AdminRequestTypeEnum requestType, Object body) this.requestType = requestType; } - private void serializeBody(Object object) { + public void serializeBody(Object object) { HessianSerializer serializer = new HessianSerializer(); try { this.body = serializer.serialize(object); diff --git a/common/src/main/java/org/dromara/dynamictp/common/entity/ThreadPoolStats.java b/common/src/main/java/org/dromara/dynamictp/common/entity/ThreadPoolStats.java index dc6c92ba7..39c124dc2 100644 --- a/common/src/main/java/org/dromara/dynamictp/common/entity/ThreadPoolStats.java +++ b/common/src/main/java/org/dromara/dynamictp/common/entity/ThreadPoolStats.java @@ -20,6 +20,8 @@ import lombok.Data; import lombok.EqualsAndHashCode; +import java.io.Serializable; + /** * ThreadPoolStats related * @@ -28,7 +30,7 @@ **/ @Data @EqualsAndHashCode(callSuper = true) -public class ThreadPoolStats extends Metrics { +public class ThreadPoolStats extends Metrics implements Serializable { /** * 线程池名字 diff --git a/example/example-adapter/example-adapter-thrift/pom.xml b/example/example-adapter/example-adapter-thrift/pom.xml index 5dbd7694f..948992602 100644 --- a/example/example-adapter/example-adapter-thrift/pom.xml +++ b/example/example-adapter/example-adapter-thrift/pom.xml @@ -9,7 +9,6 @@ ../pom.xml dynamic-tp-example-adapter-thrift - true diff --git a/example/example-admin/src/main/resources/application.yml b/example/example-admin/src/main/resources/application.yml index 2c2970764..24dbe4ab2 100644 --- a/example/example-admin/src/main/resources/application.yml +++ b/example/example-admin/src/main/resources/application.yml @@ -1,6 +1,15 @@ server: port: 9100 +spring: + application: + name: dynamic-tp-admin-demo + profiles: + active: dev + redis: + host: ${redis:localhost} + port: 6379 + #logging: # level: diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/autoconfigure/AdminAutoConfiguration.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/autoconfigure/AdminAutoConfiguration.java index 2a4138cef..e8ce32408 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/autoconfigure/AdminAutoConfiguration.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/autoconfigure/AdminAutoConfiguration.java @@ -50,6 +50,7 @@ public AdminRefresher adminRefresher(DtpProperties dtpProperties) { } @Bean + @ConditionalOnMissingBean() public AdminCollector adminCollector() { return new AdminCollector(); } diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java index cd57a9027..4aee7267b 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java @@ -35,6 +35,14 @@ import org.dromara.dynamictp.sdk.client.processor.AdminCloseEventProcessor; import org.dromara.dynamictp.sdk.client.processor.AdminConnectEventProcessor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +/** + * DynamicTp admin client + * + * @author eachann + */ @Slf4j public class AdminClient { @@ -56,9 +64,15 @@ public class AdminClient { @Setter private static Connection connection; + // Connection state management + private final AtomicBoolean isConnected = new AtomicBoolean(false); + private final AtomicInteger retryCount = new AtomicInteger(0); + private static final int MAX_RETRY_COUNT = 3; + private static final long RETRY_DELAY_MS = 1000; + public AdminClient() { - client.addConnectionEventProcessor(ConnectionEventType.CONNECT, new AdminConnectEventProcessor()); - client.addConnectionEventProcessor(ConnectionEventType.CLOSE, new AdminCloseEventProcessor()); + client.addConnectionEventProcessor(ConnectionEventType.CONNECT, new AdminConnectEventProcessor(this)); + client.addConnectionEventProcessor(ConnectionEventType.CLOSE, new AdminCloseEventProcessor(this)); client.registerUserProcessor(new AdminClientUserProcessor()); client.enableReconnectSwitch(); client.startup(); @@ -68,49 +82,161 @@ public AdminClient() { } public Object requestToServer(AdminRequestTypeEnum requestType) { - if (!client.checkConnection(url.getOriginUrl(), true)) { - if (!createConnection()) { - return null; - } + if (!ensureConnection()) { + log.error("DynamicTp admin client cannot establish connection after retries, admin ip: {}, port: {}", + adminIp, port); + return null; } AdminRequestBody requestBody = new AdminRequestBody(SNOWFLAKE_GENERATOR.next(), requestType); - Object object = null; + Object object = null; try { object = client.invokeSync(connection, requestBody, 30000); } catch (RemotingException | InterruptedException e) { log.warn("DynamicTp admin client invoke failed, admin ip: {}, port: {}, exception:", adminIp, port, e); + // Mark connection as disconnected when request fails + isConnected.set(false); } return object; } public Object requestToServer(AdminRequestBody adminRequestBody) { - if (!client.checkConnection(url.getOriginUrl(), true)) { - if (!createConnection()) { - return null; - } + if (!ensureConnection()) { + log.error("DynamicTp admin client cannot establish connection after retries, admin ip: {}, port: {}", + adminIp, port); + return null; } + Object object = null; try { object = client.invokeSync(connection, adminRequestBody, 5000); } catch (RemotingException | InterruptedException e) { log.warn("DynamicTp admin client invoke failed, admin ip: {}, port: {}, exception:", adminIp, port, e); + // Mark connection as disconnected when request fails + isConnected.set(false); } return object; } + /** + * Ensure connection is available, try to reconnect if not available + * + * @return whether connection is available + */ + private boolean ensureConnection() { + // Check connection status + if (isConnected.get() && connection != null && client.checkConnection(url.getOriginUrl(), true)) { + return true; + } + + // Connection not available, try to reconnect + return reconnectWithRetry(); + } + + /** + * Reconnect with retry mechanism + * + * @return whether reconnection is successful + */ + private boolean reconnectWithRetry() { + int currentRetry = 0; + while (currentRetry < MAX_RETRY_COUNT) { + log.info("DynamicTp admin client attempting to reconnect, attempt: {}/{}", currentRetry + 1, + MAX_RETRY_COUNT); + + if (createConnection()) { + isConnected.set(true); + retryCount.set(0); + log.info("DynamicTp admin client reconnected successfully"); + return true; + } + + currentRetry++; + retryCount.incrementAndGet(); + + if (currentRetry < MAX_RETRY_COUNT) { + try { + Thread.sleep(RETRY_DELAY_MS * currentRetry); // Incremental delay + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + log.warn("DynamicTp admin client reconnection interrupted"); + return false; + } + } + } + + log.error("DynamicTp admin client failed to reconnect after {} attempts", MAX_RETRY_COUNT); + return false; + } + private boolean createConnection() { try { + // Clean up old connection + if (connection != null) { + try { + client.closeStandaloneConnection(connection); + } catch (Exception e) { + log.debug("Error closing old connection", e); + } + connection = null; + } + connection = client.createStandaloneConnection(url.getOriginUrl(), 30000); + if (connection != null && connection.isFine()) { + log.info("DynamicTp admin client connection created successfully, admin ip: {}, port: {}", adminIp, + port); + return true; + } else { + log.warn("DynamicTp admin client connection created but not fine, admin ip: {}, port: {}", adminIp, + port); + return false; + } } catch (RemotingException e) { log.warn("DynamicTp admin create connection failed, admin ip: {}, port: {}", adminIp, port, e); return false; } - return true; + } + + /** + * Get current connection status + * + * @return whether connection is available + */ + public boolean isConnected() { + return isConnected.get() && connection != null && connection.isFine(); + } + + /** + * Get retry count + * + * @return retry count + */ + public int getRetryCount() { + return retryCount.get(); + } + + /** + * Update connection status + * + * @param connected whether connected + */ + public void updateConnectionStatus(boolean connected) { + isConnected.set(connected); + if (!connected) { + retryCount.incrementAndGet(); + } } public void close() { - client.closeStandaloneConnection(connection); + isConnected.set(false); + if (connection != null) { + try { + client.closeStandaloneConnection(connection); + } catch (Exception e) { + log.warn("Error closing connection", e); + } + connection = null; + } client.shutdown(); } } diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/collector/AdminCollector.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/collector/AdminCollector.java index 380f5c68f..698ff260d 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/collector/AdminCollector.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/collector/AdminCollector.java @@ -17,22 +17,86 @@ package org.dromara.dynamictp.sdk.client.handler.collector; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; import org.dromara.dynamictp.common.entity.ThreadPoolStats; +import org.dromara.dynamictp.core.DtpRegistry; +import org.dromara.dynamictp.core.converter.ExecutorConverter; import org.dromara.dynamictp.core.monitor.collector.AbstractCollector; -import org.dromara.dynamictp.sdk.client.AdminClient; -import org.dromara.dynamictp.common.entity.AdminRequestBody; -import org.dromara.dynamictp.common.em.AdminRequestTypeEnum; -import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * AdminCollector for collecting thread pool statistics + * Enhanced to support active collection and multiple thread pools + * + * @author eachann + */ +@Slf4j +@Component public class AdminCollector extends AbstractCollector { - @Autowired - private AdminClient adminClient; + @Getter + private ThreadPoolStats poolStats = new ThreadPoolStats(); + + @Getter + private final List multiPoolStats = new CopyOnWriteArrayList<>(); @Override public void collect(ThreadPoolStats poolStats) { - AdminRequestBody adminRequestBody = new AdminRequestBody(AdminClient.getSNOWFLAKE_GENERATOR().next(), AdminRequestTypeEnum.EXECUTOR_MONITOR, poolStats); - adminClient.requestToServer(adminRequestBody); + this.poolStats = poolStats; + // Also store in multiPoolStats for consistency + if (poolStats != null && poolStats.getPoolName() != null) { + // Remove existing stats with same pool name if exists + this.multiPoolStats.removeIf( + stats -> stats.getPoolName() != null && stats.getPoolName().equals(poolStats.getPoolName())); + this.multiPoolStats.add(poolStats); + } + log.debug("AdminCollector collected single pool stats: {}", + poolStats != null ? poolStats.getPoolName() : "null"); + } + + /** + * Actively collect all thread pool statistics from DtpRegistry + * This method can be called independently to refresh data + */ + public void collectAllPoolStats() { + try { + Set executorNames = DtpRegistry.getAllExecutorNames(); + if (executorNames.isEmpty()) { + log.debug("No executors found in DtpRegistry"); + return; + } + + List newStatsList = new ArrayList<>(); + for (String executorName : executorNames) { + try { + ThreadPoolStats stats = ExecutorConverter.toMetrics(DtpRegistry.getExecutorWrapper(executorName)); + if (stats != null) { + newStatsList.add(stats); + } + } catch (Exception e) { + log.warn("Failed to collect stats for executor: {}", executorName, e); + } + } + + // Update multiPoolStats + this.multiPoolStats.clear(); + this.multiPoolStats.addAll(newStatsList); + + // Set the first pool stats as the main poolStats for backward compatibility + if (!newStatsList.isEmpty()) { + this.poolStats = newStatsList.get(0); + } + + log.debug("AdminCollector actively collected {} pool stats", newStatsList.size()); + } catch (Exception e) { + log.error("Failed to collect all pool stats", e); + } } @Override diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminClientUserProcessor.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminClientUserProcessor.java index a3f3918e0..4c3f3b3f4 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminClientUserProcessor.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminClientUserProcessor.java @@ -22,6 +22,7 @@ import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.dromara.dynamictp.common.entity.AdminRequestBody; +import org.dromara.dynamictp.sdk.client.handler.collector.AdminCollector; import org.dromara.dynamictp.sdk.client.handler.refresh.AdminRefresher; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -31,7 +32,6 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; - /** * AdminClientUserProcessor related * @@ -48,6 +48,9 @@ public class AdminClientUserProcessor extends SyncUserProcessor Date: Thu, 14 Aug 2025 14:41:57 +0800 Subject: [PATCH 12/21] muti client rebuild and threadpool manage --- .../common/entity/AdminRequestBody.java | 5 +- .../common/entity/AttributeRequestBody.java | 54 +++++ .../DtpPropertiesSerializable.java | 225 ++++++++++++++++++ .../example/service/impl/TestServiceImpl.java | 2 +- .../src/main/resources/application.yml | 2 + example/pom.xml | 4 +- .../autoconfigure/AdminAutoConfiguration.java | 33 ++- .../AdminConfigEnvironmentProcessor.java | 76 ++++++ .../dynamictp/sdk/client/AdminClient.java | 52 ++-- .../handler/collector/AdminCollector.java | 24 +- .../handler/refresh/AdminRefresher.java | 12 +- .../processor/AdminClientUserProcessor.java | 16 +- .../main/resources/META-INF/spring.factories | 4 +- .../DtpBeanDefinitionRegistrar.java | 5 +- 14 files changed, 449 insertions(+), 65 deletions(-) create mode 100644 common/src/main/java/org/dromara/dynamictp/common/entity/AttributeRequestBody.java create mode 100644 common/src/main/java/org/dromara/dynamictp/common/serializable/DtpPropertiesSerializable.java create mode 100644 sdk/src/main/java/org/dromara/dynamictp/sdk/autoconfigure/AdminConfigEnvironmentProcessor.java diff --git a/common/src/main/java/org/dromara/dynamictp/common/entity/AdminRequestBody.java b/common/src/main/java/org/dromara/dynamictp/common/entity/AdminRequestBody.java index 181174ed3..77fca9775 100644 --- a/common/src/main/java/org/dromara/dynamictp/common/entity/AdminRequestBody.java +++ b/common/src/main/java/org/dromara/dynamictp/common/entity/AdminRequestBody.java @@ -25,10 +25,13 @@ import java.io.Serializable; +/** + * @author eachann + */ @Slf4j public class AdminRequestBody implements Serializable { - private static final long serialVersionUID = -1288207208017808618L; + private static final long serialVersionUID = -1288207208017808618L; @Getter private final long id; diff --git a/common/src/main/java/org/dromara/dynamictp/common/entity/AttributeRequestBody.java b/common/src/main/java/org/dromara/dynamictp/common/entity/AttributeRequestBody.java new file mode 100644 index 000000000..c40f175cc --- /dev/null +++ b/common/src/main/java/org/dromara/dynamictp/common/entity/AttributeRequestBody.java @@ -0,0 +1,54 @@ +/* + * 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 org.dromara.dynamictp.common.entity; + + +import lombok.Getter; +import lombok.Setter; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +/** + * @author eachann + */ +public class AttributeRequestBody implements Serializable { + + private static final long serialVersionUID = -1288207208017808630L; + + @Setter + @Getter + private String message; + + @Getter + private final Map attributes; + + public AttributeRequestBody() { + this.attributes = new HashMap<>(); + } + + public void setAttribute(String key, String value) { + this.attributes.put(key, value); + } + + public String getAttribute(String key) { + return this.attributes.get(key); + } + +} diff --git a/common/src/main/java/org/dromara/dynamictp/common/serializable/DtpPropertiesSerializable.java b/common/src/main/java/org/dromara/dynamictp/common/serializable/DtpPropertiesSerializable.java new file mode 100644 index 000000000..17f6708cd --- /dev/null +++ b/common/src/main/java/org/dromara/dynamictp/common/serializable/DtpPropertiesSerializable.java @@ -0,0 +1,225 @@ +/* + * 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 org.dromara.dynamictp.common.serializable; + +import com.google.common.collect.Lists; +import lombok.Data; +import org.dromara.dynamictp.common.em.CollectorTypeEnum; +import org.dromara.dynamictp.common.entity.DtpExecutorProps; +import org.dromara.dynamictp.common.entity.NotifyPlatform; +import org.dromara.dynamictp.common.entity.TpExecutorProps; + +import java.io.Serializable; +import java.util.List; + +/** + * Main properties that maintain by config center. + * + * @author yanhom + * @since 1.0.0 + **/ +@Data +public class DtpPropertiesSerializable implements Serializable { + + private DtpPropertiesSerializable() { } + + /** + * If enabled DynamicTp. + */ + private boolean enabled = true; + + /** + * Environment, if not set, will use "APP.ENV". + */ + private String env; + + /** + * If print banner. + */ + private boolean enabledBanner = true; + + /** + * If enabled metrics collect. + */ + private boolean enabledCollect = true; + + /** + * Metrics collector types, default is logging. + */ + private List collectorTypes = Lists.newArrayList(CollectorTypeEnum.MICROMETER.name()); + + /** + * Metrics log storage path, just for "logging" type. + */ + private String logPath; + + /** + * Config file type, for zookeeper and etcd. + */ + private String configType; + + /** + * Monitor interval, time unit(s) + */ + private int monitorInterval = 5; + + /** + * Notify platform configs. + */ + private List platforms; + + /** + * Zookeeper config. + */ + private Zookeeper zookeeper; + + /** + * Etcd config. + */ + private Etcd etcd; + + /** + * ThreadPoolExecutor global configs. + */ + private DtpExecutorProps globalExecutorProps; + + /** + * ThreadPoolExecutor configs. + */ + private List executors; + + /** + * Tomcat worker thread pool. + */ + private TpExecutorProps tomcatTp; + + /** + * Jetty thread pool. + */ + private TpExecutorProps jettyTp; + + /** + * Undertow thread pool. + */ + private TpExecutorProps undertowTp; + + /** + * Dubbo thread pools. + */ + private List dubboTp; + + /** + * Hystrix thread pools. + */ + private List hystrixTp; + + /** + * RocketMq thread pools. + */ + private List rocketMqTp; + + /** + * Grpc thread pools. + */ + private List grpcTp; + + /** + * Motan server thread pools. + */ + private List motanTp; + + /** + * Okhttp3 thread pools. + */ + private List okhttp3Tp; + + /** + * Brpc thread pools. + */ + private List brpcTp; + + /** + * Tars thread pools. + */ + private List tarsTp; + + /** + * Sofa thread pools. + */ + private List sofaTp; + + /** + * Rabbitmq thread pools. + */ + private List rabbitmqTp; + + /** + * Liteflow thread pools. + */ + private List liteflowTp; + + /** + * Thrift thread pools. + */ + private List thriftTp; + + public static DtpPropertiesSerializable getInstance() { + return Holder.INSTANCE; + } + + @Data + public static class Zookeeper { + + private String zkConnectStr; + + private String configVersion; + + private String rootNode; + + private String node; + + private String configKey; + } + + /** + * Etcd config. + */ + @Data + public static class Etcd { + + private String endpoints; + + private String user; + + private String password; + + private String charset = "UTF-8"; + + private boolean authEnable = false; + + private String authority = "ssl"; + + private String key; + + private long timeout = 30000L; + } + + private static class Holder { + private static final DtpPropertiesSerializable INSTANCE = new DtpPropertiesSerializable(); + } +} diff --git a/example/example-admin/src/main/java/org/dromara/dynamictp/example/service/impl/TestServiceImpl.java b/example/example-admin/src/main/java/org/dromara/dynamictp/example/service/impl/TestServiceImpl.java index 50ca53aed..ec06b3f11 100644 --- a/example/example-admin/src/main/java/org/dromara/dynamictp/example/service/impl/TestServiceImpl.java +++ b/example/example-admin/src/main/java/org/dromara/dynamictp/example/service/impl/TestServiceImpl.java @@ -56,7 +56,7 @@ public class TestServiceImpl implements TestService { private final OrderedDtpExecutor orderedDtpExecutor; - private AdminClient adminClient; + private AdminClient adminClient; public TestServiceImpl(ThreadPoolExecutor jucThreadPoolExecutor, ThreadPoolTaskExecutor threadPoolTaskExecutor, diff --git a/example/example-admin/src/main/resources/application.yml b/example/example-admin/src/main/resources/application.yml index 24dbe4ab2..10a182e0f 100644 --- a/example/example-admin/src/main/resources/application.yml +++ b/example/example-admin/src/main/resources/application.yml @@ -10,6 +10,8 @@ spring: host: ${redis:localhost} port: 6379 +dynamictp: + clientName: dynamic-tp-admin-demo #logging: # level: diff --git a/example/pom.xml b/example/pom.xml index 9b220254d..91be65833 100644 --- a/example/pom.xml +++ b/example/pom.xml @@ -24,10 +24,10 @@ example-zookeeper-cloud example-consul-cloud example-etcd - example-adapter + example-polaris-cloud example-huawei-cloud - example-admin + diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/autoconfigure/AdminAutoConfiguration.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/autoconfigure/AdminAutoConfiguration.java index e8ce32408..231caf737 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/autoconfigure/AdminAutoConfiguration.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/autoconfigure/AdminAutoConfiguration.java @@ -21,6 +21,9 @@ import org.dromara.dynamictp.sdk.client.AdminClient; import org.dromara.dynamictp.sdk.client.handler.collector.AdminCollector; import org.dromara.dynamictp.sdk.client.handler.refresh.AdminRefresher; +import org.dromara.dynamictp.sdk.client.processor.AdminClientUserProcessor; +import org.dromara.dynamictp.sdk.client.processor.AdminCloseEventProcessor; +import org.dromara.dynamictp.sdk.client.processor.AdminConnectEventProcessor; import org.dromara.dynamictp.spring.DtpBaseBeanConfiguration; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; @@ -34,24 +37,38 @@ * @author eachann */ @Configuration -@ConditionalOnBean({DtpBaseBeanConfiguration.class}) -@AutoConfigureAfter({DtpBaseBeanConfiguration.class}) +@ConditionalOnBean({ DtpBaseBeanConfiguration.class }) +@AutoConfigureAfter({ DtpBaseBeanConfiguration.class }) public class AdminAutoConfiguration { @Bean - public AdminClient adminClient() { - return new AdminClient(); + public AdminClient adminClient(AdminClientUserProcessor adminClientUserProcessor) { + return new AdminClient(adminClientUserProcessor); } @Bean - @ConditionalOnMissingBean() + public AdminCollector adminCollector() { + return new AdminCollector(); + } + + @Bean + @ConditionalOnMissingBean public AdminRefresher adminRefresher(DtpProperties dtpProperties) { return new AdminRefresher(dtpProperties); } + @Bean + public AdminClientUserProcessor adminClientUserProcessor(AdminRefresher adminRefresher) { + return new AdminClientUserProcessor(adminRefresher); + } @Bean - @ConditionalOnMissingBean() - public AdminCollector adminCollector() { - return new AdminCollector(); + public AdminConnectEventProcessor adminConnectEventProcessor(AdminClient adminClient) { + return new AdminConnectEventProcessor(adminClient); + } + + @Bean + public AdminCloseEventProcessor adminCloseEventProcessor(AdminClient adminClient) { + return new AdminCloseEventProcessor(adminClient); } + } diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/autoconfigure/AdminConfigEnvironmentProcessor.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/autoconfigure/AdminConfigEnvironmentProcessor.java new file mode 100644 index 000000000..49ac7b4f4 --- /dev/null +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/autoconfigure/AdminConfigEnvironmentProcessor.java @@ -0,0 +1,76 @@ +/* + * 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 org.dromara.dynamictp.sdk.autoconfigure; + +import lombok.extern.slf4j.Slf4j; +import org.dromara.dynamictp.common.em.AdminRequestTypeEnum; +import org.dromara.dynamictp.common.properties.DtpProperties; +import org.dromara.dynamictp.core.support.binder.BinderHelper; +import org.dromara.dynamictp.sdk.client.AdminClient; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.env.EnvironmentPostProcessor; +import org.springframework.boot.env.OriginTrackedMapPropertySource; +import org.springframework.core.Ordered; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.MutablePropertySources; + +import java.util.Map; + +/** + * ZkConfigEnvironmentProcessor related + * + * @author yanhom + * @since 1.0.4 + **/ +@Slf4j +public class AdminConfigEnvironmentProcessor implements EnvironmentPostProcessor, Ordered { + +// AdminClient adminClient; + +// public AdminConfigEnvironmentProcessor(AdminClient adminClient) { +// this.adminClient = adminClient; +// } + + public static final String ADMIN_PROPERTY_SOURCE_NAME = "dtpAdminPropertySource"; + + @Override + public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { +// DtpProperties dtpProperties = DtpProperties.getInstance(); +// BinderHelper.bindDtpProperties(environment, dtpProperties); +// Map properties = (Map) adminClient.requestToServer(AdminRequestTypeEnum.EXECUTOR_REFRESH); +// if (!checkPropertyExist(environment)) { +// createAdminPropertySource(environment, properties); +// } + } + + private boolean checkPropertyExist(ConfigurableEnvironment environment) { + MutablePropertySources propertySources = environment.getPropertySources(); + return propertySources.stream().anyMatch(p -> ADMIN_PROPERTY_SOURCE_NAME.equals(p.getName())); + } + + private void createAdminPropertySource(ConfigurableEnvironment environment, Map properties) { + MutablePropertySources propertySources = environment.getPropertySources(); + OriginTrackedMapPropertySource adminSource = new OriginTrackedMapPropertySource(ADMIN_PROPERTY_SOURCE_NAME, properties); + propertySources.addLast(adminSource); + } + + @Override + public int getOrder() { + return Ordered.LOWEST_PRECEDENCE; + } +} diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java index 4aee7267b..dac3aa003 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java @@ -31,13 +31,17 @@ import lombok.extern.slf4j.Slf4j; import org.dromara.dynamictp.common.entity.AdminRequestBody; import org.dromara.dynamictp.common.em.AdminRequestTypeEnum; +import org.dromara.dynamictp.common.entity.AttributeRequestBody; import org.dromara.dynamictp.sdk.client.processor.AdminClientUserProcessor; import org.dromara.dynamictp.sdk.client.processor.AdminCloseEventProcessor; import org.dromara.dynamictp.sdk.client.processor.AdminConnectEventProcessor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; -import java.util.concurrent.TimeUnit; +import javax.annotation.PostConstruct; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; + /** * DynamicTp admin client * @@ -48,9 +52,12 @@ public class AdminClient { private final String adminIp = "127.0.0.1"; - private final int port = 8989; + private final int adminPort = 8989; + + private final Url adminUrl = new Url(adminIp, adminPort); - private final Url url = new Url(adminIp, port); + @Value("${dynamictp.clientName:${spring.application.name}}") + private String clientName; @Getter private static final SnowflakeGenerator SNOWFLAKE_GENERATOR = new SnowflakeGenerator(); @@ -70,30 +77,36 @@ public class AdminClient { private static final int MAX_RETRY_COUNT = 3; private static final long RETRY_DELAY_MS = 1000; - public AdminClient() { + public AdminClient(AdminClientUserProcessor adminClientUserProcessor) { client.addConnectionEventProcessor(ConnectionEventType.CONNECT, new AdminConnectEventProcessor(this)); client.addConnectionEventProcessor(ConnectionEventType.CLOSE, new AdminCloseEventProcessor(this)); - client.registerUserProcessor(new AdminClientUserProcessor()); + client.registerUserProcessor(adminClientUserProcessor); client.enableReconnectSwitch(); client.startup(); SerializerManager.addSerializer(1, SERIALIZER); System.setProperty(Configs.SERIALIZER, String.valueOf(SERIALIZER)); + } + + @PostConstruct + public void init() { createConnection(); } public Object requestToServer(AdminRequestTypeEnum requestType) { if (!ensureConnection()) { log.error("DynamicTp admin client cannot establish connection after retries, admin ip: {}, port: {}", - adminIp, port); + adminIp, adminPort); return null; } + AttributeRequestBody attributeRequestBody = new AttributeRequestBody(); + attributeRequestBody.setAttribute("clientName", clientName); AdminRequestBody requestBody = new AdminRequestBody(SNOWFLAKE_GENERATOR.next(), requestType); - Object object = null; try { + client.invokeSync(connection, attributeRequestBody, 5000); object = client.invokeSync(connection, requestBody, 30000); } catch (RemotingException | InterruptedException e) { - log.warn("DynamicTp admin client invoke failed, admin ip: {}, port: {}, exception:", adminIp, port, e); + log.warn("DynamicTp admin client invoke failed, admin ip: {}, port: {}, exception:", adminIp, adminPort, e); // Mark connection as disconnected when request fails isConnected.set(false); } @@ -103,15 +116,17 @@ public Object requestToServer(AdminRequestTypeEnum requestType) { public Object requestToServer(AdminRequestBody adminRequestBody) { if (!ensureConnection()) { log.error("DynamicTp admin client cannot establish connection after retries, admin ip: {}, port: {}", - adminIp, port); + adminIp, adminPort); return null; } - + AttributeRequestBody attributeRequestBody = new AttributeRequestBody(); + attributeRequestBody.setAttribute("clientName", clientName); Object object = null; try { + client.invokeSync(connection, attributeRequestBody, 5000); object = client.invokeSync(connection, adminRequestBody, 5000); } catch (RemotingException | InterruptedException e) { - log.warn("DynamicTp admin client invoke failed, admin ip: {}, port: {}, exception:", adminIp, port, e); + log.warn("DynamicTp admin client invoke failed, admin ip: {}, port: {}, exception:", adminIp, adminPort, e); // Mark connection as disconnected when request fails isConnected.set(false); } @@ -125,7 +140,7 @@ public Object requestToServer(AdminRequestBody adminRequestBody) { */ private boolean ensureConnection() { // Check connection status - if (isConnected.get() && connection != null && client.checkConnection(url.getOriginUrl(), true)) { + if (isConnected.get() && connection != null && client.checkConnection(adminUrl.getOriginUrl(), true)) { return true; } @@ -181,18 +196,21 @@ private boolean createConnection() { connection = null; } - connection = client.createStandaloneConnection(url.getOriginUrl(), 30000); + connection = client.createStandaloneConnection(adminUrl.getOriginUrl(), 30000); if (connection != null && connection.isFine()) { log.info("DynamicTp admin client connection created successfully, admin ip: {}, port: {}", adminIp, - port); + adminPort); + AttributeRequestBody attributeRequestBody = new AttributeRequestBody(); + attributeRequestBody.setAttribute("clientName", clientName); + client.invokeSync(connection, attributeRequestBody, 5000); return true; } else { log.warn("DynamicTp admin client connection created but not fine, admin ip: {}, port: {}", adminIp, - port); + adminPort); return false; } - } catch (RemotingException e) { - log.warn("DynamicTp admin create connection failed, admin ip: {}, port: {}", adminIp, port, e); + } catch (RemotingException | InterruptedException e) { + log.warn("DynamicTp admin create connection failed, admin ip: {}, port: {}", adminIp, adminPort, e); return false; } } diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/collector/AdminCollector.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/collector/AdminCollector.java index 698ff260d..2bdb95af9 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/collector/AdminCollector.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/collector/AdminCollector.java @@ -22,8 +22,6 @@ import org.dromara.dynamictp.common.entity.ThreadPoolStats; import org.dromara.dynamictp.core.DtpRegistry; import org.dromara.dynamictp.core.converter.ExecutorConverter; -import org.dromara.dynamictp.core.monitor.collector.AbstractCollector; -import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; @@ -37,8 +35,7 @@ * @author eachann */ @Slf4j -@Component -public class AdminCollector extends AbstractCollector { +public class AdminCollector { @Getter private ThreadPoolStats poolStats = new ThreadPoolStats(); @@ -46,20 +43,6 @@ public class AdminCollector extends AbstractCollector { @Getter private final List multiPoolStats = new CopyOnWriteArrayList<>(); - @Override - public void collect(ThreadPoolStats poolStats) { - this.poolStats = poolStats; - // Also store in multiPoolStats for consistency - if (poolStats != null && poolStats.getPoolName() != null) { - // Remove existing stats with same pool name if exists - this.multiPoolStats.removeIf( - stats -> stats.getPoolName() != null && stats.getPoolName().equals(poolStats.getPoolName())); - this.multiPoolStats.add(poolStats); - } - log.debug("AdminCollector collected single pool stats: {}", - poolStats != null ? poolStats.getPoolName() : "null"); - } - /** * Actively collect all thread pool statistics from DtpRegistry * This method can be called independently to refresh data @@ -98,9 +81,4 @@ public void collectAllPoolStats() { log.error("Failed to collect all pool stats", e); } } - - @Override - public String type() { - return "admin"; - } } diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/refresh/AdminRefresher.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/refresh/AdminRefresher.java index 5f83b630b..d6bf23282 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/refresh/AdminRefresher.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/refresh/AdminRefresher.java @@ -18,17 +18,22 @@ package org.dromara.dynamictp.sdk.client.handler.refresh; +import lombok.extern.slf4j.Slf4j; import org.dromara.dynamictp.common.properties.DtpProperties; import org.dromara.dynamictp.core.refresher.AbstractRefresher; +import org.dromara.dynamictp.spring.AbstractSpringRefresher; +import org.springframework.beans.factory.InitializingBean; import java.util.Map; + /** * AdminRefresher related * * @author eachann */ -public class AdminRefresher extends AbstractRefresher { +@Slf4j +public class AdminRefresher extends AbstractSpringRefresher implements InitializingBean { public AdminRefresher(DtpProperties dtpProperties) { super(dtpProperties); @@ -36,7 +41,12 @@ public AdminRefresher(DtpProperties dtpProperties) { @Override public void refresh(Map properties) { + log.info("Dynamic-tp adminRefresher refresh properties"); super.refresh(properties); } + @Override + public void afterPropertiesSet() { + + } } diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminClientUserProcessor.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminClientUserProcessor.java index 4c3f3b3f4..becf51517 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminClientUserProcessor.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminClientUserProcessor.java @@ -38,7 +38,6 @@ * @author eachann */ @Slf4j -@Component public class AdminClientUserProcessor extends SyncUserProcessor { private final ExecutorService executor; @@ -46,13 +45,14 @@ public class AdminClientUserProcessor extends SyncUserProcessor properties = (Map) adminRequestBody.deserializeBody(); + Object properties = adminRequestBody.deserializeBody(); if (properties == null) { - log.error("DynamicTp admin request refresh failed, properties is null"); + log.error("DynamicTp admin executor refresh failed, properties is null"); return null; } - adminRefresher.refresh(properties); + adminRefresher.refresh((Map) properties); return adminRequestBody; } @@ -117,5 +116,4 @@ private Object handleLogManageRequest(AdminRequestBody adminRequestBody) { return adminRequestBody; } - } diff --git a/sdk/src/main/resources/META-INF/spring.factories b/sdk/src/main/resources/META-INF/spring.factories index 13372fb9b..ed9c7bf6c 100644 --- a/sdk/src/main/resources/META-INF/spring.factories +++ b/sdk/src/main/resources/META-INF/spring.factories @@ -1,2 +1,4 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ - org.dromara.dynamictp.sdk.autoconfigure.AdminAutoConfiguration \ No newline at end of file + org.dromara.dynamictp.sdk.autoconfigure.AdminAutoConfiguration +org.springframework.boot.env.EnvironmentPostProcessor=\ + org.dromara.dynamictp.sdk.autoconfigure.AdminConfigEnvironmentProcessor diff --git a/spring/src/main/java/org/dromara/dynamictp/spring/annotation/DtpBeanDefinitionRegistrar.java b/spring/src/main/java/org/dromara/dynamictp/spring/annotation/DtpBeanDefinitionRegistrar.java index d0d7c8c89..b4dc1491a 100644 --- a/spring/src/main/java/org/dromara/dynamictp/spring/annotation/DtpBeanDefinitionRegistrar.java +++ b/spring/src/main/java/org/dromara/dynamictp/spring/annotation/DtpBeanDefinitionRegistrar.java @@ -129,7 +129,8 @@ private Object[] buildConstructorArgs(Class clazz, DtpExecutorProps props) { if (clazz.equals(EagerDtpExecutor.class)) { taskQueue = new TaskQueue(props.getQueueCapacity()); } else if (clazz.equals(PriorityDtpExecutor.class)) { - taskQueue = new PriorityBlockingQueue<>(props.getQueueCapacity(), PriorityDtpExecutor.getRunnableComparator()); + taskQueue = new PriorityBlockingQueue<>(props.getQueueCapacity(), + PriorityDtpExecutor.getRunnableComparator()); } else { taskQueue = buildLbq(props.getQueueType(), props.getQueueCapacity(), @@ -137,7 +138,7 @@ private Object[] buildConstructorArgs(Class clazz, DtpExecutorProps props) { props.getMaxFreeMemory()); } - return new Object[]{ + return new Object[] { props.getCorePoolSize(), props.getMaximumPoolSize(), props.getKeepAliveTime(), From 723f1856108ef890777d52f7f475943ecf00509b Mon Sep 17 00:00:00 2001 From: chenyc55879 Date: Fri, 15 Aug 2025 14:52:29 +0800 Subject: [PATCH 13/21] add Register pt logic --- .../DtpPropertiesSerializable.java | 225 ------------------ .../AdminConfigEnvironmentProcessor.java | 35 ++- .../dynamictp/sdk/client/AdminClient.java | 14 ++ .../processor/AdminClientUserProcessor.java | 4 + 4 files changed, 41 insertions(+), 237 deletions(-) delete mode 100644 common/src/main/java/org/dromara/dynamictp/common/serializable/DtpPropertiesSerializable.java diff --git a/common/src/main/java/org/dromara/dynamictp/common/serializable/DtpPropertiesSerializable.java b/common/src/main/java/org/dromara/dynamictp/common/serializable/DtpPropertiesSerializable.java deleted file mode 100644 index 17f6708cd..000000000 --- a/common/src/main/java/org/dromara/dynamictp/common/serializable/DtpPropertiesSerializable.java +++ /dev/null @@ -1,225 +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 org.dromara.dynamictp.common.serializable; - -import com.google.common.collect.Lists; -import lombok.Data; -import org.dromara.dynamictp.common.em.CollectorTypeEnum; -import org.dromara.dynamictp.common.entity.DtpExecutorProps; -import org.dromara.dynamictp.common.entity.NotifyPlatform; -import org.dromara.dynamictp.common.entity.TpExecutorProps; - -import java.io.Serializable; -import java.util.List; - -/** - * Main properties that maintain by config center. - * - * @author yanhom - * @since 1.0.0 - **/ -@Data -public class DtpPropertiesSerializable implements Serializable { - - private DtpPropertiesSerializable() { } - - /** - * If enabled DynamicTp. - */ - private boolean enabled = true; - - /** - * Environment, if not set, will use "APP.ENV". - */ - private String env; - - /** - * If print banner. - */ - private boolean enabledBanner = true; - - /** - * If enabled metrics collect. - */ - private boolean enabledCollect = true; - - /** - * Metrics collector types, default is logging. - */ - private List collectorTypes = Lists.newArrayList(CollectorTypeEnum.MICROMETER.name()); - - /** - * Metrics log storage path, just for "logging" type. - */ - private String logPath; - - /** - * Config file type, for zookeeper and etcd. - */ - private String configType; - - /** - * Monitor interval, time unit(s) - */ - private int monitorInterval = 5; - - /** - * Notify platform configs. - */ - private List platforms; - - /** - * Zookeeper config. - */ - private Zookeeper zookeeper; - - /** - * Etcd config. - */ - private Etcd etcd; - - /** - * ThreadPoolExecutor global configs. - */ - private DtpExecutorProps globalExecutorProps; - - /** - * ThreadPoolExecutor configs. - */ - private List executors; - - /** - * Tomcat worker thread pool. - */ - private TpExecutorProps tomcatTp; - - /** - * Jetty thread pool. - */ - private TpExecutorProps jettyTp; - - /** - * Undertow thread pool. - */ - private TpExecutorProps undertowTp; - - /** - * Dubbo thread pools. - */ - private List dubboTp; - - /** - * Hystrix thread pools. - */ - private List hystrixTp; - - /** - * RocketMq thread pools. - */ - private List rocketMqTp; - - /** - * Grpc thread pools. - */ - private List grpcTp; - - /** - * Motan server thread pools. - */ - private List motanTp; - - /** - * Okhttp3 thread pools. - */ - private List okhttp3Tp; - - /** - * Brpc thread pools. - */ - private List brpcTp; - - /** - * Tars thread pools. - */ - private List tarsTp; - - /** - * Sofa thread pools. - */ - private List sofaTp; - - /** - * Rabbitmq thread pools. - */ - private List rabbitmqTp; - - /** - * Liteflow thread pools. - */ - private List liteflowTp; - - /** - * Thrift thread pools. - */ - private List thriftTp; - - public static DtpPropertiesSerializable getInstance() { - return Holder.INSTANCE; - } - - @Data - public static class Zookeeper { - - private String zkConnectStr; - - private String configVersion; - - private String rootNode; - - private String node; - - private String configKey; - } - - /** - * Etcd config. - */ - @Data - public static class Etcd { - - private String endpoints; - - private String user; - - private String password; - - private String charset = "UTF-8"; - - private boolean authEnable = false; - - private String authority = "ssl"; - - private String key; - - private long timeout = 30000L; - } - - private static class Holder { - private static final DtpPropertiesSerializable INSTANCE = new DtpPropertiesSerializable(); - } -} diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/autoconfigure/AdminConfigEnvironmentProcessor.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/autoconfigure/AdminConfigEnvironmentProcessor.java index 49ac7b4f4..d361f76c6 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/autoconfigure/AdminConfigEnvironmentProcessor.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/autoconfigure/AdminConfigEnvironmentProcessor.java @@ -22,6 +22,8 @@ import org.dromara.dynamictp.common.properties.DtpProperties; import org.dromara.dynamictp.core.support.binder.BinderHelper; import org.dromara.dynamictp.sdk.client.AdminClient; +import org.dromara.dynamictp.sdk.client.handler.refresh.AdminRefresher; +import org.dromara.dynamictp.sdk.client.processor.AdminClientUserProcessor; import org.springframework.boot.SpringApplication; import org.springframework.boot.env.EnvironmentPostProcessor; import org.springframework.boot.env.OriginTrackedMapPropertySource; @@ -40,22 +42,30 @@ @Slf4j public class AdminConfigEnvironmentProcessor implements EnvironmentPostProcessor, Ordered { -// AdminClient adminClient; - -// public AdminConfigEnvironmentProcessor(AdminClient adminClient) { -// this.adminClient = adminClient; -// } + public AdminConfigEnvironmentProcessor() { + } public static final String ADMIN_PROPERTY_SOURCE_NAME = "dtpAdminPropertySource"; @Override public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { -// DtpProperties dtpProperties = DtpProperties.getInstance(); -// BinderHelper.bindDtpProperties(environment, dtpProperties); -// Map properties = (Map) adminClient.requestToServer(AdminRequestTypeEnum.EXECUTOR_REFRESH); -// if (!checkPropertyExist(environment)) { -// createAdminPropertySource(environment, properties); -// } + // 先绑定配置属性 + DtpProperties dtpProperties = DtpProperties.getInstance(); + BinderHelper.bindDtpProperties(environment, dtpProperties); + + // 从 Environment 中直接获取 clientName 配置 + String clientName = environment.getProperty("dynamictp.clientName", + environment.getProperty("spring.application.name", "unknown")); + + // 创建 AdminClient 时传入配置的 clientName + AdminClient adminClient = new AdminClient(new AdminClientUserProcessor(), clientName); + + Map properties = (Map) adminClient + .requestToServer(AdminRequestTypeEnum.EXECUTOR_REFRESH); + if (!checkPropertyExist(environment)) { + createAdminPropertySource(environment, properties); + } + adminClient.close(); } private boolean checkPropertyExist(ConfigurableEnvironment environment) { @@ -65,7 +75,8 @@ private boolean checkPropertyExist(ConfigurableEnvironment environment) { private void createAdminPropertySource(ConfigurableEnvironment environment, Map properties) { MutablePropertySources propertySources = environment.getPropertySources(); - OriginTrackedMapPropertySource adminSource = new OriginTrackedMapPropertySource(ADMIN_PROPERTY_SOURCE_NAME, properties); + OriginTrackedMapPropertySource adminSource = new OriginTrackedMapPropertySource(ADMIN_PROPERTY_SOURCE_NAME, + properties); propertySources.addLast(adminSource); } diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java index dac3aa003..249bf1da2 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java @@ -87,6 +87,20 @@ public AdminClient(AdminClientUserProcessor adminClientUserProcessor) { System.setProperty(Configs.SERIALIZER, String.valueOf(SERIALIZER)); } + public AdminClient(AdminClientUserProcessor adminClientUserProcessor, String clientName) { + this(adminClientUserProcessor); + this.clientName = clientName; + } + + /** + * Set client name manually + * + * @param clientName the client name to set + */ + public void setClientName(String clientName) { + this.clientName = clientName; + } + @PostConstruct public void init() { createConnection(); diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminClientUserProcessor.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminClientUserProcessor.java index becf51517..6e3d51cb4 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminClientUserProcessor.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminClientUserProcessor.java @@ -49,6 +49,10 @@ public class AdminClientUserProcessor extends SyncUserProcessor Date: Fri, 15 Aug 2025 16:12:48 +0800 Subject: [PATCH 14/21] format --- .../sdk/autoconfigure/AdminConfigEnvironmentProcessor.java | 3 +-- .../java/org/dromara/dynamictp/sdk/client/AdminClient.java | 1 - .../dynamictp/sdk/client/handler/refresh/AdminRefresher.java | 1 - .../sdk/client/processor/AdminClientUserProcessor.java | 1 - 4 files changed, 1 insertion(+), 5 deletions(-) diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/autoconfigure/AdminConfigEnvironmentProcessor.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/autoconfigure/AdminConfigEnvironmentProcessor.java index d361f76c6..2f939fcf7 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/autoconfigure/AdminConfigEnvironmentProcessor.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/autoconfigure/AdminConfigEnvironmentProcessor.java @@ -22,7 +22,6 @@ import org.dromara.dynamictp.common.properties.DtpProperties; import org.dromara.dynamictp.core.support.binder.BinderHelper; import org.dromara.dynamictp.sdk.client.AdminClient; -import org.dromara.dynamictp.sdk.client.handler.refresh.AdminRefresher; import org.dromara.dynamictp.sdk.client.processor.AdminClientUserProcessor; import org.springframework.boot.SpringApplication; import org.springframework.boot.env.EnvironmentPostProcessor; @@ -63,7 +62,7 @@ public void postProcessEnvironment(ConfigurableEnvironment environment, SpringAp Map properties = (Map) adminClient .requestToServer(AdminRequestTypeEnum.EXECUTOR_REFRESH); if (!checkPropertyExist(environment)) { - createAdminPropertySource(environment, properties); + createAdminPropertySource(environment, properties); } adminClient.close(); } diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java index 249bf1da2..7a75d1572 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java @@ -36,7 +36,6 @@ import org.dromara.dynamictp.sdk.client.processor.AdminCloseEventProcessor; import org.dromara.dynamictp.sdk.client.processor.AdminConnectEventProcessor; import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import java.util.concurrent.atomic.AtomicBoolean; diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/refresh/AdminRefresher.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/refresh/AdminRefresher.java index d6bf23282..a4873c3c4 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/refresh/AdminRefresher.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/refresh/AdminRefresher.java @@ -20,7 +20,6 @@ import lombok.extern.slf4j.Slf4j; import org.dromara.dynamictp.common.properties.DtpProperties; -import org.dromara.dynamictp.core.refresher.AbstractRefresher; import org.dromara.dynamictp.spring.AbstractSpringRefresher; import org.springframework.beans.factory.InitializingBean; diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminClientUserProcessor.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminClientUserProcessor.java index 6e3d51cb4..cca13eecf 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminClientUserProcessor.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminClientUserProcessor.java @@ -25,7 +25,6 @@ import org.dromara.dynamictp.sdk.client.handler.collector.AdminCollector; import org.dromara.dynamictp.sdk.client.handler.refresh.AdminRefresher; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; import java.util.Map; import java.util.concurrent.Executor; From 39b13aa77ec3675a0f3236673e5ac3e46b551dc4 Mon Sep 17 00:00:00 2001 From: chenyc55879 Date: Fri, 15 Aug 2025 17:11:05 +0800 Subject: [PATCH 15/21] add client heatbeat logic --- .../src/main/resources/application.yml | 1 + .../autoconfigure/AdminAutoConfiguration.java | 1 + .../AdminConfigEnvironmentProcessor.java | 2 +- .../dynamictp/sdk/client/AdminClient.java | 54 +++++++++++++++++++ 4 files changed, 57 insertions(+), 1 deletion(-) diff --git a/example/example-admin/src/main/resources/application.yml b/example/example-admin/src/main/resources/application.yml index 10a182e0f..c53f5cdfb 100644 --- a/example/example-admin/src/main/resources/application.yml +++ b/example/example-admin/src/main/resources/application.yml @@ -12,6 +12,7 @@ spring: dynamictp: clientName: dynamic-tp-admin-demo + adminEnabled: true #logging: # level: diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/autoconfigure/AdminAutoConfiguration.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/autoconfigure/AdminAutoConfiguration.java index 231caf737..0179cbe5f 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/autoconfigure/AdminAutoConfiguration.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/autoconfigure/AdminAutoConfiguration.java @@ -56,6 +56,7 @@ public AdminCollector adminCollector() { public AdminRefresher adminRefresher(DtpProperties dtpProperties) { return new AdminRefresher(dtpProperties); } + @Bean public AdminClientUserProcessor adminClientUserProcessor(AdminRefresher adminRefresher) { return new AdminClientUserProcessor(adminRefresher); diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/autoconfigure/AdminConfigEnvironmentProcessor.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/autoconfigure/AdminConfigEnvironmentProcessor.java index 2f939fcf7..c1a488452 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/autoconfigure/AdminConfigEnvironmentProcessor.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/autoconfigure/AdminConfigEnvironmentProcessor.java @@ -61,7 +61,7 @@ public void postProcessEnvironment(ConfigurableEnvironment environment, SpringAp Map properties = (Map) adminClient .requestToServer(AdminRequestTypeEnum.EXECUTOR_REFRESH); - if (!checkPropertyExist(environment)) { + if (!checkPropertyExist(environment) && properties != null) { createAdminPropertySource(environment, properties); } adminClient.close(); diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java index 7a75d1572..67e0d1e8d 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java +++ b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java @@ -38,6 +38,10 @@ import org.springframework.beans.factory.annotation.Value; import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; @@ -58,6 +62,9 @@ public class AdminClient { @Value("${dynamictp.clientName:${spring.application.name}}") private String clientName; + @Value("${dynamictp.adminEnabled:false}") + private Boolean adminEnabled; + @Getter private static final SnowflakeGenerator SNOWFLAKE_GENERATOR = new SnowflakeGenerator(); @@ -76,6 +83,10 @@ public class AdminClient { private static final int MAX_RETRY_COUNT = 3; private static final long RETRY_DELAY_MS = 1000; + // Heartbeat mechanism + private static final long HEARTBEAT_INTERVAL_SECONDS = 30; + private ScheduledExecutorService heartbeatExecutor; + public AdminClient(AdminClientUserProcessor adminClientUserProcessor) { client.addConnectionEventProcessor(ConnectionEventType.CONNECT, new AdminConnectEventProcessor(this)); client.addConnectionEventProcessor(ConnectionEventType.CLOSE, new AdminCloseEventProcessor(this)); @@ -103,6 +114,47 @@ public void setClientName(String clientName) { @PostConstruct public void init() { createConnection(); + startHeartbeat(); + } + + /** + * Start heartbeat mechanism if admin is enabled + */ + private void startHeartbeat() { + if (adminEnabled) { + heartbeatExecutor = Executors.newSingleThreadScheduledExecutor(r -> { + Thread thread = new Thread(r, "DynamicTp-AdminClient-Heartbeat"); + thread.setDaemon(true); + return thread; + }); + + heartbeatExecutor.scheduleAtFixedRate(() -> { + try { + ensureConnection(); + } catch (Exception e) { + log.warn("DynamicTp admin client heartbeat execution failed", e); + } + }, HEARTBEAT_INTERVAL_SECONDS, HEARTBEAT_INTERVAL_SECONDS, TimeUnit.SECONDS); + } + } + + /** + * Stop heartbeat mechanism + */ + private void stopHeartbeat() { + if (heartbeatExecutor != null && !heartbeatExecutor.isShutdown()) { + try { + heartbeatExecutor.shutdown(); + if (!heartbeatExecutor.awaitTermination(5, TimeUnit.SECONDS)) { + heartbeatExecutor.shutdownNow(); + } + log.info("DynamicTp admin client heartbeat stopped"); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + heartbeatExecutor.shutdownNow(); + log.warn("DynamicTp admin client heartbeat shutdown interrupted"); + } + } } public Object requestToServer(AdminRequestTypeEnum requestType) { @@ -258,7 +310,9 @@ public void updateConnectionStatus(boolean connected) { } } + @PreDestroy public void close() { + stopHeartbeat(); isConnected.set(false); if (connection != null) { try { From 97c9df92cf36a31e2256220f3c7ad6162404ae5d Mon Sep 17 00:00:00 2001 From: eachann Date: Wed, 20 Aug 2025 17:26:40 +0800 Subject: [PATCH 16/21] fix,add example test,optimize AdminCollector AdminRequestBody and rm AttributeRequestBody --- {sdk => client}/pom.xml | 2 +- .../client/adminclient}/AdminClient.java | 50 ++++--- .../handler/collector/AdminCollector.java | 52 +++++++ .../handler/refresh/AdminRefresher.java | 2 +- .../processor/AdminClientUserProcessor.java | 13 +- .../processor/AdminCloseEventProcessor.java | 4 +- .../processor/AdminConnectEventProcessor.java | 4 +- .../autoconfigure/AdminAutoConfiguration.java | 18 +-- .../AdminConfigEnvironmentProcessor.java | 6 +- ...tp.core.monitor.collector.MetricsCollector | 1 + .../main/resources/META-INF/spring.factories | 4 + common/pom.xml | 5 - .../common/em/AdminRequestTypeEnum.java | 4 +- .../common/em/CollectorTypeEnum.java | 7 +- .../common/entity/AdminRequestBody.java | 29 +--- .../common/entity/AttributeRequestBody.java | 54 ------- dependencies/pom.xml | 28 ++-- example/example-admin/pom.xml | 2 +- .../example/controller/TestController.java | 56 ++++---- .../example/service/TestService.java | 34 ++--- .../example/service/impl/TestServiceImpl.java | 134 +++--------------- .../example/wrapper/CustomTaskWrapper.java | 57 -------- .../src/main/resources/application.yml | 4 +- example/pom.xml | 3 +- pom.xml | 2 +- .../handler/collector/AdminCollector.java | 84 ----------- .../main/resources/META-INF/spring.factories | 4 - .../TarsTpAutoConfiguration.java | 2 +- 28 files changed, 194 insertions(+), 471 deletions(-) rename {sdk => client}/pom.xml (95%) rename {sdk/src/main/java/org/dromara/dynamictp/sdk/client => client/src/main/java/org/dromara/dynamictp/client/adminclient}/AdminClient.java (86%) create mode 100644 client/src/main/java/org/dromara/dynamictp/client/adminclient/handler/collector/AdminCollector.java rename {sdk/src/main/java/org/dromara/dynamictp/sdk/client => client/src/main/java/org/dromara/dynamictp/client/adminclient}/handler/refresh/AdminRefresher.java (95%) rename {sdk/src/main/java/org/dromara/dynamictp/sdk/client => client/src/main/java/org/dromara/dynamictp/client/adminclient}/processor/AdminClientUserProcessor.java (89%) rename {sdk/src/main/java/org/dromara/dynamictp/sdk/client => client/src/main/java/org/dromara/dynamictp/client/adminclient}/processor/AdminCloseEventProcessor.java (93%) rename {sdk/src/main/java/org/dromara/dynamictp/sdk/client => client/src/main/java/org/dromara/dynamictp/client/adminclient}/processor/AdminConnectEventProcessor.java (92%) rename {sdk/src/main/java/org/dromara/dynamictp/sdk => client/src/main/java/org/dromara/dynamictp/client}/autoconfigure/AdminAutoConfiguration.java (80%) rename {sdk/src/main/java/org/dromara/dynamictp/sdk => client/src/main/java/org/dromara/dynamictp/client}/autoconfigure/AdminConfigEnvironmentProcessor.java (94%) create mode 100644 client/src/main/resources/META-INF/services/org.dromara.dynamictp.core.monitor.collector.MetricsCollector create mode 100644 client/src/main/resources/META-INF/spring.factories delete mode 100644 common/src/main/java/org/dromara/dynamictp/common/entity/AttributeRequestBody.java delete mode 100644 example/example-admin/src/main/java/org/dromara/dynamictp/example/wrapper/CustomTaskWrapper.java delete mode 100644 sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/collector/AdminCollector.java delete mode 100644 sdk/src/main/resources/META-INF/spring.factories diff --git a/sdk/pom.xml b/client/pom.xml similarity index 95% rename from sdk/pom.xml rename to client/pom.xml index 4534e979b..668dc5030 100644 --- a/sdk/pom.xml +++ b/client/pom.xml @@ -8,7 +8,7 @@ ${revision} ../pom.xml - dynamic-tp-sdk + dynamic-tp-client diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java b/client/src/main/java/org/dromara/dynamictp/client/adminclient/AdminClient.java similarity index 86% rename from sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java rename to client/src/main/java/org/dromara/dynamictp/client/adminclient/AdminClient.java index 67e0d1e8d..dca7301aa 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/AdminClient.java +++ b/client/src/main/java/org/dromara/dynamictp/client/adminclient/AdminClient.java @@ -15,12 +15,11 @@ * limitations under the License. */ -package org.dromara.dynamictp.sdk.client; +package org.dromara.dynamictp.client.adminclient; import cn.hutool.core.lang.generator.SnowflakeGenerator; import com.alipay.remoting.Connection; import com.alipay.remoting.ConnectionEventType; -import com.alipay.remoting.Url; import com.alipay.remoting.config.Configs; import com.alipay.remoting.exception.RemotingException; import com.alipay.remoting.rpc.RpcClient; @@ -31,14 +30,14 @@ import lombok.extern.slf4j.Slf4j; import org.dromara.dynamictp.common.entity.AdminRequestBody; import org.dromara.dynamictp.common.em.AdminRequestTypeEnum; -import org.dromara.dynamictp.common.entity.AttributeRequestBody; -import org.dromara.dynamictp.sdk.client.processor.AdminClientUserProcessor; -import org.dromara.dynamictp.sdk.client.processor.AdminCloseEventProcessor; -import org.dromara.dynamictp.sdk.client.processor.AdminConnectEventProcessor; +import org.dromara.dynamictp.client.adminclient.processor.AdminClientUserProcessor; +import org.dromara.dynamictp.client.adminclient.processor.AdminCloseEventProcessor; +import org.dromara.dynamictp.client.adminclient.processor.AdminConnectEventProcessor; import org.springframework.beans.factory.annotation.Value; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; +import java.util.HashMap; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -53,11 +52,11 @@ @Slf4j public class AdminClient { - private final String adminIp = "127.0.0.1"; + @Value("${dynamictp.adminIp:127.0.0.1}") + private String adminIp; - private final int adminPort = 8989; - - private final Url adminUrl = new Url(adminIp, adminPort); + @Value("${dynamictp.adminPort:8989}") + private int adminPort; @Value("${dynamictp.clientName:${spring.application.name}}") private String clientName; @@ -103,9 +102,9 @@ public AdminClient(AdminClientUserProcessor adminClientUserProcessor, String cli } /** - * Set client name manually + * Set adminclient name manually * - * @param clientName the client name to set + * @param clientName the adminclient name to set */ public void setClientName(String clientName) { this.clientName = clientName; @@ -163,8 +162,10 @@ public Object requestToServer(AdminRequestTypeEnum requestType) { adminIp, adminPort); return null; } - AttributeRequestBody attributeRequestBody = new AttributeRequestBody(); - attributeRequestBody.setAttribute("clientName", clientName); + AdminRequestBody attributeRequestBody = new AdminRequestBody(SNOWFLAKE_GENERATOR.next(), AdminRequestTypeEnum.ATTRIBUTE); + HashMap attributes = new HashMap<>(); + attributes.put("clientName", clientName); + attributeRequestBody.setBody(attributes); AdminRequestBody requestBody = new AdminRequestBody(SNOWFLAKE_GENERATOR.next(), requestType); Object object = null; try { @@ -172,7 +173,6 @@ public Object requestToServer(AdminRequestTypeEnum requestType) { object = client.invokeSync(connection, requestBody, 30000); } catch (RemotingException | InterruptedException e) { log.warn("DynamicTp admin client invoke failed, admin ip: {}, port: {}, exception:", adminIp, adminPort, e); - // Mark connection as disconnected when request fails isConnected.set(false); } return object; @@ -184,8 +184,10 @@ public Object requestToServer(AdminRequestBody adminRequestBody) { adminIp, adminPort); return null; } - AttributeRequestBody attributeRequestBody = new AttributeRequestBody(); - attributeRequestBody.setAttribute("clientName", clientName); + AdminRequestBody attributeRequestBody = new AdminRequestBody(SNOWFLAKE_GENERATOR.next(), AdminRequestTypeEnum.ATTRIBUTE); + HashMap attributes = new HashMap<>(); + attributes.put("clientName", clientName); + attributeRequestBody.setBody(attributes); Object object = null; try { client.invokeSync(connection, attributeRequestBody, 5000); @@ -205,7 +207,7 @@ public Object requestToServer(AdminRequestBody adminRequestBody) { */ private boolean ensureConnection() { // Check connection status - if (isConnected.get() && connection != null && client.checkConnection(adminUrl.getOriginUrl(), true)) { + if (isConnected.get() && connection != null && client.checkConnection(getAdminAddress(), true)) { return true; } @@ -261,12 +263,14 @@ private boolean createConnection() { connection = null; } - connection = client.createStandaloneConnection(adminUrl.getOriginUrl(), 30000); + connection = client.createStandaloneConnection(getAdminAddress(), 30000); if (connection != null && connection.isFine()) { log.info("DynamicTp admin client connection created successfully, admin ip: {}, port: {}", adminIp, adminPort); - AttributeRequestBody attributeRequestBody = new AttributeRequestBody(); - attributeRequestBody.setAttribute("clientName", clientName); + AdminRequestBody attributeRequestBody = new AdminRequestBody(SNOWFLAKE_GENERATOR.next(), AdminRequestTypeEnum.ATTRIBUTE); + HashMap attributes = new HashMap<>(); + attributes.put("clientName", clientName); + attributeRequestBody.setBody(attributes); client.invokeSync(connection, attributeRequestBody, 5000); return true; } else { @@ -310,6 +314,10 @@ public void updateConnectionStatus(boolean connected) { } } + private String getAdminAddress() { + return adminIp + ":" + adminPort; + } + @PreDestroy public void close() { stopHeartbeat(); diff --git a/client/src/main/java/org/dromara/dynamictp/client/adminclient/handler/collector/AdminCollector.java b/client/src/main/java/org/dromara/dynamictp/client/adminclient/handler/collector/AdminCollector.java new file mode 100644 index 000000000..7bdcd5dfc --- /dev/null +++ b/client/src/main/java/org/dromara/dynamictp/client/adminclient/handler/collector/AdminCollector.java @@ -0,0 +1,52 @@ +/* + * 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 org.dromara.dynamictp.client.adminclient.handler.collector; + +import org.dromara.dynamictp.common.em.CollectorTypeEnum; +import org.dromara.dynamictp.common.entity.ThreadPoolStats; +import org.dromara.dynamictp.core.monitor.collector.AbstractCollector; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * AdminCollector for collecting thread pool statistics + * Enhanced to support active collection and multiple thread pools + * + * @author eachann + */ +public class AdminCollector extends AbstractCollector { + + private static final Map MULTI_POOL_STATS = new ConcurrentHashMap(); + + public static List getMultiPoolStats() { + return new ArrayList<>(MULTI_POOL_STATS.values()); + } + + @Override + public void collect(ThreadPoolStats poolStats) { + MULTI_POOL_STATS.put(poolStats.getPoolName(), poolStats); + } + + @Override + public String type() { + return CollectorTypeEnum.ADMIN.name().toLowerCase(); + } +} diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/refresh/AdminRefresher.java b/client/src/main/java/org/dromara/dynamictp/client/adminclient/handler/refresh/AdminRefresher.java similarity index 95% rename from sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/refresh/AdminRefresher.java rename to client/src/main/java/org/dromara/dynamictp/client/adminclient/handler/refresh/AdminRefresher.java index a4873c3c4..14843a056 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/refresh/AdminRefresher.java +++ b/client/src/main/java/org/dromara/dynamictp/client/adminclient/handler/refresh/AdminRefresher.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.dromara.dynamictp.sdk.client.handler.refresh; +package org.dromara.dynamictp.client.adminclient.handler.refresh; import lombok.extern.slf4j.Slf4j; diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminClientUserProcessor.java b/client/src/main/java/org/dromara/dynamictp/client/adminclient/processor/AdminClientUserProcessor.java similarity index 89% rename from sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminClientUserProcessor.java rename to client/src/main/java/org/dromara/dynamictp/client/adminclient/processor/AdminClientUserProcessor.java index cca13eecf..1c18f9480 100644 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/processor/AdminClientUserProcessor.java +++ b/client/src/main/java/org/dromara/dynamictp/client/adminclient/processor/AdminClientUserProcessor.java @@ -15,15 +15,15 @@ * limitations under the License. */ -package org.dromara.dynamictp.sdk.client.processor; +package org.dromara.dynamictp.client.adminclient.processor; import com.alipay.remoting.BizContext; import com.alipay.remoting.rpc.protocol.SyncUserProcessor; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.dromara.dynamictp.common.entity.AdminRequestBody; -import org.dromara.dynamictp.sdk.client.handler.collector.AdminCollector; -import org.dromara.dynamictp.sdk.client.handler.refresh.AdminRefresher; +import org.dromara.dynamictp.client.adminclient.handler.collector.AdminCollector; +import org.dromara.dynamictp.client.adminclient.handler.refresh.AdminRefresher; import org.springframework.beans.factory.annotation.Autowired; import java.util.Map; @@ -46,8 +46,6 @@ public class AdminClientUserProcessor extends SyncUserProcessorbyte-buddy - - com.alipay.sofa - bolt - - org.yaml snakeyaml diff --git a/common/src/main/java/org/dromara/dynamictp/common/em/AdminRequestTypeEnum.java b/common/src/main/java/org/dromara/dynamictp/common/em/AdminRequestTypeEnum.java index 0187e0062..337ec55e1 100644 --- a/common/src/main/java/org/dromara/dynamictp/common/em/AdminRequestTypeEnum.java +++ b/common/src/main/java/org/dromara/dynamictp/common/em/AdminRequestTypeEnum.java @@ -35,7 +35,9 @@ public enum AdminRequestTypeEnum { ALARM_MANAGE("alarm_manage"), - LOG_MANAGE("log_manage"); + LOG_MANAGE("log_manage"), + + ATTRIBUTE("attribute"); private final String value; diff --git a/common/src/main/java/org/dromara/dynamictp/common/em/CollectorTypeEnum.java b/common/src/main/java/org/dromara/dynamictp/common/em/CollectorTypeEnum.java index 7356cc52e..a742571c9 100644 --- a/common/src/main/java/org/dromara/dynamictp/common/em/CollectorTypeEnum.java +++ b/common/src/main/java/org/dromara/dynamictp/common/em/CollectorTypeEnum.java @@ -46,6 +46,11 @@ public enum CollectorTypeEnum { /** * JMX collect type. */ - JMX + JMX, + + /** + * ADMIN collect type. + */ + ADMIN } diff --git a/common/src/main/java/org/dromara/dynamictp/common/entity/AdminRequestBody.java b/common/src/main/java/org/dromara/dynamictp/common/entity/AdminRequestBody.java index 77fca9775..1668fbd9a 100644 --- a/common/src/main/java/org/dromara/dynamictp/common/entity/AdminRequestBody.java +++ b/common/src/main/java/org/dromara/dynamictp/common/entity/AdminRequestBody.java @@ -17,9 +17,8 @@ package org.dromara.dynamictp.common.entity; -import com.alipay.remoting.exception.CodecException; -import com.alipay.remoting.serialization.HessianSerializer; import lombok.Getter; +import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.dromara.dynamictp.common.em.AdminRequestTypeEnum; @@ -39,7 +38,9 @@ public class AdminRequestBody implements Serializable { @Getter private final AdminRequestTypeEnum requestType; - private byte[] body; + @Setter + @Getter + private Object body; public AdminRequestBody(long id, AdminRequestTypeEnum requestType) { this.id = id; @@ -48,28 +49,8 @@ public AdminRequestBody(long id, AdminRequestTypeEnum requestType) { public AdminRequestBody(long id, AdminRequestTypeEnum requestType, Object body) { this.id = id; - serializeBody(body); + this.body = body; this.requestType = requestType; } - public void serializeBody(Object object) { - HessianSerializer serializer = new HessianSerializer(); - try { - this.body = serializer.serialize(object); - } catch (CodecException e) { - log.error("DynamicTp admin client serialize failed.", e); - } - } - - public Object deserializeBody() { - HessianSerializer serializer = new HessianSerializer(); - Object object = null; - try { - object = serializer.deserialize(this.body, null); - } catch (CodecException e) { - log.error("DynamicTp admin client deserialize failed.", e); - } - return object; - } - } diff --git a/common/src/main/java/org/dromara/dynamictp/common/entity/AttributeRequestBody.java b/common/src/main/java/org/dromara/dynamictp/common/entity/AttributeRequestBody.java deleted file mode 100644 index c40f175cc..000000000 --- a/common/src/main/java/org/dromara/dynamictp/common/entity/AttributeRequestBody.java +++ /dev/null @@ -1,54 +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 org.dromara.dynamictp.common.entity; - - -import lombok.Getter; -import lombok.Setter; - -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; - -/** - * @author eachann - */ -public class AttributeRequestBody implements Serializable { - - private static final long serialVersionUID = -1288207208017808630L; - - @Setter - @Getter - private String message; - - @Getter - private final Map attributes; - - public AttributeRequestBody() { - this.attributes = new HashMap<>(); - } - - public void setAttribute(String key, String value) { - this.attributes.put(key, value); - } - - public String getAttribute(String key) { - return this.attributes.get(key); - } - -} diff --git a/dependencies/pom.xml b/dependencies/pom.xml index 81bce9729..e56b727c0 100644 --- a/dependencies/pom.xml +++ b/dependencies/pom.xml @@ -391,7 +391,7 @@ org.dromara.dynamictp - dynamic-tp-sdk + dynamic-tp-client ${revision} @@ -727,19 +727,19 @@ - - - - - - - - - - - - - + + org.apache.maven.plugins + maven-gpg-plugin + 1.6 + + + verify + + sign + + + + org.sonatype.central diff --git a/example/example-admin/pom.xml b/example/example-admin/pom.xml index 337fe5629..e97b88423 100644 --- a/example/example-admin/pom.xml +++ b/example/example-admin/pom.xml @@ -33,7 +33,7 @@ org.dromara.dynamictp - dynamic-tp-sdk + dynamic-tp-client diff --git a/example/example-admin/src/main/java/org/dromara/dynamictp/example/controller/TestController.java b/example/example-admin/src/main/java/org/dromara/dynamictp/example/controller/TestController.java index 5f4d1c196..b7676df64 100644 --- a/example/example-admin/src/main/java/org/dromara/dynamictp/example/controller/TestController.java +++ b/example/example-admin/src/main/java/org/dromara/dynamictp/example/controller/TestController.java @@ -18,10 +18,14 @@ package org.dromara.dynamictp.example.controller; import com.alipay.remoting.exception.RemotingException; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.dromara.dynamictp.example.service.TestService; +import org.dromara.dynamictp.common.em.AdminRequestTypeEnum; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; /** @@ -34,45 +38,33 @@ public class TestController { private final TestService testService; - @GetMapping("/dtp-nacos-example/testAdminClient") - public String testAdminClient() throws RemotingException, InterruptedException { - testService.testAdminClient(); - return "testAdminClient success"; - } - - @GetMapping("/dtp-nacos-example/testJucTp") - public String testJuc() { - testService.testJucTp(); - return "testJucTp success"; - } + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); - @GetMapping("/dtp-nacos-example/testSpringTp") - public String testSpring() { - testService.testSpringTp(); - return "testSpringTp success"; + @GetMapping("/dtp-nacos-example/testAdminClient") + public String testAdminClient() { + return toJson(testService.testAdminClient()); } - @GetMapping("/dtp-nacos-example/testCommonDtp") - public String testCommon() { - testService.testCommonDtp(); - return "testCommonDtp success"; + @GetMapping("/dtp-nacos-example/testAdminClient/{type}") + public String testAdminClientByType(@PathVariable("type") String type) { + AdminRequestTypeEnum requestType = AdminRequestTypeEnum.of(type); + if (requestType == null) { + return "unknown type: " + type; + } + return toJson(testService.testAdminClient(requestType)); } - @GetMapping("/dtp-nacos-example/testEagerDtp") - public String testEager() { - testService.testEagerDtp(); - return "testEagerDtp success"; + @GetMapping("/dtp-nacos-example/testAdminClientAll") + public String testAdminClientAll() { + return toJson(testService.testAdminClientAll()); } - @GetMapping("/dtp-nacos-example/testScheduledDtp") - public String testScheduled() { - testService.testScheduledDtp(); - return "testScheduledDtp success"; + private String toJson(Object value) { + try { + return OBJECT_MAPPER.writeValueAsString(value); + } catch (JsonProcessingException e) { + return String.valueOf(value); + } } - @GetMapping("/dtp-nacos-example/testOrderedDtp") - public String testOrdered() { - testService.testOrderedDtp(); - return "testOrderedDtp success"; - } } diff --git a/example/example-admin/src/main/java/org/dromara/dynamictp/example/service/TestService.java b/example/example-admin/src/main/java/org/dromara/dynamictp/example/service/TestService.java index dcc11e8b6..263104cba 100644 --- a/example/example-admin/src/main/java/org/dromara/dynamictp/example/service/TestService.java +++ b/example/example-admin/src/main/java/org/dromara/dynamictp/example/service/TestService.java @@ -17,7 +17,8 @@ package org.dromara.dynamictp.example.service; -import com.alipay.remoting.exception.RemotingException; +import org.dromara.dynamictp.common.em.AdminRequestTypeEnum; +import java.util.Map; /** * TestService related @@ -27,35 +28,18 @@ */ public interface TestService { - void testAdminClient() throws RemotingException, InterruptedException; + Object testAdminClient(); /** - * Test juc tp. + * Invoke admin with the specified request type. + * + * @param type admin request type */ - void testJucTp(); + Object testAdminClient(AdminRequestTypeEnum type); /** - * Test spring tp. + * Invoke admin with all available request types. */ - void testSpringTp(); + Map testAdminClientAll(); - /** - * Test common dtp. - */ - void testCommonDtp(); - - /** - * Test eager dtp. - */ - void testEagerDtp(); - - /** - * Test scheduled dtp. - */ - void testScheduledDtp(); - - /** - * Test ordered dtp. - */ - void testOrderedDtp(); } diff --git a/example/example-admin/src/main/java/org/dromara/dynamictp/example/service/impl/TestServiceImpl.java b/example/example-admin/src/main/java/org/dromara/dynamictp/example/service/impl/TestServiceImpl.java index ec06b3f11..0825bbaff 100644 --- a/example/example-admin/src/main/java/org/dromara/dynamictp/example/service/impl/TestServiceImpl.java +++ b/example/example-admin/src/main/java/org/dromara/dynamictp/example/service/impl/TestServiceImpl.java @@ -17,24 +17,17 @@ package org.dromara.dynamictp.example.service.impl; -import lombok.AllArgsConstructor; -import lombok.Data; import lombok.extern.slf4j.Slf4j; -import org.dromara.dynamictp.core.DtpRegistry; import org.dromara.dynamictp.core.executor.DtpExecutor; import org.dromara.dynamictp.core.executor.OrderedDtpExecutor; -import org.dromara.dynamictp.core.support.task.runnable.NamedRunnable; -import org.dromara.dynamictp.core.support.task.runnable.OrderedRunnable; import org.dromara.dynamictp.example.service.TestService; -import org.dromara.dynamictp.sdk.client.AdminClient; +import org.dromara.dynamictp.client.adminclient.AdminClient; import org.dromara.dynamictp.common.em.AdminRequestTypeEnum; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Service; -import java.util.concurrent.Executor; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; /** * TestServiceImpl related @@ -59,11 +52,11 @@ public class TestServiceImpl implements TestService { private AdminClient adminClient; public TestServiceImpl(ThreadPoolExecutor jucThreadPoolExecutor, - ThreadPoolTaskExecutor threadPoolTaskExecutor, - DtpExecutor eagerDtpExecutor, - ScheduledExecutorService scheduledDtpExecutor, - OrderedDtpExecutor orderedDtpExecutor, - AdminClient adminClient) { + ThreadPoolTaskExecutor threadPoolTaskExecutor, + DtpExecutor eagerDtpExecutor, + ScheduledExecutorService scheduledDtpExecutor, + OrderedDtpExecutor orderedDtpExecutor, + AdminClient adminClient) { this.jucThreadPoolExecutor = jucThreadPoolExecutor; this.threadPoolTaskExecutor = threadPoolTaskExecutor; this.eagerDtpExecutor = eagerDtpExecutor; @@ -73,115 +66,28 @@ public TestServiceImpl(ThreadPoolExecutor jucThreadPoolExecutor, } @Override - public void testAdminClient() { - adminClient.requestToServer(AdminRequestTypeEnum.ALARM_MANAGE); + public Object testAdminClient() { + Object resp = adminClient.requestToServer(AdminRequestTypeEnum.ALARM_MANAGE); log.info("testAdminClient,remoteAddress:{}", adminClient.getConnection().getRemoteAddress()); + return resp; } @Override - public void testJucTp() { - for (int i = 0; i < 10; i++) { - jucThreadPoolExecutor.execute(() -> { - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - log.info("i am a jucThreadPoolExecutor's task"); - }); - } - } - - @Override - public void testSpringTp() { - for (int i = 0; i < 10; i++) { - threadPoolTaskExecutor.execute(() -> { - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - log.info("i am a threadPoolTaskExecutor's task"); - }); - } - } - - @Override - public void testCommonDtp() { - Executor dtpExecutor1 = DtpRegistry.getExecutor("dtpExecutor1"); - for (int i = 0; i < 10; i++) { - dtpExecutor1.execute(NamedRunnable.of(() -> { - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - log.info("i am a dtpExecutor's task"); - }, "task" + i)); - } - } - - @Override - public void testEagerDtp() { - for (int i = 0; i < 10; i++) { - eagerDtpExecutor.execute(() -> { - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - log.info("i am a eagerDtpExecutor's task"); - }); - } + public Object testAdminClient(AdminRequestTypeEnum type) { + Object resp = adminClient.requestToServer(type); + log.info("testAdminClient type:{}, remoteAddress:{}", type, adminClient.getConnection().getRemoteAddress()); + return resp; } @Override - public void testScheduledDtp() { - scheduledDtpExecutor.scheduleAtFixedRate(() -> { - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - log.info("i am a scheduledDtpExecutor's task"); - }, 0, 2, TimeUnit.SECONDS); - } - - @Override - public void testOrderedDtp() { - for (int i = 0; i < 10; i++) { - orderedDtpExecutor.execute(new TestOrderedRunnable(new UserInfo(i, "dtp" + i))); + public java.util.Map testAdminClientAll() { + java.util.Map result = new java.util.LinkedHashMap<>(); + for (AdminRequestTypeEnum type : AdminRequestTypeEnum.values()) { + Object resp = adminClient.requestToServer(type); + log.info("testAdminClient type:{}, remoteAddress:{}", type, adminClient.getConnection().getRemoteAddress()); + result.put(type.name(), resp); } + return result; } - public static class TestOrderedRunnable implements OrderedRunnable { - - private final UserInfo userInfo; - - public TestOrderedRunnable(UserInfo userInfo) { - this.userInfo = userInfo; - } - - @Override - public Object hashKey() { - return userInfo.getUid(); - } - - @Override - public void run() { - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - log.info("i am a orderedDtpExecutor's task, userInfo: {}", userInfo); - } - } - - @Data - @AllArgsConstructor - public static class UserInfo { - private long uid; - private String name; - } } diff --git a/example/example-admin/src/main/java/org/dromara/dynamictp/example/wrapper/CustomTaskWrapper.java b/example/example-admin/src/main/java/org/dromara/dynamictp/example/wrapper/CustomTaskWrapper.java deleted file mode 100644 index b884643b8..000000000 --- a/example/example-admin/src/main/java/org/dromara/dynamictp/example/wrapper/CustomTaskWrapper.java +++ /dev/null @@ -1,57 +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 org.dromara.dynamictp.example.wrapper; - -import lombok.extern.slf4j.Slf4j; -import org.dromara.dynamictp.core.support.task.wrapper.TaskWrapper; - -/** - * CustomTaskWrapper related - * - * @author yanhom - * @since 1.1.0 - */ -@Slf4j -public class CustomTaskWrapper implements TaskWrapper { - - @Override - public String name() { - return "custom"; - } - - @Override - public Runnable wrap(Runnable runnable) { - return new MyRunnable(runnable); - } - - public static class MyRunnable implements Runnable { - - private final Runnable runnable; - - public MyRunnable(Runnable runnable) { - this.runnable = runnable; - } - - @Override - public void run() { - log.info("before run"); - runnable.run(); - log.info("after run"); - } - } -} diff --git a/example/example-admin/src/main/resources/application.yml b/example/example-admin/src/main/resources/application.yml index c53f5cdfb..9cb910a14 100644 --- a/example/example-admin/src/main/resources/application.yml +++ b/example/example-admin/src/main/resources/application.yml @@ -11,8 +11,10 @@ spring: port: 6379 dynamictp: - clientName: dynamic-tp-admin-demo adminEnabled: true + adminPort: 8989 + clientName: dynamic-tp-admin-demo + collector-types: admin #logging: # level: diff --git a/example/pom.xml b/example/pom.xml index 91be65833..fc23530bb 100644 --- a/example/pom.xml +++ b/example/pom.xml @@ -24,10 +24,9 @@ example-zookeeper-cloud example-consul-cloud example-etcd - + example-adapter example-polaris-cloud example-huawei-cloud - diff --git a/pom.xml b/pom.xml index df35f90d5..b2938d5e5 100644 --- a/pom.xml +++ b/pom.xml @@ -39,7 +39,7 @@ adapter core common - sdk + client starter logging example diff --git a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/collector/AdminCollector.java b/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/collector/AdminCollector.java deleted file mode 100644 index 2bdb95af9..000000000 --- a/sdk/src/main/java/org/dromara/dynamictp/sdk/client/handler/collector/AdminCollector.java +++ /dev/null @@ -1,84 +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 org.dromara.dynamictp.sdk.client.handler.collector; - -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import org.dromara.dynamictp.common.entity.ThreadPoolStats; -import org.dromara.dynamictp.core.DtpRegistry; -import org.dromara.dynamictp.core.converter.ExecutorConverter; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * AdminCollector for collecting thread pool statistics - * Enhanced to support active collection and multiple thread pools - * - * @author eachann - */ -@Slf4j -public class AdminCollector { - - @Getter - private ThreadPoolStats poolStats = new ThreadPoolStats(); - - @Getter - private final List multiPoolStats = new CopyOnWriteArrayList<>(); - - /** - * Actively collect all thread pool statistics from DtpRegistry - * This method can be called independently to refresh data - */ - public void collectAllPoolStats() { - try { - Set executorNames = DtpRegistry.getAllExecutorNames(); - if (executorNames.isEmpty()) { - log.debug("No executors found in DtpRegistry"); - return; - } - - List newStatsList = new ArrayList<>(); - for (String executorName : executorNames) { - try { - ThreadPoolStats stats = ExecutorConverter.toMetrics(DtpRegistry.getExecutorWrapper(executorName)); - if (stats != null) { - newStatsList.add(stats); - } - } catch (Exception e) { - log.warn("Failed to collect stats for executor: {}", executorName, e); - } - } - - // Update multiPoolStats - this.multiPoolStats.clear(); - this.multiPoolStats.addAll(newStatsList); - - // Set the first pool stats as the main poolStats for backward compatibility - if (!newStatsList.isEmpty()) { - this.poolStats = newStatsList.get(0); - } - - log.debug("AdminCollector actively collected {} pool stats", newStatsList.size()); - } catch (Exception e) { - log.error("Failed to collect all pool stats", e); - } - } -} diff --git a/sdk/src/main/resources/META-INF/spring.factories b/sdk/src/main/resources/META-INF/spring.factories deleted file mode 100644 index ed9c7bf6c..000000000 --- a/sdk/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,4 +0,0 @@ -org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ - org.dromara.dynamictp.sdk.autoconfigure.AdminAutoConfiguration -org.springframework.boot.env.EnvironmentPostProcessor=\ - org.dromara.dynamictp.sdk.autoconfigure.AdminConfigEnvironmentProcessor diff --git a/starter/starter-adapter/starter-adapter-tars/src/main/java/org/dromara/dynamictp/starter/adapter/tars/autoconfigure/TarsTpAutoConfiguration.java b/starter/starter-adapter/starter-adapter-tars/src/main/java/org/dromara/dynamictp/starter/adapter/tars/autoconfigure/TarsTpAutoConfiguration.java index 187fef76e..88b5d9123 100644 --- a/starter/starter-adapter/starter-adapter-tars/src/main/java/org/dromara/dynamictp/starter/adapter/tars/autoconfigure/TarsTpAutoConfiguration.java +++ b/starter/starter-adapter/starter-adapter-tars/src/main/java/org/dromara/dynamictp/starter/adapter/tars/autoconfigure/TarsTpAutoConfiguration.java @@ -34,7 +34,7 @@ */ @Configuration @AutoConfigureAfter({DtpBaseBeanConfiguration.class}) -@ConditionalOnClass(name = "com.qq.tars.client.Communicator") +@ConditionalOnClass(name = "com.qq.tars.adminclient.Communicator") @ConditionalOnBean({DtpBaseBeanConfiguration.class}) public class TarsTpAutoConfiguration { From bf379acc91b505ba894b25124635dfa4477817d8 Mon Sep 17 00:00:00 2001 From: eachann Date: Thu, 21 Aug 2025 11:41:11 +0800 Subject: [PATCH 17/21] optimize client structure --- .../client/{adminclient => }/AdminClient.java | 29 ++++++------------- .../autoconfigure/AdminAutoConfiguration.java | 10 +++---- .../AdminConfigEnvironmentProcessor.java | 4 +-- .../handler/collector/AdminCollector.java | 2 +- .../handler/refresh/AdminRefresher.java | 2 +- .../processor/AdminClientUserProcessor.java | 6 ++-- .../processor/AdminCloseEventProcessor.java | 4 +-- .../processor/AdminConnectEventProcessor.java | 4 +-- ...tp.core.monitor.collector.MetricsCollector | 2 +- .../common/em/AdminRequestTypeEnum.java | 4 +-- .../common/entity/AdminRequestBody.java | 8 +++++ .../example/controller/TestController.java | 1 - .../example/service/impl/TestServiceImpl.java | 2 +- .../TarsTpAutoConfiguration.java | 2 +- 14 files changed, 37 insertions(+), 43 deletions(-) rename client/src/main/java/org/dromara/dynamictp/client/{adminclient => }/AdminClient.java (88%) rename client/src/main/java/org/dromara/dynamictp/client/{adminclient => }/handler/collector/AdminCollector.java (96%) rename client/src/main/java/org/dromara/dynamictp/client/{adminclient => }/handler/refresh/AdminRefresher.java (95%) rename client/src/main/java/org/dromara/dynamictp/client/{adminclient => }/processor/AdminClientUserProcessor.java (94%) rename client/src/main/java/org/dromara/dynamictp/client/{adminclient => }/processor/AdminCloseEventProcessor.java (93%) rename client/src/main/java/org/dromara/dynamictp/client/{adminclient => }/processor/AdminConnectEventProcessor.java (92%) diff --git a/client/src/main/java/org/dromara/dynamictp/client/adminclient/AdminClient.java b/client/src/main/java/org/dromara/dynamictp/client/AdminClient.java similarity index 88% rename from client/src/main/java/org/dromara/dynamictp/client/adminclient/AdminClient.java rename to client/src/main/java/org/dromara/dynamictp/client/AdminClient.java index dca7301aa..9c4a6b5b6 100644 --- a/client/src/main/java/org/dromara/dynamictp/client/adminclient/AdminClient.java +++ b/client/src/main/java/org/dromara/dynamictp/client/AdminClient.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.dromara.dynamictp.client.adminclient; +package org.dromara.dynamictp.client; import cn.hutool.core.lang.generator.SnowflakeGenerator; import com.alipay.remoting.Connection; @@ -30,14 +30,13 @@ import lombok.extern.slf4j.Slf4j; import org.dromara.dynamictp.common.entity.AdminRequestBody; import org.dromara.dynamictp.common.em.AdminRequestTypeEnum; -import org.dromara.dynamictp.client.adminclient.processor.AdminClientUserProcessor; -import org.dromara.dynamictp.client.adminclient.processor.AdminCloseEventProcessor; -import org.dromara.dynamictp.client.adminclient.processor.AdminConnectEventProcessor; +import org.dromara.dynamictp.client.processor.AdminClientUserProcessor; +import org.dromara.dynamictp.client.processor.AdminCloseEventProcessor; +import org.dromara.dynamictp.client.processor.AdminConnectEventProcessor; import org.springframework.beans.factory.annotation.Value; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; -import java.util.HashMap; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -162,14 +161,10 @@ public Object requestToServer(AdminRequestTypeEnum requestType) { adminIp, adminPort); return null; } - AdminRequestBody attributeRequestBody = new AdminRequestBody(SNOWFLAKE_GENERATOR.next(), AdminRequestTypeEnum.ATTRIBUTE); - HashMap attributes = new HashMap<>(); - attributes.put("clientName", clientName); - attributeRequestBody.setBody(attributes); AdminRequestBody requestBody = new AdminRequestBody(SNOWFLAKE_GENERATOR.next(), requestType); + requestBody.setAttributes("clientName", clientName); Object object = null; try { - client.invokeSync(connection, attributeRequestBody, 5000); object = client.invokeSync(connection, requestBody, 30000); } catch (RemotingException | InterruptedException e) { log.warn("DynamicTp admin client invoke failed, admin ip: {}, port: {}, exception:", adminIp, adminPort, e); @@ -184,13 +179,9 @@ public Object requestToServer(AdminRequestBody adminRequestBody) { adminIp, adminPort); return null; } - AdminRequestBody attributeRequestBody = new AdminRequestBody(SNOWFLAKE_GENERATOR.next(), AdminRequestTypeEnum.ATTRIBUTE); - HashMap attributes = new HashMap<>(); - attributes.put("clientName", clientName); - attributeRequestBody.setBody(attributes); + adminRequestBody.setAttributes("clientName", clientName); Object object = null; try { - client.invokeSync(connection, attributeRequestBody, 5000); object = client.invokeSync(connection, adminRequestBody, 5000); } catch (RemotingException | InterruptedException e) { log.warn("DynamicTp admin client invoke failed, admin ip: {}, port: {}, exception:", adminIp, adminPort, e); @@ -267,11 +258,9 @@ private boolean createConnection() { if (connection != null && connection.isFine()) { log.info("DynamicTp admin client connection created successfully, admin ip: {}, port: {}", adminIp, adminPort); - AdminRequestBody attributeRequestBody = new AdminRequestBody(SNOWFLAKE_GENERATOR.next(), AdminRequestTypeEnum.ATTRIBUTE); - HashMap attributes = new HashMap<>(); - attributes.put("clientName", clientName); - attributeRequestBody.setBody(attributes); - client.invokeSync(connection, attributeRequestBody, 5000); + AdminRequestBody adminRequestBody = new AdminRequestBody(SNOWFLAKE_GENERATOR.next(), AdminRequestTypeEnum.EXECUTOR_REFRESH); + adminRequestBody.setAttributes("clientName", clientName); + client.invokeSync(connection, adminRequestBody, 5000); return true; } else { log.warn("DynamicTp admin client connection created but not fine, admin ip: {}, port: {}", adminIp, diff --git a/client/src/main/java/org/dromara/dynamictp/client/autoconfigure/AdminAutoConfiguration.java b/client/src/main/java/org/dromara/dynamictp/client/autoconfigure/AdminAutoConfiguration.java index 2936b97ea..2e0bd5521 100644 --- a/client/src/main/java/org/dromara/dynamictp/client/autoconfigure/AdminAutoConfiguration.java +++ b/client/src/main/java/org/dromara/dynamictp/client/autoconfigure/AdminAutoConfiguration.java @@ -18,11 +18,11 @@ package org.dromara.dynamictp.client.autoconfigure; import org.dromara.dynamictp.common.properties.DtpProperties; -import org.dromara.dynamictp.client.adminclient.AdminClient; -import org.dromara.dynamictp.client.adminclient.handler.refresh.AdminRefresher; -import org.dromara.dynamictp.client.adminclient.processor.AdminClientUserProcessor; -import org.dromara.dynamictp.client.adminclient.processor.AdminCloseEventProcessor; -import org.dromara.dynamictp.client.adminclient.processor.AdminConnectEventProcessor; +import org.dromara.dynamictp.client.AdminClient; +import org.dromara.dynamictp.client.handler.refresh.AdminRefresher; +import org.dromara.dynamictp.client.processor.AdminClientUserProcessor; +import org.dromara.dynamictp.client.processor.AdminCloseEventProcessor; +import org.dromara.dynamictp.client.processor.AdminConnectEventProcessor; import org.dromara.dynamictp.spring.DtpBaseBeanConfiguration; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; diff --git a/client/src/main/java/org/dromara/dynamictp/client/autoconfigure/AdminConfigEnvironmentProcessor.java b/client/src/main/java/org/dromara/dynamictp/client/autoconfigure/AdminConfigEnvironmentProcessor.java index b91690017..49913bee5 100644 --- a/client/src/main/java/org/dromara/dynamictp/client/autoconfigure/AdminConfigEnvironmentProcessor.java +++ b/client/src/main/java/org/dromara/dynamictp/client/autoconfigure/AdminConfigEnvironmentProcessor.java @@ -21,8 +21,8 @@ import org.dromara.dynamictp.common.em.AdminRequestTypeEnum; import org.dromara.dynamictp.common.properties.DtpProperties; import org.dromara.dynamictp.core.support.binder.BinderHelper; -import org.dromara.dynamictp.client.adminclient.AdminClient; -import org.dromara.dynamictp.client.adminclient.processor.AdminClientUserProcessor; +import org.dromara.dynamictp.client.AdminClient; +import org.dromara.dynamictp.client.processor.AdminClientUserProcessor; import org.springframework.boot.SpringApplication; import org.springframework.boot.env.EnvironmentPostProcessor; import org.springframework.boot.env.OriginTrackedMapPropertySource; diff --git a/client/src/main/java/org/dromara/dynamictp/client/adminclient/handler/collector/AdminCollector.java b/client/src/main/java/org/dromara/dynamictp/client/handler/collector/AdminCollector.java similarity index 96% rename from client/src/main/java/org/dromara/dynamictp/client/adminclient/handler/collector/AdminCollector.java rename to client/src/main/java/org/dromara/dynamictp/client/handler/collector/AdminCollector.java index 7bdcd5dfc..d50aaa10c 100644 --- a/client/src/main/java/org/dromara/dynamictp/client/adminclient/handler/collector/AdminCollector.java +++ b/client/src/main/java/org/dromara/dynamictp/client/handler/collector/AdminCollector.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.dromara.dynamictp.client.adminclient.handler.collector; +package org.dromara.dynamictp.client.handler.collector; import org.dromara.dynamictp.common.em.CollectorTypeEnum; import org.dromara.dynamictp.common.entity.ThreadPoolStats; diff --git a/client/src/main/java/org/dromara/dynamictp/client/adminclient/handler/refresh/AdminRefresher.java b/client/src/main/java/org/dromara/dynamictp/client/handler/refresh/AdminRefresher.java similarity index 95% rename from client/src/main/java/org/dromara/dynamictp/client/adminclient/handler/refresh/AdminRefresher.java rename to client/src/main/java/org/dromara/dynamictp/client/handler/refresh/AdminRefresher.java index 14843a056..ed2713aac 100644 --- a/client/src/main/java/org/dromara/dynamictp/client/adminclient/handler/refresh/AdminRefresher.java +++ b/client/src/main/java/org/dromara/dynamictp/client/handler/refresh/AdminRefresher.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.dromara.dynamictp.client.adminclient.handler.refresh; +package org.dromara.dynamictp.client.handler.refresh; import lombok.extern.slf4j.Slf4j; diff --git a/client/src/main/java/org/dromara/dynamictp/client/adminclient/processor/AdminClientUserProcessor.java b/client/src/main/java/org/dromara/dynamictp/client/processor/AdminClientUserProcessor.java similarity index 94% rename from client/src/main/java/org/dromara/dynamictp/client/adminclient/processor/AdminClientUserProcessor.java rename to client/src/main/java/org/dromara/dynamictp/client/processor/AdminClientUserProcessor.java index 1c18f9480..168d7523c 100644 --- a/client/src/main/java/org/dromara/dynamictp/client/adminclient/processor/AdminClientUserProcessor.java +++ b/client/src/main/java/org/dromara/dynamictp/client/processor/AdminClientUserProcessor.java @@ -15,15 +15,15 @@ * limitations under the License. */ -package org.dromara.dynamictp.client.adminclient.processor; +package org.dromara.dynamictp.client.processor; import com.alipay.remoting.BizContext; import com.alipay.remoting.rpc.protocol.SyncUserProcessor; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.dromara.dynamictp.common.entity.AdminRequestBody; -import org.dromara.dynamictp.client.adminclient.handler.collector.AdminCollector; -import org.dromara.dynamictp.client.adminclient.handler.refresh.AdminRefresher; +import org.dromara.dynamictp.client.handler.collector.AdminCollector; +import org.dromara.dynamictp.client.handler.refresh.AdminRefresher; import org.springframework.beans.factory.annotation.Autowired; import java.util.Map; diff --git a/client/src/main/java/org/dromara/dynamictp/client/adminclient/processor/AdminCloseEventProcessor.java b/client/src/main/java/org/dromara/dynamictp/client/processor/AdminCloseEventProcessor.java similarity index 93% rename from client/src/main/java/org/dromara/dynamictp/client/adminclient/processor/AdminCloseEventProcessor.java rename to client/src/main/java/org/dromara/dynamictp/client/processor/AdminCloseEventProcessor.java index de8a3dd04..5a172fc91 100644 --- a/client/src/main/java/org/dromara/dynamictp/client/adminclient/processor/AdminCloseEventProcessor.java +++ b/client/src/main/java/org/dromara/dynamictp/client/processor/AdminCloseEventProcessor.java @@ -15,12 +15,12 @@ * limitations under the License. */ -package org.dromara.dynamictp.client.adminclient.processor; +package org.dromara.dynamictp.client.processor; import com.alipay.remoting.Connection; import com.alipay.remoting.ConnectionEventProcessor; import lombok.extern.slf4j.Slf4j; -import org.dromara.dynamictp.client.adminclient.AdminClient; +import org.dromara.dynamictp.client.AdminClient; /** * AdminCloseEventProcessor related diff --git a/client/src/main/java/org/dromara/dynamictp/client/adminclient/processor/AdminConnectEventProcessor.java b/client/src/main/java/org/dromara/dynamictp/client/processor/AdminConnectEventProcessor.java similarity index 92% rename from client/src/main/java/org/dromara/dynamictp/client/adminclient/processor/AdminConnectEventProcessor.java rename to client/src/main/java/org/dromara/dynamictp/client/processor/AdminConnectEventProcessor.java index 947a3a5d3..770f955ab 100644 --- a/client/src/main/java/org/dromara/dynamictp/client/adminclient/processor/AdminConnectEventProcessor.java +++ b/client/src/main/java/org/dromara/dynamictp/client/processor/AdminConnectEventProcessor.java @@ -15,12 +15,12 @@ * limitations under the License. */ -package org.dromara.dynamictp.client.adminclient.processor; +package org.dromara.dynamictp.client.processor; import com.alipay.remoting.Connection; import com.alipay.remoting.ConnectionEventProcessor; import lombok.extern.slf4j.Slf4j; -import org.dromara.dynamictp.client.adminclient.AdminClient; +import org.dromara.dynamictp.client.AdminClient; /** * AdminConnectEventProcessor related diff --git a/client/src/main/resources/META-INF/services/org.dromara.dynamictp.core.monitor.collector.MetricsCollector b/client/src/main/resources/META-INF/services/org.dromara.dynamictp.core.monitor.collector.MetricsCollector index 8a9eb37c2..f2b87fdc4 100644 --- a/client/src/main/resources/META-INF/services/org.dromara.dynamictp.core.monitor.collector.MetricsCollector +++ b/client/src/main/resources/META-INF/services/org.dromara.dynamictp.core.monitor.collector.MetricsCollector @@ -1 +1 @@ -org.dromara.dynamictp.client.adminclient.handler.collector.AdminCollector \ No newline at end of file +org.dromara.dynamictp.client.handler.collector.AdminCollector \ No newline at end of file diff --git a/common/src/main/java/org/dromara/dynamictp/common/em/AdminRequestTypeEnum.java b/common/src/main/java/org/dromara/dynamictp/common/em/AdminRequestTypeEnum.java index 337ec55e1..0187e0062 100644 --- a/common/src/main/java/org/dromara/dynamictp/common/em/AdminRequestTypeEnum.java +++ b/common/src/main/java/org/dromara/dynamictp/common/em/AdminRequestTypeEnum.java @@ -35,9 +35,7 @@ public enum AdminRequestTypeEnum { ALARM_MANAGE("alarm_manage"), - LOG_MANAGE("log_manage"), - - ATTRIBUTE("attribute"); + LOG_MANAGE("log_manage"); private final String value; diff --git a/common/src/main/java/org/dromara/dynamictp/common/entity/AdminRequestBody.java b/common/src/main/java/org/dromara/dynamictp/common/entity/AdminRequestBody.java index 1668fbd9a..84eec0759 100644 --- a/common/src/main/java/org/dromara/dynamictp/common/entity/AdminRequestBody.java +++ b/common/src/main/java/org/dromara/dynamictp/common/entity/AdminRequestBody.java @@ -23,6 +23,8 @@ import org.dromara.dynamictp.common.em.AdminRequestTypeEnum; import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; /** * @author eachann @@ -42,6 +44,9 @@ public class AdminRequestBody implements Serializable { @Getter private Object body; + @Getter + private Map attributes = new HashMap<>(); + public AdminRequestBody(long id, AdminRequestTypeEnum requestType) { this.id = id; this.requestType = requestType; @@ -53,4 +58,7 @@ public AdminRequestBody(long id, AdminRequestTypeEnum requestType, Object body) this.requestType = requestType; } + public void setAttributes(String key, String value) { + this.attributes.put(key, value); + } } diff --git a/example/example-admin/src/main/java/org/dromara/dynamictp/example/controller/TestController.java b/example/example-admin/src/main/java/org/dromara/dynamictp/example/controller/TestController.java index b7676df64..04d89aa6a 100644 --- a/example/example-admin/src/main/java/org/dromara/dynamictp/example/controller/TestController.java +++ b/example/example-admin/src/main/java/org/dromara/dynamictp/example/controller/TestController.java @@ -17,7 +17,6 @@ package org.dromara.dynamictp.example.controller; -import com.alipay.remoting.exception.RemotingException; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.AllArgsConstructor; diff --git a/example/example-admin/src/main/java/org/dromara/dynamictp/example/service/impl/TestServiceImpl.java b/example/example-admin/src/main/java/org/dromara/dynamictp/example/service/impl/TestServiceImpl.java index 0825bbaff..b72fab7c4 100644 --- a/example/example-admin/src/main/java/org/dromara/dynamictp/example/service/impl/TestServiceImpl.java +++ b/example/example-admin/src/main/java/org/dromara/dynamictp/example/service/impl/TestServiceImpl.java @@ -21,7 +21,7 @@ import org.dromara.dynamictp.core.executor.DtpExecutor; import org.dromara.dynamictp.core.executor.OrderedDtpExecutor; import org.dromara.dynamictp.example.service.TestService; -import org.dromara.dynamictp.client.adminclient.AdminClient; +import org.dromara.dynamictp.client.AdminClient; import org.dromara.dynamictp.common.em.AdminRequestTypeEnum; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Service; diff --git a/starter/starter-adapter/starter-adapter-tars/src/main/java/org/dromara/dynamictp/starter/adapter/tars/autoconfigure/TarsTpAutoConfiguration.java b/starter/starter-adapter/starter-adapter-tars/src/main/java/org/dromara/dynamictp/starter/adapter/tars/autoconfigure/TarsTpAutoConfiguration.java index 88b5d9123..187fef76e 100644 --- a/starter/starter-adapter/starter-adapter-tars/src/main/java/org/dromara/dynamictp/starter/adapter/tars/autoconfigure/TarsTpAutoConfiguration.java +++ b/starter/starter-adapter/starter-adapter-tars/src/main/java/org/dromara/dynamictp/starter/adapter/tars/autoconfigure/TarsTpAutoConfiguration.java @@ -34,7 +34,7 @@ */ @Configuration @AutoConfigureAfter({DtpBaseBeanConfiguration.class}) -@ConditionalOnClass(name = "com.qq.tars.adminclient.Communicator") +@ConditionalOnClass(name = "com.qq.tars.client.Communicator") @ConditionalOnBean({DtpBaseBeanConfiguration.class}) public class TarsTpAutoConfiguration { From 1e03e245a5eed956dec2d107e91227388ba5d92a Mon Sep 17 00:00:00 2001 From: eachann Date: Thu, 28 Aug 2025 20:20:25 +0800 Subject: [PATCH 18/21] complete cluster logic --- .../dromara/dynamictp/client/AdminClient.java | 228 +++++++++++++++--- .../client/cluster/AdminClusterManager.java | 206 ++++++++++++++++ .../dynamictp/client/node/AdminNode.java | 121 ++++++++++ .../client/selector/AdminNodeSelector.java | 41 ++++ .../selector/RandomAdminNodeSelector.java | 60 +++++ .../selector/RoundRobinAdminNodeSelector.java | 61 +++++ .../WeightedRoundRobinAdminNodeSelector.java | 96 ++++++++ .../resources/application-cluster-example.yml | 44 ++++ .../src/main/resources/application.yml | 16 +- 9 files changed, 836 insertions(+), 37 deletions(-) create mode 100644 client/src/main/java/org/dromara/dynamictp/client/cluster/AdminClusterManager.java create mode 100644 client/src/main/java/org/dromara/dynamictp/client/node/AdminNode.java create mode 100644 client/src/main/java/org/dromara/dynamictp/client/selector/AdminNodeSelector.java create mode 100644 client/src/main/java/org/dromara/dynamictp/client/selector/RandomAdminNodeSelector.java create mode 100644 client/src/main/java/org/dromara/dynamictp/client/selector/RoundRobinAdminNodeSelector.java create mode 100644 client/src/main/java/org/dromara/dynamictp/client/selector/WeightedRoundRobinAdminNodeSelector.java create mode 100644 example/example-admin/src/main/resources/application-cluster-example.yml diff --git a/client/src/main/java/org/dromara/dynamictp/client/AdminClient.java b/client/src/main/java/org/dromara/dynamictp/client/AdminClient.java index 9c4a6b5b6..ef5748238 100644 --- a/client/src/main/java/org/dromara/dynamictp/client/AdminClient.java +++ b/client/src/main/java/org/dromara/dynamictp/client/AdminClient.java @@ -28,15 +28,22 @@ import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; +import org.dromara.dynamictp.client.selector.RandomAdminNodeSelector; +import org.dromara.dynamictp.client.selector.WeightedRoundRobinAdminNodeSelector; import org.dromara.dynamictp.common.entity.AdminRequestBody; import org.dromara.dynamictp.common.em.AdminRequestTypeEnum; import org.dromara.dynamictp.client.processor.AdminClientUserProcessor; import org.dromara.dynamictp.client.processor.AdminCloseEventProcessor; import org.dromara.dynamictp.client.processor.AdminConnectEventProcessor; +import org.dromara.dynamictp.client.cluster.AdminClusterManager; +import org.dromara.dynamictp.client.node.AdminNode; +import org.dromara.dynamictp.client.selector.AdminNodeSelector; +import org.dromara.dynamictp.client.selector.RoundRobinAdminNodeSelector; import org.springframework.beans.factory.annotation.Value; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; +import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -51,12 +58,19 @@ @Slf4j public class AdminClient { - @Value("${dynamictp.adminIp:127.0.0.1}") - private String adminIp; + @Value("${dynamictp.adminNodes:}") + private String adminNodes; - @Value("${dynamictp.adminPort:8989}") - private int adminPort; + @Value("${dynamictp.loadBalanceStrategy:roundRobin}") + private String loadBalanceStrategy; + /** + * -- SETTER -- + * Set adminclient name manually + * + * @param clientName the adminclient name to set + */ + @Setter @Value("${dynamictp.clientName:${spring.application.name}}") private String clientName; @@ -75,6 +89,9 @@ public class AdminClient { @Setter private static Connection connection; + // 集群管理器 + private AdminClusterManager clusterManager; + // Connection state management private final AtomicBoolean isConnected = new AtomicBoolean(false); private final AtomicInteger retryCount = new AtomicInteger(0); @@ -100,19 +117,104 @@ public AdminClient(AdminClientUserProcessor adminClientUserProcessor, String cli this.clientName = clientName; } + @PostConstruct + public void init() { + try { + initClusterManager(); + createConnection(); + startHeartbeat(); + } catch (Exception e) { + log.error("Failed to initialize AdminClient", e); + // 如果初始化失败,不要启动心跳,避免持续重试 + if (heartbeatExecutor != null) { + stopHeartbeat(); + } + throw new RuntimeException("AdminClient initialization failed", e); + } + } + /** - * Set adminclient name manually - * - * @param clientName the adminclient name to set + * 初始化集群管理器 */ - public void setClientName(String clientName) { - this.clientName = clientName; + private void initClusterManager() { + // 创建节点选择器 + AdminNodeSelector selector = createNodeSelector(); + + // 创建集群管理器 + clusterManager = new AdminClusterManager(selector); + + // 添加配置的节点 + addConfiguredNodes(); + + log.info("Admin cluster manager initialized with {} nodes", clusterManager.getAllNodes().size()); } - @PostConstruct - public void init() { - createConnection(); - startHeartbeat(); + /** + * 创建节点选择器 + */ + private AdminNodeSelector createNodeSelector() { + switch (loadBalanceStrategy.toLowerCase()) { + case "random": + return new RandomAdminNodeSelector(); + case "weighted": + return new WeightedRoundRobinAdminNodeSelector(); + case "roundRobin": + default: + return new RoundRobinAdminNodeSelector(); + } + } + + /** + * 添加配置的节点 + */ + private void addConfiguredNodes() { + log.info("Configuring admin nodes: adminNodes={}", adminNodes); + + if (adminNodes == null || adminNodes.trim().isEmpty()) { + log.error("No admin nodes configured. Please configure dynamictp.adminNodes property."); + throw new IllegalStateException("No admin nodes configured"); + } + + String[] nodeConfigs = adminNodes.split(","); + log.info("Parsed {} node configurations", nodeConfigs.length); + + for (String nodeConfig : nodeConfigs) { + String trimmedConfig = nodeConfig.trim(); + if (trimmedConfig.isEmpty()) { + log.warn("Skipping empty node configuration"); + continue; + } + + String[] parts = trimmedConfig.split(":"); + if (parts.length >= 2) { + try { + String ip = parts[0].trim(); + int port = Integer.parseInt(parts[1].trim()); + int weight = parts.length > 2 ? Integer.parseInt(parts[2].trim()) : 1; + + if (ip.isEmpty()) { + log.error("Invalid IP address in node configuration: {}", trimmedConfig); + throw new IllegalArgumentException("Invalid IP address in node configuration: " + trimmedConfig); + } + + clusterManager.addNode(ip, port, weight); + log.info("Added admin node: {}:{} with weight {}", ip, port, weight); + } catch (NumberFormatException e) { + log.error("Invalid admin node configuration: {}", trimmedConfig, e); + throw new IllegalArgumentException("Invalid admin node configuration: " + trimmedConfig, e); + } + } else { + log.error("Invalid admin node configuration format: {}", trimmedConfig); + throw new IllegalArgumentException("Invalid admin node configuration format: " + trimmedConfig); + } + } + + if (clusterManager.getAllNodes().isEmpty()) { + log.error("No valid admin nodes found in configuration"); + throw new IllegalStateException("No valid admin nodes found in configuration"); + } + + log.info("Successfully configured {} admin nodes", clusterManager.getAllNodes().size()); } /** @@ -157,8 +259,7 @@ private void stopHeartbeat() { public Object requestToServer(AdminRequestTypeEnum requestType) { if (!ensureConnection()) { - log.error("DynamicTp admin client cannot establish connection after retries, admin ip: {}, port: {}", - adminIp, adminPort); + log.error("DynamicTp admin client cannot establish connection after retries"); return null; } AdminRequestBody requestBody = new AdminRequestBody(SNOWFLAKE_GENERATOR.next(), requestType); @@ -166,8 +267,18 @@ public Object requestToServer(AdminRequestTypeEnum requestType) { Object object = null; try { object = client.invokeSync(connection, requestBody, 30000); + // 标记当前节点成功 + AdminNode currentNode = getCurrentNode(); + if (currentNode != null) { + clusterManager.markNodeSuccess(currentNode); + } } catch (RemotingException | InterruptedException e) { - log.warn("DynamicTp admin client invoke failed, admin ip: {}, port: {}, exception:", adminIp, adminPort, e); + log.warn("DynamicTp admin client invoke failed, exception:", e); + // 标记当前节点失败 + AdminNode currentNode = getCurrentNode(); + if (currentNode != null) { + clusterManager.markNodeFailed(currentNode); + } isConnected.set(false); } return object; @@ -175,22 +286,48 @@ public Object requestToServer(AdminRequestTypeEnum requestType) { public Object requestToServer(AdminRequestBody adminRequestBody) { if (!ensureConnection()) { - log.error("DynamicTp admin client cannot establish connection after retries, admin ip: {}, port: {}", - adminIp, adminPort); + log.error("DynamicTp admin client cannot establish connection after retries"); return null; } adminRequestBody.setAttributes("clientName", clientName); Object object = null; try { object = client.invokeSync(connection, adminRequestBody, 5000); + // 标记当前节点成功 + AdminNode currentNode = getCurrentNode(); + if (currentNode != null) { + clusterManager.markNodeSuccess(currentNode); + } } catch (RemotingException | InterruptedException e) { - log.warn("DynamicTp admin client invoke failed, admin ip: {}, port: {}, exception:", adminIp, adminPort, e); + log.warn("DynamicTp admin client invoke failed, exception:", e); + // 标记当前节点失败 + AdminNode currentNode = getCurrentNode(); + if (currentNode != null) { + clusterManager.markNodeFailed(currentNode); + } // Mark connection as disconnected when request fails isConnected.set(false); } return object; } + /** + * 获取当前连接的节点 + */ + private AdminNode getCurrentNode() { + if (connection != null) { + String address = connection.getRemoteAddress().getAddress().getHostAddress(); + int port = connection.getRemoteAddress().getPort(); + + for (AdminNode node : clusterManager.getAllNodes()) { + if (node.getIp().equals(address) && node.getPort() == port) { + return node; + } + } + } + return null; + } + /** * Ensure connection is available, try to reconnect if not available * @@ -198,7 +335,7 @@ public Object requestToServer(AdminRequestBody adminRequestBody) { */ private boolean ensureConnection() { // Check connection status - if (isConnected.get() && connection != null && client.checkConnection(getAdminAddress(), true)) { + if (isConnected.get() && connection != null && connection.isFine()) { return true; } @@ -244,6 +381,12 @@ private boolean reconnectWithRetry() { private boolean createConnection() { try { + // 检查集群管理器是否已初始化 + if (clusterManager == null) { + log.error("Cluster manager not initialized"); + return false; + } + // Clean up old connection if (connection != null) { try { @@ -254,21 +397,28 @@ private boolean createConnection() { connection = null; } - connection = client.createStandaloneConnection(getAdminAddress(), 30000); + AdminNode selectedNode = clusterManager.selectNode(null); + if (selectedNode == null) { + log.error("No available admin nodes for connection"); + return false; + } + + connection = client.createStandaloneConnection(selectedNode.getAddress(), 30000); if (connection != null && connection.isFine()) { - log.info("DynamicTp admin client connection created successfully, admin ip: {}, port: {}", adminIp, - adminPort); - AdminRequestBody adminRequestBody = new AdminRequestBody(SNOWFLAKE_GENERATOR.next(), AdminRequestTypeEnum.EXECUTOR_REFRESH); + log.info("DynamicTp admin client connection created successfully, admin node: {}", + selectedNode.getAddress()); + AdminRequestBody adminRequestBody = new AdminRequestBody(SNOWFLAKE_GENERATOR.next(), + AdminRequestTypeEnum.EXECUTOR_REFRESH); adminRequestBody.setAttributes("clientName", clientName); client.invokeSync(connection, adminRequestBody, 5000); return true; } else { - log.warn("DynamicTp admin client connection created but not fine, admin ip: {}, port: {}", adminIp, - adminPort); + log.warn("DynamicTp admin client connection created but not fine, admin node: {}", + selectedNode.getAddress()); return false; } } catch (RemotingException | InterruptedException e) { - log.warn("DynamicTp admin create connection failed, admin ip: {}, port: {}", adminIp, adminPort, e); + log.warn("DynamicTp admin create connection failed", e); return false; } } @@ -303,13 +453,33 @@ public void updateConnectionStatus(boolean connected) { } } - private String getAdminAddress() { - return adminIp + ":" + adminPort; + /** + * 获取集群管理器 + */ + public AdminClusterManager getClusterManager() { + return clusterManager; + } + + /** + * 获取所有admin节点 + */ + public List getAllAdminNodes() { + return clusterManager != null ? clusterManager.getAllNodes() : null; + } + + /** + * 获取健康的admin节点 + */ + public List getHealthyAdminNodes() { + return clusterManager != null ? clusterManager.getHealthyNodes() : null; } @PreDestroy public void close() { stopHeartbeat(); + if (clusterManager != null) { + clusterManager.shutdown(); + } isConnected.set(false); if (connection != null) { try { diff --git a/client/src/main/java/org/dromara/dynamictp/client/cluster/AdminClusterManager.java b/client/src/main/java/org/dromara/dynamictp/client/cluster/AdminClusterManager.java new file mode 100644 index 000000000..4ea6bfdfb --- /dev/null +++ b/client/src/main/java/org/dromara/dynamictp/client/cluster/AdminClusterManager.java @@ -0,0 +1,206 @@ +/* + * 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 org.dromara.dynamictp.client.cluster; + +import lombok.extern.slf4j.Slf4j; +import org.dromara.dynamictp.client.node.AdminNode; +import org.dromara.dynamictp.client.selector.AdminNodeSelector; +import org.dromara.dynamictp.client.selector.RoundRobinAdminNodeSelector; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +/** + * Admin集群管理器 + * + * @author eachann + * @since 1.2.3 + */ +@Slf4j +public class AdminClusterManager { + + private final List adminNodes = new CopyOnWriteArrayList<>(); + private final AdminNodeSelector nodeSelector; + private final ScheduledExecutorService healthCheckExecutor; + + private static final long HEALTH_CHECK_INTERVAL = 30000; // 30秒 + private static final int MAX_FAIL_COUNT = 3; + + public AdminClusterManager() { + this(new RoundRobinAdminNodeSelector()); + } + + public AdminClusterManager(AdminNodeSelector nodeSelector) { + this.nodeSelector = nodeSelector; + this.healthCheckExecutor = Executors.newSingleThreadScheduledExecutor(r -> { + Thread thread = new Thread(r, "DynamicTp-AdminCluster-HealthCheck"); + thread.setDaemon(true); + return thread; + }); + + startHealthCheck(); + } + + /** + * 添加admin节点 + * + * @param ip 节点IP + * @param port 节点端口 + */ + public void addNode(String ip, int port) { + addNode(ip, port, 1); + } + + /** + * 添加admin节点 + * + * @param ip 节点IP + * @param port 节点端口 + * @param weight 节点权重 + */ + public void addNode(String ip, int port, int weight) { + AdminNode node = new AdminNode(ip, port, weight); + if (!adminNodes.contains(node)) { + adminNodes.add(node); + log.info("Added admin node: {}:{} with weight {}", ip, port, weight); + } + } + + /** + * 移除admin节点 + * + * @param ip 节点IP + * @param port 节点端口 + */ + public void removeNode(String ip, int port) { + adminNodes.removeIf(node -> node.getIp().equals(ip) && node.getPort() == port); + log.info("Removed admin node: {}:{}", ip, port); + } + + /** + * 选择admin节点 + * + * @param arg 选择参数 + * @return 选中的admin节点 + */ + public AdminNode selectNode(Object arg) { + if (adminNodes.isEmpty()) { + log.warn("No admin nodes available"); + return null; + } + + AdminNode selectedNode = nodeSelector.select(adminNodes); + if (selectedNode != null) { + log.debug("Selected admin node: {}", selectedNode.getAddress()); + } + return selectedNode; + } + + /** + * 获取所有admin节点 + * + * @return admin节点列表 + */ + public List getAllNodes() { + return new ArrayList<>(adminNodes); + } + + /** + * 获取健康的admin节点 + * + * @return 健康的admin节点列表 + */ + public List getHealthyNodes() { + return adminNodes.stream() + .filter(AdminNode::isAvailable) + .collect(java.util.stream.Collectors.toList()); + } + + /** + * 标记节点失败 + * + * @param node 失败的节点 + */ + public void markNodeFailed(AdminNode node) { + if (node != null) { + node.markFailed(); + log.warn("Marked admin node as failed: {}", node.getAddress()); + } + } + + /** + * 标记节点成功 + * + * @param node 成功的节点 + */ + public void markNodeSuccess(AdminNode node) { + if (node != null) { + node.markSuccess(); + log.debug("Marked admin node as success: {}", node.getAddress()); + } + } + + /** + * 启动健康检查 + */ + private void startHealthCheck() { + healthCheckExecutor.scheduleAtFixedRate(() -> { + try { + performHealthCheck(); + } catch (Exception e) { + log.warn("Health check execution failed", e); + } + }, HEALTH_CHECK_INTERVAL, HEALTH_CHECK_INTERVAL, TimeUnit.MILLISECONDS); + } + + /** + * 执行健康检查 + */ + private void performHealthCheck() { + for (AdminNode node : adminNodes) { + boolean healthy = node.isHealthy(MAX_FAIL_COUNT, HEALTH_CHECK_INTERVAL); + if (!healthy && node.isAvailable()) { + log.warn("Admin node {} is marked as unhealthy", node.getAddress()); + } + } + } + + /** + * 关闭集群管理器 + */ + public void shutdown() { + if (healthCheckExecutor != null && !healthCheckExecutor.isShutdown()) { + try { + healthCheckExecutor.shutdown(); + if (!healthCheckExecutor.awaitTermination(5, TimeUnit.SECONDS)) { + healthCheckExecutor.shutdownNow(); + } + log.info("Admin cluster manager health check stopped"); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + healthCheckExecutor.shutdownNow(); + log.warn("Admin cluster manager shutdown interrupted"); + } + } + } +} + diff --git a/client/src/main/java/org/dromara/dynamictp/client/node/AdminNode.java b/client/src/main/java/org/dromara/dynamictp/client/node/AdminNode.java new file mode 100644 index 000000000..925d530f9 --- /dev/null +++ b/client/src/main/java/org/dromara/dynamictp/client/node/AdminNode.java @@ -0,0 +1,121 @@ +/* + * 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 org.dromara.dynamictp.client.node; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * Admin节点信息 + * + * @author eachann + * @since 1.2.3 + */ +@Data +@EqualsAndHashCode +public class AdminNode { + + /** + * 节点IP地址 + */ + private String ip; + + /** + * 节点端口 + */ + private int port; + + /** + * 节点权重,用于加权负载均衡 + */ + private int weight = 1; + + /** + * 节点是否可用 + */ + private boolean available = true; + + /** + * 节点最后心跳时间 + */ + private long lastHeartbeatTime; + + /** + * 节点连接失败次数 + */ + private int failCount = 0; + + public AdminNode(String ip, int port) { + this.ip = ip; + this.port = port; + } + + public AdminNode(String ip, int port, int weight) { + this.ip = ip; + this.port = port; + this.weight = weight; + } + + /** + * 获取节点地址字符串 + * + * @return 节点地址 + */ + public String getAddress() { + return ip + ":" + port; + } + + /** + * 标记节点失败 + */ + public void markFailed() { + this.failCount++; + this.lastHeartbeatTime = System.currentTimeMillis(); + } + + /** + * 标记节点成功 + */ + public void markSuccess() { + this.failCount = 0; + this.lastHeartbeatTime = System.currentTimeMillis(); + this.available = true; + } + + /** + * 检查节点是否健康 + * + * @param maxFailCount 最大失败次数 + * @param healthCheckInterval 健康检查间隔(毫秒) + * @return 是否健康 + */ + public boolean isHealthy(int maxFailCount, long healthCheckInterval) { + if (failCount >= maxFailCount) { + this.available = false; + return false; + } + + if (System.currentTimeMillis() - lastHeartbeatTime > healthCheckInterval) { + this.available = false; + return false; + } + + return this.available; + } +} + diff --git a/client/src/main/java/org/dromara/dynamictp/client/selector/AdminNodeSelector.java b/client/src/main/java/org/dromara/dynamictp/client/selector/AdminNodeSelector.java new file mode 100644 index 000000000..28778cebe --- /dev/null +++ b/client/src/main/java/org/dromara/dynamictp/client/selector/AdminNodeSelector.java @@ -0,0 +1,41 @@ +/* + * 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 org.dromara.dynamictp.client.selector; + +import org.dromara.dynamictp.client.node.AdminNode; + +import java.util.List; + +/** + * Admin节点选择器接口,用于负载均衡选择admin节点 + * + * @author eachann + * @since 1.2.3 + */ +public interface AdminNodeSelector { + + /** + * 选择admin节点 + * + * @param nodes 可用的admin节点列表 + * @param arg 选择参数 + * @return 选中的admin节点 + */ + AdminNode select(List nodes); +} + diff --git a/client/src/main/java/org/dromara/dynamictp/client/selector/RandomAdminNodeSelector.java b/client/src/main/java/org/dromara/dynamictp/client/selector/RandomAdminNodeSelector.java new file mode 100644 index 000000000..683274f8d --- /dev/null +++ b/client/src/main/java/org/dromara/dynamictp/client/selector/RandomAdminNodeSelector.java @@ -0,0 +1,60 @@ +/* + * 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 org.dromara.dynamictp.client.selector; + +import lombok.extern.slf4j.Slf4j; +import org.dromara.dynamictp.client.node.AdminNode; + +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; +import java.util.stream.Collectors; + +/** + * 随机选择器实现 + * + * @author eachann + * @since 1.2.3 + */ +@Slf4j +public class RandomAdminNodeSelector implements AdminNodeSelector { + + @Override + public AdminNode select(List nodes) { + if (nodes == null || nodes.isEmpty()) { + log.warn("No available admin nodes for selection"); + return null; + } + + // 过滤出健康的节点 + List healthyNodes = nodes.stream() + .filter(AdminNode::isAvailable) + .collect(Collectors.toList()); + + if (healthyNodes.isEmpty()) { + log.warn("No healthy admin nodes available, using all nodes"); + healthyNodes = nodes; + } + + int index = ThreadLocalRandom.current().nextInt(healthyNodes.size()); + AdminNode selectedNode = healthyNodes.get(index); + + log.debug("Random selector selected admin node: {}", selectedNode.getAddress()); + return selectedNode; + } +} + diff --git a/client/src/main/java/org/dromara/dynamictp/client/selector/RoundRobinAdminNodeSelector.java b/client/src/main/java/org/dromara/dynamictp/client/selector/RoundRobinAdminNodeSelector.java new file mode 100644 index 000000000..522de5a5f --- /dev/null +++ b/client/src/main/java/org/dromara/dynamictp/client/selector/RoundRobinAdminNodeSelector.java @@ -0,0 +1,61 @@ +/* + * 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 org.dromara.dynamictp.client.selector; + +import lombok.extern.slf4j.Slf4j; +import org.dromara.dynamictp.client.node.AdminNode; + +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +/** + * 轮询选择器实现 + * + * @author eachann + * @since 1.2.3 + */ +@Slf4j +public class RoundRobinAdminNodeSelector implements AdminNodeSelector { + + private final AtomicInteger counter = new AtomicInteger(0); + + @Override + public AdminNode select(List nodes) { + if (nodes == null || nodes.isEmpty()) { + log.warn("No available admin nodes for selection"); + return null; + } + + // 过滤出健康的节点 + List healthyNodes = nodes.stream() + .filter(AdminNode::isAvailable) + .collect(Collectors.toList()); + + if (healthyNodes.isEmpty()) { + log.warn("No healthy admin nodes available, using all nodes"); + healthyNodes = nodes; + } + + int index = counter.getAndIncrement() % healthyNodes.size(); + AdminNode selectedNode = healthyNodes.get(index); + + log.debug("RoundRobin selector selected admin node: {}", selectedNode.getAddress()); + return selectedNode; + } +} diff --git a/client/src/main/java/org/dromara/dynamictp/client/selector/WeightedRoundRobinAdminNodeSelector.java b/client/src/main/java/org/dromara/dynamictp/client/selector/WeightedRoundRobinAdminNodeSelector.java new file mode 100644 index 000000000..1bab1c7dd --- /dev/null +++ b/client/src/main/java/org/dromara/dynamictp/client/selector/WeightedRoundRobinAdminNodeSelector.java @@ -0,0 +1,96 @@ +/* + * 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 org.dromara.dynamictp.client.selector; + +import lombok.extern.slf4j.Slf4j; +import org.dromara.dynamictp.client.node.AdminNode; + +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +/** + * 加权轮询选择器实现 + * + * @author eachann + * @since 1.2.3 + */ +@Slf4j +public class WeightedRoundRobinAdminNodeSelector implements AdminNodeSelector { + + private final AtomicInteger currentWeight = new AtomicInteger(0); + private final AtomicInteger currentIndex = new AtomicInteger(0); + + @Override + public AdminNode select(List nodes) { + if (nodes == null || nodes.isEmpty()) { + log.warn("No available admin nodes for selection"); + return null; + } + + // 过滤出健康的节点 + List healthyNodes = nodes.stream() + .filter(AdminNode::isAvailable) + .collect(Collectors.toList()); + + if (healthyNodes.isEmpty()) { + log.warn("No healthy admin nodes available, using all nodes"); + healthyNodes = nodes; + } + + if (healthyNodes.size() == 1) { + return healthyNodes.get(0); + } + + // 计算最大权重 + int maxWeight = healthyNodes.stream() + .mapToInt(AdminNode::getWeight) + .max() + .orElse(1); + + // 计算权重总和 + int weightSum = healthyNodes.stream() + .mapToInt(AdminNode::getWeight) + .sum(); + + AdminNode selectedNode = null; + while (selectedNode == null) { + int current = currentIndex.get(); + int weight = currentWeight.get(); + + if (weight == 0) { + weight = maxWeight; + currentWeight.set(weight); + } + + AdminNode node = healthyNodes.get(current); + if (node.getWeight() >= weight) { + selectedNode = node; + currentWeight.addAndGet(-weight); + } else { + currentWeight.addAndGet(-node.getWeight()); + } + + currentIndex.set((current + 1) % healthyNodes.size()); + } + + log.debug("WeightedRoundRobin selector selected admin node: {}", selectedNode.getAddress()); + return selectedNode; + } +} + diff --git a/example/example-admin/src/main/resources/application-cluster-example.yml b/example/example-admin/src/main/resources/application-cluster-example.yml new file mode 100644 index 000000000..c4325f1c4 --- /dev/null +++ b/example/example-admin/src/main/resources/application-cluster-example.yml @@ -0,0 +1,44 @@ +# DynamicTp Admin Client 集群和负载均衡配置示例 +# 将此配置添加到你的 application.yml 或 bootstrap.yml 中 + +dynamictp: + # 集群配置 - 必须配置多个admin节点 + # 格式:ip:port:weight,ip:port:weight + # weight为可选参数,默认为1 + adminNodes: > + 192.168.1.100:8989:2, + 192.168.1.101:8989:1, + 192.168.1.102:8989:3 + + # 负载均衡策略 + # 可选值:roundRobin(轮询,默认)、random(随机)、weighted(加权轮询) + loadBalanceStrategy: roundRobin + + # 其他配置 + clientName: ${spring.application.name} + adminEnabled: true +# 集群配置说明: +# 1. adminNodes: 必须配置多个admin节点,用逗号分隔 +# - 每个节点格式:ip:port:weight +# - weight为权重,数值越大被选中的概率越高 +# - 如果不指定weight,默认为1 +# - 至少需要配置2个节点才能形成集群 +# +# 2. loadBalanceStrategy: 负载均衡策略 +# - roundRobin: 轮询选择,按顺序选择节点 +# - random: 随机选择,每次随机选择一个可用节点 +# - weighted: 加权轮询,根据节点权重进行选择 +# +# 3. 故障转移:当某个节点不可用时,自动选择其他健康节点 +# 4. 健康检查:定期检查节点健康状态,自动标记不健康节点 +# 5. 权重支持:支持为不同节点设置不同权重,实现负载分配 +# +# 重要提示: +# - adminNodes 配置项是必须的,不能为空 +# - 至少需要配置2个节点才能启用集群功能 +# - 单个节点配置将导致启动失败 +# +# 示例场景: +# - 生产环境:配置多个admin节点,使用加权轮询 +# - 测试环境:配置2-3个节点,使用轮询策略 +# - 高可用:配置多个节点,自动故障转移 diff --git a/example/example-admin/src/main/resources/application.yml b/example/example-admin/src/main/resources/application.yml index 9cb910a14..41d689573 100644 --- a/example/example-admin/src/main/resources/application.yml +++ b/example/example-admin/src/main/resources/application.yml @@ -12,13 +12,13 @@ spring: dynamictp: adminEnabled: true - adminPort: 8989 clientName: dynamic-tp-admin-demo collector-types: admin - -#logging: -# level: -# org: -# springframework: -# boot: -# autoconfigure: DEBUG \ No newline at end of file + # 集群配置 - 必须配置多个admin节点 + # 格式:ip:port:weight,ip:port:weight + # weight为可选参数,默认为1 + adminNodes: > + 127.0.0.1:8989 + # 负载均衡策略 + # 可选值:roundRobin(轮询,默认)、random(随机)、weighted(加权轮询) + loadBalanceStrategy: roundRobin \ No newline at end of file From 9160bf45da0fac7062e9a4f186f2459d90cfb348 Mon Sep 17 00:00:00 2001 From: eachann Date: Tue, 16 Sep 2025 18:59:01 +0800 Subject: [PATCH 19/21] optimize client structure --- .../dromara/dynamictp/client/AdminClient.java | 59 +++++++++++++------ .../AdminConfigEnvironmentProcessor.java | 6 +- .../processor/AdminClientUserProcessor.java | 23 +++++++- 3 files changed, 67 insertions(+), 21 deletions(-) diff --git a/client/src/main/java/org/dromara/dynamictp/client/AdminClient.java b/client/src/main/java/org/dromara/dynamictp/client/AdminClient.java index ef5748238..dbf9a2f6a 100644 --- a/client/src/main/java/org/dromara/dynamictp/client/AdminClient.java +++ b/client/src/main/java/org/dromara/dynamictp/client/AdminClient.java @@ -65,15 +65,21 @@ public class AdminClient { private String loadBalanceStrategy; /** - * -- SETTER -- - * Set adminclient name manually * - * @param clientName the adminclient name to set + * @param clientName the adminclient name */ @Setter @Value("${dynamictp.clientName:${spring.application.name}}") private String clientName; + /** + * + * @param serviceName the adminclient service name + */ + @Setter + @Value("${dynamictp.serviceName:${spring.application.name}}") + private String serviceName; + @Value("${dynamictp.adminEnabled:false}") private Boolean adminEnabled; @@ -89,20 +95,38 @@ public class AdminClient { @Setter private static Connection connection; - // 集群管理器 + /** + * 集群管理器 + */ private AdminClusterManager clusterManager; - // Connection state management + /** + * Connection state management + */ private final AtomicBoolean isConnected = new AtomicBoolean(false); private final AtomicInteger retryCount = new AtomicInteger(0); private static final int MAX_RETRY_COUNT = 3; private static final long RETRY_DELAY_MS = 1000; - // Heartbeat mechanism + /** + * Heartbeat mechanism + */ private static final long HEARTBEAT_INTERVAL_SECONDS = 30; + private ScheduledExecutorService heartbeatExecutor; public AdminClient(AdminClientUserProcessor adminClientUserProcessor) { + this(adminClientUserProcessor, ""); + } + + public AdminClient(AdminClientUserProcessor adminClientUserProcessor, String clientName) { + this(adminClientUserProcessor, clientName, ""); + } + + public AdminClient(AdminClientUserProcessor adminClientUserProcessor, String clientName, String serviceName) { + this.clientName = clientName; + this.serviceName = serviceName; + client.addConnectionEventProcessor(ConnectionEventType.CONNECT, new AdminConnectEventProcessor(this)); client.addConnectionEventProcessor(ConnectionEventType.CLOSE, new AdminCloseEventProcessor(this)); client.registerUserProcessor(adminClientUserProcessor); @@ -112,11 +136,6 @@ public AdminClient(AdminClientUserProcessor adminClientUserProcessor) { System.setProperty(Configs.SERIALIZER, String.valueOf(SERIALIZER)); } - public AdminClient(AdminClientUserProcessor adminClientUserProcessor, String clientName) { - this(adminClientUserProcessor); - this.clientName = clientName; - } - @PostConstruct public void init() { try { @@ -264,6 +283,7 @@ public Object requestToServer(AdminRequestTypeEnum requestType) { } AdminRequestBody requestBody = new AdminRequestBody(SNOWFLAKE_GENERATOR.next(), requestType); requestBody.setAttributes("clientName", clientName); + requestBody.setAttributes("serviceName", serviceName); Object object = null; try { object = client.invokeSync(connection, requestBody, 30000); @@ -284,15 +304,16 @@ public Object requestToServer(AdminRequestTypeEnum requestType) { return object; } - public Object requestToServer(AdminRequestBody adminRequestBody) { + public Object requestToServer(AdminRequestBody requestBody) { if (!ensureConnection()) { log.error("DynamicTp admin client cannot establish connection after retries"); return null; } - adminRequestBody.setAttributes("clientName", clientName); + requestBody.setAttributes("clientName", clientName); + requestBody.setAttributes("serviceName", serviceName); Object object = null; try { - object = client.invokeSync(connection, adminRequestBody, 5000); + object = client.invokeSync(connection, requestBody, 5000); // 标记当前节点成功 AdminNode currentNode = getCurrentNode(); if (currentNode != null) { @@ -366,7 +387,8 @@ private boolean reconnectWithRetry() { if (currentRetry < MAX_RETRY_COUNT) { try { - Thread.sleep(RETRY_DELAY_MS * currentRetry); // Incremental delay + // Incremental delay + Thread.sleep(RETRY_DELAY_MS * currentRetry); } catch (InterruptedException e) { Thread.currentThread().interrupt(); log.warn("DynamicTp admin client reconnection interrupted"); @@ -407,10 +429,11 @@ private boolean createConnection() { if (connection != null && connection.isFine()) { log.info("DynamicTp admin client connection created successfully, admin node: {}", selectedNode.getAddress()); - AdminRequestBody adminRequestBody = new AdminRequestBody(SNOWFLAKE_GENERATOR.next(), + AdminRequestBody requestBody = new AdminRequestBody(SNOWFLAKE_GENERATOR.next(), AdminRequestTypeEnum.EXECUTOR_REFRESH); - adminRequestBody.setAttributes("clientName", clientName); - client.invokeSync(connection, adminRequestBody, 5000); + requestBody.setAttributes("clientName", clientName); + requestBody.setAttributes("serviceName", serviceName); + client.invokeSync(connection, requestBody, 5000); return true; } else { log.warn("DynamicTp admin client connection created but not fine, admin node: {}", diff --git a/client/src/main/java/org/dromara/dynamictp/client/autoconfigure/AdminConfigEnvironmentProcessor.java b/client/src/main/java/org/dromara/dynamictp/client/autoconfigure/AdminConfigEnvironmentProcessor.java index 49913bee5..c82fb4d3f 100644 --- a/client/src/main/java/org/dromara/dynamictp/client/autoconfigure/AdminConfigEnvironmentProcessor.java +++ b/client/src/main/java/org/dromara/dynamictp/client/autoconfigure/AdminConfigEnvironmentProcessor.java @@ -54,10 +54,12 @@ public void postProcessEnvironment(ConfigurableEnvironment environment, SpringAp // 从 Environment 中直接获取 clientName 配置 String clientName = environment.getProperty("dynamictp.clientName", - environment.getProperty("spring.application.name", "unknown")); + environment.getProperty("spring.application.name")); + String serviceName = environment.getProperty("dynamictp.serviceName", + environment.getProperty("spring.application.name")); // 创建 AdminClient 时传入配置的 clientName - AdminClient adminClient = new AdminClient(new AdminClientUserProcessor(), clientName); + AdminClient adminClient = new AdminClient(new AdminClientUserProcessor(), clientName, serviceName); Map properties = (Map) adminClient .requestToServer(AdminRequestTypeEnum.EXECUTOR_REFRESH); diff --git a/client/src/main/java/org/dromara/dynamictp/client/processor/AdminClientUserProcessor.java b/client/src/main/java/org/dromara/dynamictp/client/processor/AdminClientUserProcessor.java index 168d7523c..fc8177c39 100644 --- a/client/src/main/java/org/dromara/dynamictp/client/processor/AdminClientUserProcessor.java +++ b/client/src/main/java/org/dromara/dynamictp/client/processor/AdminClientUserProcessor.java @@ -20,11 +20,13 @@ import com.alipay.remoting.BizContext; import com.alipay.remoting.rpc.protocol.SyncUserProcessor; import lombok.Getter; +import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.dromara.dynamictp.common.entity.AdminRequestBody; import org.dromara.dynamictp.client.handler.collector.AdminCollector; import org.dromara.dynamictp.client.handler.refresh.AdminRefresher; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import java.util.Map; import java.util.concurrent.Executor; @@ -46,6 +48,23 @@ public class AdminClientUserProcessor extends SyncUserProcessor Date: Sat, 20 Sep 2025 15:17:08 +0800 Subject: [PATCH 20/21] refactor AdminClient initialization and same client service connection error handling --- .../dromara/dynamictp/client/AdminClient.java | 36 +++++++++++++++---- .../AdminConfigEnvironmentProcessor.java | 7 ++-- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/client/src/main/java/org/dromara/dynamictp/client/AdminClient.java b/client/src/main/java/org/dromara/dynamictp/client/AdminClient.java index dbf9a2f6a..d3518bc6a 100644 --- a/client/src/main/java/org/dromara/dynamictp/client/AdminClient.java +++ b/client/src/main/java/org/dromara/dynamictp/client/AdminClient.java @@ -120,12 +120,23 @@ public AdminClient(AdminClientUserProcessor adminClientUserProcessor) { } public AdminClient(AdminClientUserProcessor adminClientUserProcessor, String clientName) { - this(adminClientUserProcessor, clientName, ""); + this(adminClientUserProcessor, clientName, "", "", "", false); } - public AdminClient(AdminClientUserProcessor adminClientUserProcessor, String clientName, String serviceName) { - this.clientName = clientName; - this.serviceName = serviceName; + public AdminClient(AdminClientUserProcessor adminClientUserProcessor, String clientName, String serviceName, String adminNodes, String loadBalanceStrategy, Boolean adminEnabled) { + if (!clientName.isEmpty()) { + this.clientName = clientName; + } + if (!serviceName.isEmpty()) { + this.serviceName = serviceName; + } + if (!adminNodes.isEmpty()) { + this.adminNodes = adminNodes; + } + if (!loadBalanceStrategy.isEmpty()) { + this.loadBalanceStrategy = loadBalanceStrategy; + } + this.adminEnabled = adminEnabled; client.addConnectionEventProcessor(ConnectionEventType.CONNECT, new AdminConnectEventProcessor(this)); client.addConnectionEventProcessor(ConnectionEventType.CLOSE, new AdminCloseEventProcessor(this)); @@ -301,6 +312,10 @@ public Object requestToServer(AdminRequestTypeEnum requestType) { } isConnected.set(false); } + if (object instanceof IllegalStateException) { + log.error(((IllegalStateException) object).getMessage()); + return null; + } return object; } @@ -329,6 +344,10 @@ public Object requestToServer(AdminRequestBody requestBody) { // Mark connection as disconnected when request fails isConnected.set(false); } + if (object instanceof IllegalStateException) { + log.error(((IllegalStateException) object).getMessage()); + return null; + } return object; } @@ -433,7 +452,12 @@ private boolean createConnection() { AdminRequestTypeEnum.EXECUTOR_REFRESH); requestBody.setAttributes("clientName", clientName); requestBody.setAttributes("serviceName", serviceName); - client.invokeSync(connection, requestBody, 5000); + Object object = client.invokeSync(connection, requestBody, 5000); + if (object instanceof IllegalStateException) { + log.error(((IllegalStateException) object).getMessage()); + client.closeStandaloneConnection(connection); + return false; + } return true; } else { log.warn("DynamicTp admin client connection created but not fine, admin node: {}", @@ -441,7 +465,7 @@ private boolean createConnection() { return false; } } catch (RemotingException | InterruptedException e) { - log.warn("DynamicTp admin create connection failed", e); + log.error("DynamicTp admin create connection failed", e); return false; } } diff --git a/client/src/main/java/org/dromara/dynamictp/client/autoconfigure/AdminConfigEnvironmentProcessor.java b/client/src/main/java/org/dromara/dynamictp/client/autoconfigure/AdminConfigEnvironmentProcessor.java index c82fb4d3f..d95987010 100644 --- a/client/src/main/java/org/dromara/dynamictp/client/autoconfigure/AdminConfigEnvironmentProcessor.java +++ b/client/src/main/java/org/dromara/dynamictp/client/autoconfigure/AdminConfigEnvironmentProcessor.java @@ -57,10 +57,13 @@ public void postProcessEnvironment(ConfigurableEnvironment environment, SpringAp environment.getProperty("spring.application.name")); String serviceName = environment.getProperty("dynamictp.serviceName", environment.getProperty("spring.application.name")); + String adminNodes = environment.getProperty("dynamictp.adminNodes"); + String loadBalanceStrategy = environment.getProperty("dynamictp.loadBalanceStrategy", "roundRobin"); + Boolean adminEnabled = Boolean.parseBoolean(environment.getProperty("dynamictp.adminEnabled", "false")); // 创建 AdminClient 时传入配置的 clientName - AdminClient adminClient = new AdminClient(new AdminClientUserProcessor(), clientName, serviceName); - + AdminClient adminClient = new AdminClient(new AdminClientUserProcessor(), clientName, serviceName, adminNodes, loadBalanceStrategy, adminEnabled); + adminClient.init(); Map properties = (Map) adminClient .requestToServer(AdminRequestTypeEnum.EXECUTOR_REFRESH); if (!checkPropertyExist(environment) && properties != null) { From 6da1f0918a705dd2de436f132ab80765bf618927 Mon Sep 17 00:00:00 2001 From: eachann Date: Wed, 1 Oct 2025 20:04:49 +0800 Subject: [PATCH 21/21] send health message to server while ensure connection --- .../dromara/dynamictp/client/AdminClient.java | 18 ++++++++++++++++++ .../client/selector/AdminNodeSelector.java | 1 - 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/client/src/main/java/org/dromara/dynamictp/client/AdminClient.java b/client/src/main/java/org/dromara/dynamictp/client/AdminClient.java index d3518bc6a..081706854 100644 --- a/client/src/main/java/org/dromara/dynamictp/client/AdminClient.java +++ b/client/src/main/java/org/dromara/dynamictp/client/AdminClient.java @@ -376,6 +376,21 @@ private AdminNode getCurrentNode() { private boolean ensureConnection() { // Check connection status if (isConnected.get() && connection != null && connection.isFine()) { + // send health message to server + AdminRequestBody requestBody = new AdminRequestBody(SNOWFLAKE_GENERATOR.next(), AdminRequestTypeEnum.EXECUTOR_MONITOR); + requestBody.setAttributes("clientName", clientName); + requestBody.setAttributes("serviceName", serviceName); + try { + client.invokeSync(connection, requestBody, 30000); + } catch (RemotingException | InterruptedException e) { + log.warn("DynamicTp admin client invoke failed, exception:", e); + // 标记当前节点失败 + AdminNode currentNode = getCurrentNode(); + if (currentNode != null) { + clusterManager.markNodeFailed(currentNode); + } + isConnected.set(false); + } return true; } @@ -502,6 +517,7 @@ public void updateConnectionStatus(boolean connected) { /** * 获取集群管理器 + * @return clusterManager */ public AdminClusterManager getClusterManager() { return clusterManager; @@ -509,6 +525,7 @@ public AdminClusterManager getClusterManager() { /** * 获取所有admin节点 + * @return allAdminNodes */ public List getAllAdminNodes() { return clusterManager != null ? clusterManager.getAllNodes() : null; @@ -516,6 +533,7 @@ public List getAllAdminNodes() { /** * 获取健康的admin节点 + * @return healthyAdminNodes */ public List getHealthyAdminNodes() { return clusterManager != null ? clusterManager.getHealthyNodes() : null; diff --git a/client/src/main/java/org/dromara/dynamictp/client/selector/AdminNodeSelector.java b/client/src/main/java/org/dromara/dynamictp/client/selector/AdminNodeSelector.java index 28778cebe..cc9d8399d 100644 --- a/client/src/main/java/org/dromara/dynamictp/client/selector/AdminNodeSelector.java +++ b/client/src/main/java/org/dromara/dynamictp/client/selector/AdminNodeSelector.java @@ -33,7 +33,6 @@ public interface AdminNodeSelector { * 选择admin节点 * * @param nodes 可用的admin节点列表 - * @param arg 选择参数 * @return 选中的admin节点 */ AdminNode select(List nodes);