diff --git a/channel/channel-server-app/pom.xml b/channel/channel-server-app/pom.xml new file mode 100644 index 000000000..3472104c4 --- /dev/null +++ b/channel/channel-server-app/pom.xml @@ -0,0 +1,76 @@ + + + + arthas-all + com.taobao.arthas + 3.3.10-SNAPSHOT + ../../pom.xml + + 4.0.0 + + arthas-channel-server-app + arthas-channel-server-app + + + 1.8 + 1.8 + + + + + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + + + + + org.springframework.boot + spring-boot-starter-webflux + + + org.springframework.boot + spring-boot-starter-web + + + com.taobao.arthas + arthas-channel-server-starter + ${project.version} + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + true + + + + + org.springframework.boot + spring-boot-maven-plugin + 2.1.7.RELEASE + + + package + + repackage + + + + + + + + \ No newline at end of file diff --git a/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/ArthasChannelApplication.java b/channel/channel-server-app/src/main/java/com/alibaba/arthas/channel/server/ArthasChannelApplication.java similarity index 95% rename from channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/ArthasChannelApplication.java rename to channel/channel-server-app/src/main/java/com/alibaba/arthas/channel/server/ArthasChannelApplication.java index 4c8e93119..0669970ba 100644 --- a/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/ArthasChannelApplication.java +++ b/channel/channel-server-app/src/main/java/com/alibaba/arthas/channel/server/ArthasChannelApplication.java @@ -4,7 +4,6 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.scheduling.annotation.EnableScheduling; -@EnableScheduling @SpringBootApplication public class ArthasChannelApplication { diff --git a/channel/channel-server/src/main/resources/application-memory.properties b/channel/channel-server-app/src/main/resources/application-memory.properties similarity index 100% rename from channel/channel-server/src/main/resources/application-memory.properties rename to channel/channel-server-app/src/main/resources/application-memory.properties diff --git a/channel/channel-server/src/main/resources/application-redis.properties b/channel/channel-server-app/src/main/resources/application-redis.properties similarity index 100% rename from channel/channel-server/src/main/resources/application-redis.properties rename to channel/channel-server-app/src/main/resources/application-redis.properties diff --git a/channel/channel-server/src/main/resources/application.properties b/channel/channel-server-app/src/main/resources/application.properties similarity index 100% rename from channel/channel-server/src/main/resources/application.properties rename to channel/channel-server-app/src/main/resources/application.properties diff --git a/channel/channel-server/src/main/resources/static/bootstrap-4.2.1.min.css b/channel/channel-server-app/src/main/resources/static/bootstrap-4.2.1.min.css similarity index 100% rename from channel/channel-server/src/main/resources/static/bootstrap-4.2.1.min.css rename to channel/channel-server-app/src/main/resources/static/bootstrap-4.2.1.min.css diff --git a/channel/channel-server/src/main/resources/static/bootstrap-4.2.1.min.js b/channel/channel-server-app/src/main/resources/static/bootstrap-4.2.1.min.js similarity index 100% rename from channel/channel-server/src/main/resources/static/bootstrap-4.2.1.min.js rename to channel/channel-server-app/src/main/resources/static/bootstrap-4.2.1.min.js diff --git a/channel/channel-server/src/main/resources/static/fullsc.png b/channel/channel-server-app/src/main/resources/static/fullsc.png similarity index 100% rename from channel/channel-server/src/main/resources/static/fullsc.png rename to channel/channel-server-app/src/main/resources/static/fullsc.png diff --git a/channel/channel-server/src/main/resources/static/index.html b/channel/channel-server-app/src/main/resources/static/index.html similarity index 100% rename from channel/channel-server/src/main/resources/static/index.html rename to channel/channel-server-app/src/main/resources/static/index.html diff --git a/channel/channel-server/src/main/resources/static/jquery-3.3.1.slim.min.js b/channel/channel-server-app/src/main/resources/static/jquery-3.3.1.slim.min.js similarity index 100% rename from channel/channel-server/src/main/resources/static/jquery-3.3.1.slim.min.js rename to channel/channel-server-app/src/main/resources/static/jquery-3.3.1.slim.min.js diff --git a/channel/channel-server/src/main/resources/static/logo.png b/channel/channel-server-app/src/main/resources/static/logo.png similarity index 100% rename from channel/channel-server/src/main/resources/static/logo.png rename to channel/channel-server-app/src/main/resources/static/logo.png diff --git a/channel/channel-server/src/main/resources/static/main.css b/channel/channel-server-app/src/main/resources/static/main.css similarity index 100% rename from channel/channel-server/src/main/resources/static/main.css rename to channel/channel-server-app/src/main/resources/static/main.css diff --git a/channel/channel-server/src/main/resources/static/popper-1.14.6.min.js b/channel/channel-server-app/src/main/resources/static/popper-1.14.6.min.js similarity index 100% rename from channel/channel-server/src/main/resources/static/popper-1.14.6.min.js rename to channel/channel-server-app/src/main/resources/static/popper-1.14.6.min.js diff --git a/channel/channel-server/src/main/resources/static/web-console.js b/channel/channel-server-app/src/main/resources/static/web-console.js similarity index 100% rename from channel/channel-server/src/main/resources/static/web-console.js rename to channel/channel-server-app/src/main/resources/static/web-console.js diff --git a/channel/channel-server/src/main/resources/static/xterm.css b/channel/channel-server-app/src/main/resources/static/xterm.css similarity index 100% rename from channel/channel-server/src/main/resources/static/xterm.css rename to channel/channel-server-app/src/main/resources/static/xterm.css diff --git a/channel/channel-server/src/main/resources/static/xterm.js b/channel/channel-server-app/src/main/resources/static/xterm.js similarity index 100% rename from channel/channel-server/src/main/resources/static/xterm.js rename to channel/channel-server-app/src/main/resources/static/xterm.js diff --git a/channel/channel-server-starter/pom.xml b/channel/channel-server-starter/pom.xml new file mode 100644 index 000000000..e003b76a6 --- /dev/null +++ b/channel/channel-server-starter/pom.xml @@ -0,0 +1,51 @@ + + + + arthas-all + com.taobao.arthas + 3.3.10-SNAPSHOT + ../../pom.xml + + 4.0.0 + + arthas-channel-server-starter + arthas-channel-server-starter + + + 1.8 + 1.8 + + + + + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + + + + + org.springframework.boot + spring-boot-autoconfigure + + + org.springframework.boot + spring-boot-configuration-processor + true + + + com.taobao.arthas + arthas-channel-server + ${project.version} + + + + \ No newline at end of file diff --git a/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/configuration/ChannelServerConfiguration.java b/channel/channel-server-starter/src/main/java/com/alibaba/arthas/channel/server/autoconfigure/ChannelServerAutoConfiguration.java similarity index 71% rename from channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/configuration/ChannelServerConfiguration.java rename to channel/channel-server-starter/src/main/java/com/alibaba/arthas/channel/server/autoconfigure/ChannelServerAutoConfiguration.java index c378f0007..461b8d555 100644 --- a/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/configuration/ChannelServerConfiguration.java +++ b/channel/channel-server-starter/src/main/java/com/alibaba/arthas/channel/server/autoconfigure/ChannelServerAutoConfiguration.java @@ -1,5 +1,6 @@ -package com.alibaba.arthas.channel.server.configuration; +package com.alibaba.arthas.channel.server.autoconfigure; +import com.alibaba.arthas.channel.server.conf.ScheduledExecutorConfig; import com.alibaba.arthas.channel.server.grpc.ArthasServiceGrpcImpl; import com.alibaba.arthas.channel.server.grpc.ChannelServer; import com.alibaba.arthas.channel.server.message.MessageExchangeService; @@ -7,13 +8,15 @@ import com.alibaba.arthas.channel.server.message.impl.MessageExchangeServiceImpl import com.alibaba.arthas.channel.server.redis.RedisAgentManageServiceImpl; import com.alibaba.arthas.channel.server.redis.RedisMessageExchangeServiceImpl; import com.alibaba.arthas.channel.server.service.AgentBizSerivce; +import com.alibaba.arthas.channel.server.service.AgentCleaner; import com.alibaba.arthas.channel.server.service.AgentManageService; import com.alibaba.arthas.channel.server.service.ApiActionDelegateService; import com.alibaba.arthas.channel.server.service.impl.AgentBizServiceImpl; import com.alibaba.arthas.channel.server.service.impl.AgentManageServiceImpl; import com.alibaba.arthas.channel.server.service.impl.ApiActionDelegateServiceImpl; import com.alibaba.arthas.channel.server.ws.WebSocketServer; -import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; @@ -29,16 +32,16 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ThreadFactory; -/** - * @author gongdewei 2020/8/14 - */ + @Configuration +@ConditionalOnClass(ChannelServer.class) @EnableConfigurationProperties(ChannelServerProperties.class) -public class ChannelServerConfiguration { +public class ChannelServerAutoConfiguration { @Bean - public ScheduledExecutorService executorService() { - // 设置较大的corePoolSize,避免长时间运行的task阻塞调度队列 (https://developer.aliyun.com/article/5897 "1.2 线程数量控制") + @ConditionalOnMissingBean + public ScheduledExecutorConfig scheduledExecutorConfig() { + // 设置较大的corePoolSize,避免并发运行的task阻塞调度队列 (https://developer.aliyun.com/article/5897 "1.2 线程数量控制") int corePoolSize = 10; ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(corePoolSize, new ThreadFactory() { @Override @@ -49,12 +52,15 @@ public class ChannelServerConfiguration { } }); - //ScheduledThreadPoolExecutor为无界队列,设置MaximumPoolSize无效 -// if (executorService instanceof ThreadPoolExecutor) { -// ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executorService; -// threadPoolExecutor.setMaximumPoolSize(50); -// } - return executorService; + ScheduledExecutorConfig scheduledExecutorConfig = new ScheduledExecutorConfig(); + scheduledExecutorConfig.setExecutorService(executorService); + return scheduledExecutorConfig; + } + + @Bean + @ConditionalOnMissingBean + public AgentBizSerivce agentBizSerivce() { + return new AgentBizServiceImpl(); } @Bean @@ -62,25 +68,33 @@ public class ChannelServerConfiguration { return new ApiActionDelegateServiceImpl(); } - @Bean - public AgentBizSerivce agentBizSerivce() { - return new AgentBizServiceImpl(); - } - @Bean public ArthasServiceGrpcImpl arthasServiceGrpc() { return new ArthasServiceGrpcImpl(); } @Bean(initMethod = "start", destroyMethod = "stop") + public AgentCleaner agentCleaner(ScheduledExecutorConfig scheduledExecutorConfig, ChannelServerProperties serverProperties) { + ChannelServerProperties.Agent agentConfig = serverProperties.getAgent(); + AgentCleaner agentCleaner = new AgentCleaner(scheduledExecutorConfig); + agentCleaner.setCleanIntervalMills(agentConfig.getCleanIntervalMills()); + agentCleaner.setRemovingTimeout(agentConfig.getRemovingTimeoutMills()); + agentCleaner.setDownTimeout(agentConfig.getDownTimeoutMills()); + agentCleaner.setOutOfServiceTimeout(agentConfig.getOutOfServiceTimeoutMills()); + return agentCleaner; + } + + @Bean(initMethod = "start", destroyMethod = "stop") + @ConditionalOnMissingBean @ConditionalOnProperty(value = "channel.server.backend.enabled", havingValue = "true", matchIfMissing = false) - public ChannelServer channelServer(@Value("${channel.server.backend.port}") int port) { + public ChannelServer channelServer(ChannelServerProperties serverProperties) { ChannelServer channelServer = new ChannelServer(); - channelServer.setPort(port); + channelServer.setPort(serverProperties.getBackend().getPort()); return channelServer; } @Bean(initMethod = "start", destroyMethod = "stop") + @ConditionalOnMissingBean @ConditionalOnProperty(value = "channel.server.websocket.enabled", havingValue = "true", matchIfMissing = false) public WebSocketServer webSocketServer(ChannelServerProperties serverProperties) { WebSocketServer server = new WebSocketServer(); @@ -96,11 +110,13 @@ public class ChannelServerConfiguration { static class StandaloneConfiguration { @Bean + @ConditionalOnMissingBean public AgentManageService agentManageService() { return new AgentManageServiceImpl(); } @Bean + @ConditionalOnMissingBean public MessageExchangeService messageExchangeService() { return new MessageExchangeServiceImpl(); } @@ -111,16 +127,19 @@ public class ChannelServerConfiguration { @Configuration static class RedisConfiguration { @Bean + @ConditionalOnMissingBean public AgentManageService agentManageService() { return new RedisAgentManageServiceImpl(); } @Bean + @ConditionalOnMissingBean public MessageExchangeService messageExchangeService() { return new RedisMessageExchangeServiceImpl(); } @Bean + @ConditionalOnMissingBean public ReactiveRedisTemplate reactiveRedisTemplate(ReactiveRedisConnectionFactory redisConnectionFactory) { ReactiveRedisTemplate template = new ReactiveRedisTemplate (redisConnectionFactory, RedisSerializationContext .newSerializationContext() @@ -133,6 +152,7 @@ public class ChannelServerConfiguration { } @Bean + @ConditionalOnMissingBean public ReactiveStringRedisTemplate reactiveStringRedisTemplate(ReactiveRedisConnectionFactory redisConnectionFactory) { ReactiveStringRedisTemplate template = new ReactiveStringRedisTemplate(redisConnectionFactory); return template; diff --git a/channel/channel-server-starter/src/main/java/com/alibaba/arthas/channel/server/autoconfigure/ChannelServerProperties.java b/channel/channel-server-starter/src/main/java/com/alibaba/arthas/channel/server/autoconfigure/ChannelServerProperties.java new file mode 100644 index 000000000..448858758 --- /dev/null +++ b/channel/channel-server-starter/src/main/java/com/alibaba/arthas/channel/server/autoconfigure/ChannelServerProperties.java @@ -0,0 +1,115 @@ +package com.alibaba.arthas.channel.server.autoconfigure; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties(prefix = "channel.server") +public class ChannelServerProperties { + + private Server websocket = new Server(); + private Server backend = new Server(); + + private Agent agent = new Agent(); + + public Server getWebsocket() { + return websocket; + } + + public void setWebsocket(Server websocket) { + this.websocket = websocket; + } + + public Server getBackend() { + return backend; + } + + public void setBackend(Server backend) { + this.backend = backend; + } + + public Agent getAgent() { + return agent; + } + + public void setAgent(Agent agent) { + this.agent = agent; + } + + public static class Server { + private String host; + private int port; + private boolean ssl; + private boolean enabled; + + public String getHost() { + return host; + } + + public void setHost(String host) { + this.host = host; + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + + public boolean isSsl() { + return ssl; + } + + public void setSsl(boolean ssl) { + this.ssl = ssl; + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + } + + public static class Agent { + private int cleanIntervalMills = 5000; + private int outOfServiceTimeoutMills = 15*1000; + private int downTimeoutMills = 30*1000; + private int removingTimeoutMills = 600*1000; + + public int getCleanIntervalMills() { + return cleanIntervalMills; + } + + public void setCleanIntervalMills(int cleanIntervalMills) { + this.cleanIntervalMills = cleanIntervalMills; + } + + public int getOutOfServiceTimeoutMills() { + return outOfServiceTimeoutMills; + } + + public void setOutOfServiceTimeoutMills(int outOfServiceTimeoutMills) { + this.outOfServiceTimeoutMills = outOfServiceTimeoutMills; + } + + public int getDownTimeoutMills() { + return downTimeoutMills; + } + + public void setDownTimeoutMills(int downTimeoutMills) { + this.downTimeoutMills = downTimeoutMills; + } + + public int getRemovingTimeoutMills() { + return removingTimeoutMills; + } + + public void setRemovingTimeoutMills(int removingTimeoutMills) { + this.removingTimeoutMills = removingTimeoutMills; + } + } + +} diff --git a/channel/channel-server-starter/src/main/resources/MEAT-INF/spring.factories b/channel/channel-server-starter/src/main/resources/MEAT-INF/spring.factories new file mode 100644 index 000000000..8431d887b --- /dev/null +++ b/channel/channel-server-starter/src/main/resources/MEAT-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +com.alibaba.arthas.channel.server.autoconfigure.ChannelServerAutoConfiguration \ No newline at end of file diff --git a/channel/channel-server/pom.xml b/channel/channel-server/pom.xml index d9e05872e..1970773f4 100644 --- a/channel/channel-server/pom.xml +++ b/channel/channel-server/pom.xml @@ -102,20 +102,6 @@ true - - - org.springframework.boot - spring-boot-maven-plugin - 2.1.7.RELEASE - - - package - - repackage - - - - diff --git a/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/conf/ScheduledExecutorConfig.java b/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/conf/ScheduledExecutorConfig.java new file mode 100644 index 000000000..dc7a5a2bd --- /dev/null +++ b/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/conf/ScheduledExecutorConfig.java @@ -0,0 +1,20 @@ +package com.alibaba.arthas.channel.server.conf; + +import java.util.concurrent.ScheduledExecutorService; + +/** + * ScheduledExecutorService config for channel server, avoiding bean injecting conflicts + * @author gongdewei 2020/9/8 + */ +public class ScheduledExecutorConfig { + + private ScheduledExecutorService executorService; + + public ScheduledExecutorService getExecutorService() { + return executorService; + } + + public void setExecutorService(ScheduledExecutorService executorService) { + this.executorService = executorService; + } +} diff --git a/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/configuration/ChannelServerProperties.java b/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/configuration/ChannelServerProperties.java deleted file mode 100644 index 209b500c3..000000000 --- a/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/configuration/ChannelServerProperties.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.alibaba.arthas.channel.server.configuration; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -@ConfigurationProperties(prefix = "channel.server") -public class ChannelServerProperties { - - private Server websocket; - private Server backend; - - public Server getWebsocket() { - return websocket; - } - - public void setWebsocket(Server websocket) { - this.websocket = websocket; - } - - public Server getBackend() { - return backend; - } - - public void setBackend(Server backend) { - this.backend = backend; - } - - public static class Server { - private String host; - private int port; - private boolean ssl; - private boolean enabled = true; - - public String getHost() { - return host; - } - - public void setHost(String host) { - this.host = host; - } - - public int getPort() { - return port; - } - - public void setPort(int port) { - this.port = port; - } - - public boolean isSsl() { - return ssl; - } - - public void setSsl(boolean ssl) { - this.ssl = ssl; - } - - public boolean isEnabled() { - return enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - } - -} diff --git a/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/grpc/ChannelServer.java b/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/grpc/ChannelServer.java index 7abc24fc8..94cac8858 100644 --- a/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/grpc/ChannelServer.java +++ b/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/grpc/ChannelServer.java @@ -1,5 +1,6 @@ package com.alibaba.arthas.channel.server.grpc; +import com.alibaba.arthas.channel.server.conf.ScheduledExecutorConfig; import io.grpc.Server; import io.grpc.ServerBuilder; import org.slf4j.Logger; @@ -20,14 +21,14 @@ public class ChannelServer { private ArthasServiceGrpcImpl arthasServiceGrpc; @Autowired - private ScheduledExecutorService executorService; + private ScheduledExecutorConfig executorServiceConfig; private Server server; private int port = 7700; public void start() throws Exception { - executorService.submit(new Runnable() { + executorServiceConfig.getExecutorService().submit(new Runnable() { @Override public void run() { try { diff --git a/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/message/impl/MessageExchangeServiceImpl.java b/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/message/impl/MessageExchangeServiceImpl.java index 0ac2dccca..455f4ef4b 100644 --- a/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/message/impl/MessageExchangeServiceImpl.java +++ b/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/message/impl/MessageExchangeServiceImpl.java @@ -1,5 +1,6 @@ package com.alibaba.arthas.channel.server.message.impl; +import com.alibaba.arthas.channel.server.conf.ScheduledExecutorConfig; import com.alibaba.arthas.channel.server.message.MessageExchangeException; import com.alibaba.arthas.channel.server.message.MessageExchangeService; import com.alibaba.arthas.channel.server.message.topic.Topic; @@ -14,7 +15,6 @@ import java.util.Map; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; /** @@ -28,7 +28,7 @@ public class MessageExchangeServiceImpl implements MessageExchangeService { private Map topicMap = new ConcurrentHashMap(); @Autowired - private ScheduledExecutorService executorService; + private ScheduledExecutorConfig executorServiceConfig; @Override public void createTopic(Topic topic) throws MessageExchangeException { @@ -108,7 +108,7 @@ public class MessageExchangeServiceImpl implements MessageExchangeService { topicData.setTimeout(timeout); final TopicData finalTopicData = topicData; - executorService.submit(new Runnable() { + executorServiceConfig.getExecutorService().submit(new Runnable() { @Override public void run() { while (true) { diff --git a/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/redis/RedisMessageExchangeServiceImpl.java b/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/redis/RedisMessageExchangeServiceImpl.java index eeee1c4b3..5bf701b73 100644 --- a/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/redis/RedisMessageExchangeServiceImpl.java +++ b/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/redis/RedisMessageExchangeServiceImpl.java @@ -1,5 +1,6 @@ package com.alibaba.arthas.channel.server.redis; +import com.alibaba.arthas.channel.server.conf.ScheduledExecutorConfig; import com.alibaba.arthas.channel.server.message.MessageExchangeException; import com.alibaba.arthas.channel.server.message.MessageExchangeService; import com.alibaba.arthas.channel.server.message.topic.Topic; @@ -13,7 +14,6 @@ import reactor.core.publisher.Mono; import java.time.Duration; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.ScheduledExecutorService; /** * Message exchange for cluster channel server @@ -30,7 +30,7 @@ public class RedisMessageExchangeServiceImpl implements MessageExchangeService { private ReactiveRedisTemplate redisTemplate; @Autowired - private ScheduledExecutorService executorService; + private ScheduledExecutorConfig executorServiceConfig; @Override public void createTopic(Topic topic) throws MessageExchangeException { @@ -82,7 +82,7 @@ public class RedisMessageExchangeServiceImpl implements MessageExchangeService { Mono mono = redisTemplate.opsForList().rightPop(topic.getTopic(), Duration.ofMillis(timeout)); mono.doOnSuccess(messageBytes -> { //schedule running, avoid blocking redis reactive - executorService.submit(() -> { + executorServiceConfig.getExecutorService().submit(() -> { if (messageBytes != null) { boolean next = messageHandler.onMessage(messageBytes); if (next) { @@ -96,7 +96,7 @@ public class RedisMessageExchangeServiceImpl implements MessageExchangeService { } }); }).doOnError(throwable -> { - executorService.submit(() -> { + executorServiceConfig.getExecutorService().submit(() -> { if (throwable instanceof QueryTimeoutException) { //ignore Redis command timed out subscribe(topic, timeout, messageHandler); diff --git a/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/service/AgentBizSerivce.java b/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/service/AgentBizSerivce.java index ded5abdd1..81155c070 100644 --- a/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/service/AgentBizSerivce.java +++ b/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/service/AgentBizSerivce.java @@ -9,7 +9,5 @@ public interface AgentBizSerivce { void heartbeat(String agentId, String agentStatus, String agentVersion); - void cleanOutdatedAgents(); - void compareAndUpdateAgentStatus(String agentId, AgentStatus expectedStatus, AgentStatus newStatus); } diff --git a/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/service/AgentCleaner.java b/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/service/AgentCleaner.java new file mode 100644 index 000000000..21f1e545c --- /dev/null +++ b/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/service/AgentCleaner.java @@ -0,0 +1,124 @@ +package com.alibaba.arthas.channel.server.service; + +import com.alibaba.arthas.channel.proto.AgentStatus; +import com.alibaba.arthas.channel.server.conf.ScheduledExecutorConfig; +import com.alibaba.arthas.channel.server.model.AgentVO; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import reactor.core.publisher.Mono; + +import java.util.List; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +public class AgentCleaner { + + private static final Logger logger = LoggerFactory.getLogger(AgentCleaner.class); + private int removingTimeout = 60000; + private int downTimeout = 30000; + private int outOfServiceTimeout = 15000; + private int cleanIntervalMills = 5000; + + @Autowired + private AgentManageService agentManageService; + private ScheduledExecutorConfig scheduledExecutorConfig; + private ScheduledFuture scheduledFuture; + + public AgentCleaner(ScheduledExecutorConfig scheduledExecutorConfig) { + this.scheduledExecutorConfig = scheduledExecutorConfig; + } + + public void start() { + + if (downTimeout < outOfServiceTimeout) { + throw new IllegalArgumentException(" agent down timeout must not be less than out of service timeout"); + } + + if (removingTimeout > 0 && removingTimeout < downTimeout) { + throw new IllegalArgumentException(" agent removing timeout must not be less than down timeout or -1"); + } + + scheduledFuture = scheduledExecutorConfig.getExecutorService().scheduleWithFixedDelay(new Runnable() { + @Override + public void run() { + doClean(); + } + }, cleanIntervalMills, cleanIntervalMills, TimeUnit.MILLISECONDS); + } + + public void stop() { + if (scheduledFuture != null) { + scheduledFuture.cancel(true); + } + } + + public void doClean() { + long now = System.currentTimeMillis(); + Mono> agentsMono = agentManageService.listAgents(); + agentsMono.doOnSuccess(agents -> { + for (AgentVO agent : agents) { + long heartbeatDelay = now - agent.getHeartbeatTime(); + if (heartbeatDelay > removingTimeout && removingTimeout > 0) { + logger.info("clean up dead agent: {}, heartbeat delay: {}", agent.getAgentId(), heartbeatDelay); + agentManageService.removeAgentById(agent.getAgentId()); + } else if (heartbeatDelay > downTimeout) { + if (!AgentStatus.DOWN.name().equals(agent.getAgentStatus())) { + logger.info("Mark agent status as DOWN, agentId: {}, heartbeat delay: {}", agent.getAgentId(), heartbeatDelay); + agent.setAgentStatus(AgentStatus.DOWN.name()); + agentManageService.updateAgent(agent); + } + } else if (heartbeatDelay > outOfServiceTimeout) { + if (!AgentStatus.OUT_OF_SERVICE.name().equals(agent.getAgentStatus())) { + logger.info("Mark agent status as OUT_OF_SERVICE, agentId: {}, heartbeat delay: {}", agent.getAgentId(), heartbeatDelay); + agent.setAgentStatus(AgentStatus.OUT_OF_SERVICE.name()); + agentManageService.updateAgent(agent); + } + } + } + }).doOnError(throwable -> { + logger.error("clean agent error", throwable); + }).subscribe(); + } + + public int getRemovingTimeout() { + return removingTimeout; + } + + public void setRemovingTimeout(int removingTimeout) { + this.removingTimeout = removingTimeout; + } + + public int getDownTimeout() { + return downTimeout; + } + + public void setDownTimeout(int downTimeout) { + if (downTimeout < 5000) { + throw new IllegalArgumentException("agent down timeout must be not be less than 5000 mills"); + } + this.downTimeout = downTimeout; + } + + public int getOutOfServiceTimeout() { + return outOfServiceTimeout; + } + + public void setOutOfServiceTimeout(int outOfServiceTimeout) { + if (outOfServiceTimeout < 5000) { + throw new IllegalArgumentException("agent out of service timeout must not be less than 5000 mills"); + } + this.outOfServiceTimeout = outOfServiceTimeout; + } + + public int getCleanIntervalMills() { + return cleanIntervalMills; + } + + public void setCleanIntervalMills(int cleanIntervalMills) { + if (cleanIntervalMills < 2000) { + throw new IllegalArgumentException("agent clean interval must not be less than 2000 mills"); + } + this.cleanIntervalMills = cleanIntervalMills; + } +} diff --git a/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/service/impl/AgentBizServiceImpl.java b/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/service/impl/AgentBizServiceImpl.java index cad18d8a9..99c6bb0e5 100644 --- a/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/service/impl/AgentBizServiceImpl.java +++ b/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/service/impl/AgentBizServiceImpl.java @@ -8,7 +8,6 @@ import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.scheduling.annotation.Scheduled; import reactor.core.publisher.Mono; import java.util.List; @@ -43,38 +42,6 @@ public class AgentBizServiceImpl implements AgentBizSerivce { }).subscribe(); } - @Override - @Scheduled(fixedDelayString = "5000") - public void cleanOutdatedAgents() { - long now = System.currentTimeMillis(); - Mono> agentsMono = agentManageService.listAgents(); - agentsMono.doOnSuccess(new Consumer>() { - @Override - public void accept(List agents) { - for (AgentVO agent : agents) { - long heartbeatDelay = now - agent.getHeartbeatTime(); - if (heartbeatDelay > 60000) { - logger.info("clean up dead agent: {}, heartbeat delay: {}", agent.getAgentId(), heartbeatDelay); - agentManageService.removeAgentById(agent.getAgentId()); - } else if (heartbeatDelay > 30000) { - if (!AgentStatus.DOWN.name().equals(agent.getAgentStatus())) { - logger.info("Mark agent status as DOWN, agentId: {}, heartbeat delay: {}", agent.getAgentId(), heartbeatDelay); - agent.setAgentStatus(AgentStatus.DOWN.name()); - agentManageService.updateAgent(agent); - } - } else if (heartbeatDelay > 15000) { - if (!AgentStatus.OUT_OF_SERVICE.name().equals(agent.getAgentStatus())) { - logger.info("Mark agent status as OUT_OF_SERVICE, agentId: {}, heartbeat delay: {}", agent.getAgentId(), heartbeatDelay); - agent.setAgentStatus(AgentStatus.OUT_OF_SERVICE.name()); - agentManageService.updateAgent(agent); - } - } - } - } - }).subscribe(); - - } - @Override public void compareAndUpdateAgentStatus(String agentId, AgentStatus expectedStatus, AgentStatus newStatus) { agentManageService.findAgentById(agentId).flatMap(optionalAgentVO -> { diff --git a/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/web/AgentController.java b/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/web/AgentController.java index fb12b286a..93dccc305 100644 --- a/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/web/AgentController.java +++ b/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/web/AgentController.java @@ -4,6 +4,7 @@ import com.alibaba.arthas.channel.proto.ActionResponse; import com.alibaba.arthas.channel.proto.ExecuteResult; import com.alibaba.arthas.channel.proto.ResponseStatus; import com.alibaba.arthas.channel.server.api.ApiException; +import com.alibaba.arthas.channel.server.conf.ScheduledExecutorConfig; import com.alibaba.arthas.channel.server.model.AgentVO; import com.alibaba.arthas.channel.server.api.ApiRequest; import com.alibaba.arthas.channel.server.api.ApiResponse; @@ -24,7 +25,6 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.server.ResponseStatusException; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import reactor.core.publisher.Mono; @@ -32,7 +32,6 @@ import reactor.core.publisher.Mono; import java.io.IOException; import java.util.List; import java.util.Optional; -import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; /** @@ -50,7 +49,7 @@ public class AgentController { private ApiActionDelegateService apiActionDelegateService; @Autowired - private ScheduledExecutorService executorService; + private ScheduledExecutorConfig executorServiceConfig; @RequestMapping("/agents") @@ -174,7 +173,7 @@ public class AgentController { @RequestBody final String requestBody, @RequestParam(value = "timeout", defaultValue = "300000") final int timeout) { final SseEmitter emitter = new SseEmitter(Long.valueOf(timeout)); - executorService.submit(new Runnable() { + executorServiceConfig.getExecutorService().submit(new Runnable() { public void run() { ApiResponse apiResponse; try { diff --git a/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/ws/WebSocketFrameHandler.java b/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/ws/WebSocketFrameHandler.java index 12541405e..cbb9253c5 100644 --- a/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/ws/WebSocketFrameHandler.java +++ b/channel/channel-server/src/main/java/com/alibaba/arthas/channel/server/ws/WebSocketFrameHandler.java @@ -29,9 +29,7 @@ import java.util.Collections; import java.util.List; import java.util.Optional; -/** - * @author gongdewei 2020/9/2 - */ + public class WebSocketFrameHandler extends SimpleChannelInboundHandler { private static final Logger logger = LoggerFactory.getLogger(WebSocketFrameHandler.class); diff --git a/pom.xml b/pom.xml index c1c4bf3f8..4899c78b5 100644 --- a/pom.xml +++ b/pom.xml @@ -74,6 +74,8 @@ channel/channel-common channel/channel-server channel/channel-client + channel/channel-server-starter + channel/channel-server-app