This is an automated email from the ASF dual-hosted git repository.
xcsnx pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git
The following commit(s) were added to refs/heads/master by this push:
new 555f9b456f [type:feat]Change bootstrap heartbeat reporting (#6187)
555f9b456f is described below
commit 555f9b456f1d90dec93d4c60bc6c4a3aa1f54ab7
Author: xchoox <[email protected]>
AuthorDate: Mon Sep 29 15:31:05 2025 +0800
[type:feat]Change bootstrap heartbeat reporting (#6187)
* change
* fix code style
* change Conditional
* fix
---------
Co-authored-by: aias00 <[email protected]>
Co-authored-by: moremind <[email protected]>
---
.../src/main/resources/application.yml | 14 ++--
.../register/client/beat/HeartbeatListener.java | 79 ++++++++++++++++++++--
.../beat/ShenyuBootstrapHeartBeatConfig.java | 56 +++++++++++++++
.../beat/HeartbeatListenerConfiguration.java | 34 +++++++---
4 files changed, 161 insertions(+), 22 deletions(-)
diff --git a/shenyu-bootstrap/src/main/resources/application.yml
b/shenyu-bootstrap/src/main/resources/application.yml
index e1da6a1a5b..1c4006de9e 100644
--- a/shenyu-bootstrap/src/main/resources/application.yml
+++ b/shenyu-bootstrap/src/main/resources/application.yml
@@ -194,12 +194,10 @@ shenyu:
# workerCount: 8
# daemon: true
register:
- enable: true
- registerType: http
- serverLists: http://localhost:9095
+ enabled: false
+ registerType: zookeeper #etcd #consul
+ serverLists: localhost:2181 #http://localhost:2379 #localhost:8848
props:
- username: admin
- password: 123456
cross:
enabled: true
allowedHeaders:
@@ -268,6 +266,12 @@ shenyu:
# url: http://localhost:8500
# waitTime: 10000
# watchDelay: 10000
+ heartbeat:
+ enabled: true
+ serverLists: http://localhost:9095
+ props:
+ username: admin
+ password: 123456
exclude:
enabled: false
paths:
diff --git
a/shenyu-register-center/shenyu-register-client-beat/src/main/java/org/apache/shenyu/register/client/beat/HeartbeatListener.java
b/shenyu-register-center/shenyu-register-client-beat/src/main/java/org/apache/shenyu/register/client/beat/HeartbeatListener.java
index a5db7aad43..36a54e2fcf 100644
---
a/shenyu-register-center/shenyu-register-client-beat/src/main/java/org/apache/shenyu/register/client/beat/HeartbeatListener.java
+++
b/shenyu-register-center/shenyu-register-client-beat/src/main/java/org/apache/shenyu/register/client/beat/HeartbeatListener.java
@@ -17,19 +17,32 @@
package org.apache.shenyu.register.client.beat;
+import com.github.benmanes.caffeine.cache.CacheLoader;
+import com.github.benmanes.caffeine.cache.Caffeine;
+import com.github.benmanes.caffeine.cache.LoadingCache;
+import com.google.common.base.Splitter;
+import com.google.common.collect.Lists;
+import org.apache.commons.lang3.StringUtils;
import org.apache.shenyu.common.concurrent.ShenyuThreadFactory;
import org.apache.shenyu.common.config.ShenyuConfig;
+import org.apache.shenyu.common.constant.Constants;
import org.apache.shenyu.common.constant.InstanceTypeConstants;
+import org.apache.shenyu.common.utils.AesUtils;
+import org.apache.shenyu.common.utils.GsonUtils;
import org.apache.shenyu.common.utils.IpUtils;
import org.apache.shenyu.common.utils.SystemInfoUtils;
-import org.apache.shenyu.register.client.api.ShenyuClientRegisterRepository;
+import org.apache.shenyu.register.client.http.utils.RegisterUtils;
import org.apache.shenyu.register.common.dto.InstanceBeatInfoDTO;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.EventListener;
+import java.util.List;
+import java.util.Optional;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@@ -43,15 +56,49 @@ public class HeartbeatListener {
private ScheduledThreadPoolExecutor executor;
- private final ShenyuClientRegisterRepository httpClientRegisterRepository;
-
private final ShenyuConfig shenyuConfig;
- public HeartbeatListener(final ShenyuClientRegisterRepository
httpClientRegisterRepository, final ShenyuConfig shenyuConfig, final
ServerProperties serverProperties) {
+ private String username;
+
+ private String password;
+
+ private List<String> serverList;
+
+ /**
+ * server -> accessToken.
+ */
+ private LoadingCache<String, String> accessToken;
+
+ private ShenyuBootstrapHeartBeatConfig config;
+
+ public HeartbeatListener(final ShenyuBootstrapHeartBeatConfig config,
final ShenyuConfig shenyuConfig, final ServerProperties serverProperties) {
executor = new ScheduledThreadPoolExecutor(1,
ShenyuThreadFactory.create("scheduled-instance-task", false));
- this.httpClientRegisterRepository = httpClientRegisterRepository;
this.shenyuConfig = shenyuConfig;
LOG.info("Web server initialized on port {}, starting heartbeat
reporter", serverProperties.getPort());
+ this.username = config.getProps().getProperty(Constants.USER_NAME);
+ this.password = config.getProps().getProperty(Constants.PASS_WORD);
+ this.config = config;
+ String secretKey =
config.getProps().getProperty(Constants.AES_SECRET_KEY);
+ String secretIv =
config.getProps().getProperty(Constants.AES_SECRET_IV);
+ if (StringUtils.isNotBlank(secretKey) &&
StringUtils.isNotBlank(secretIv)) {
+ this.password = AesUtils.cbcEncrypt(secretKey, secretIv, password);
+ }
+ this.serverList =
Lists.newArrayList(Splitter.on(",").split(config.getServerLists()));
+ this.accessToken = Caffeine.newBuilder()
+ //see
org.apache.shenyu.admin.config.properties.JwtProperties#expiredSeconds
+ .expireAfterWrite(24L, TimeUnit.HOURS)
+ .build(new CacheLoader<>() {
+ @Override
+ public @Nullable String load(@NonNull final String server)
{
+ try {
+ Optional<?> login =
RegisterUtils.doLogin(username, password, server.concat(Constants.LOGIN_PATH));
+ return login.map(String::valueOf).orElse(null);
+ } catch (Exception e) {
+ LOG.error("Login admin url :{} is fail, will
retry. cause: {} ", server, e.getMessage());
+ return null;
+ }
+ }
+ });
executor.scheduleAtFixedRate(() -> {
InstanceBeatInfoDTO instanceBeatInfoDTO = new
InstanceBeatInfoDTO();
instanceBeatInfoDTO.setInstancePort(String.valueOf(serverProperties.getPort()));
@@ -59,11 +106,31 @@ public class HeartbeatListener {
instanceBeatInfoDTO.setNamespaceId(shenyuConfig.getNamespace());
instanceBeatInfoDTO.setInstanceInfo(SystemInfoUtils.getSystemInfo());
instanceBeatInfoDTO.setInstanceType(InstanceTypeConstants.BOOTSTRAP_INSTANCE_INFO);
- httpClientRegisterRepository.sendHeartbeat(instanceBeatInfoDTO);
+ sendHeartbeat(instanceBeatInfoDTO);
}, INITIAL_DELAY, CHECK_PERIOD, TimeUnit.SECONDS
);
}
+ private void sendHeartbeat(final InstanceBeatInfoDTO instanceBeatInfoDTO) {
+ int i = 0;
+ for (String server : serverList) {
+ i++;
+ String concat = server.concat(Constants.BEAT_URI_PATH);
+ try {
+ String accessToken = this.accessToken.get(server);
+ if (StringUtils.isBlank(accessToken)) {
+ throw new NullPointerException("accessToken is null");
+ }
+
RegisterUtils.doHeartBeat(GsonUtils.getInstance().toJson(instanceBeatInfoDTO),
concat, Constants.HEARTBEAT, accessToken);
+ } catch (Exception e) {
+ LOG.error("HeartBeat admin url :{} is fail, will retry.",
server, e);
+ if (i == serverList.size()) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ }
+
@EventListener(ContextClosedEvent.class)
public void onShutdown() {
executor.shutdown();
diff --git
a/shenyu-register-center/shenyu-register-client-beat/src/main/java/org/apache/shenyu/register/client/beat/ShenyuBootstrapHeartBeatConfig.java
b/shenyu-register-center/shenyu-register-client-beat/src/main/java/org/apache/shenyu/register/client/beat/ShenyuBootstrapHeartBeatConfig.java
new file mode 100644
index 0000000000..84241e2289
--- /dev/null
+++
b/shenyu-register-center/shenyu-register-client-beat/src/main/java/org/apache/shenyu/register/client/beat/ShenyuBootstrapHeartBeatConfig.java
@@ -0,0 +1,56 @@
+/*
+ * 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.apache.shenyu.register.client.beat;
+
+import org.apache.shenyu.register.common.config.PropertiesConfig;
+
+import java.util.Properties;
+
+public class ShenyuBootstrapHeartBeatConfig extends PropertiesConfig {
+
+ private String serverLists;
+
+ public ShenyuBootstrapHeartBeatConfig() {
+
+ }
+
+ public ShenyuBootstrapHeartBeatConfig(
+ final String serverLists,
+ final Properties props) {
+ this.serverLists = serverLists;
+ this.setProps(props);
+ }
+
+ /**
+ * getServerLists.
+ *
+ * @return String
+ */
+ public String getServerLists() {
+ return serverLists;
+ }
+
+ /**
+ * setServerLists.
+ *
+ * @param serverLists serverLists
+ */
+ public void setServerLists(final String serverLists) {
+ this.serverLists = serverLists;
+ }
+}
diff --git
a/shenyu-spring-boot-starter/shenyu-spring-boot-starter-client/shenyu-spring-boot-starter-client-beat/src/main/java/org/apache/shenyu/register/client/beat/HeartbeatListenerConfiguration.java
b/shenyu-spring-boot-starter/shenyu-spring-boot-starter-client/shenyu-spring-boot-starter-client-beat/src/main/java/org/apache/shenyu/register/client/beat/HeartbeatListenerConfiguration.java
index a38d03815d..2fd1a464f3 100644
---
a/shenyu-spring-boot-starter/shenyu-spring-boot-starter-client/shenyu-spring-boot-starter-client-beat/src/main/java/org/apache/shenyu/register/client/beat/HeartbeatListenerConfiguration.java
+++
b/shenyu-spring-boot-starter/shenyu-spring-boot-starter-client/shenyu-spring-boot-starter-client-beat/src/main/java/org/apache/shenyu/register/client/beat/HeartbeatListenerConfiguration.java
@@ -18,32 +18,44 @@
package org.apache.shenyu.register.client.beat;
import org.apache.shenyu.common.config.ShenyuConfig;
-import org.apache.shenyu.register.client.api.ShenyuClientRegisterRepository;
-import
org.apache.shenyu.springboot.starter.client.common.config.ShenyuClientCommonBeanConfiguration;
-import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import
org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.web.ServerProperties;
+import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
-@ImportAutoConfiguration(ShenyuClientCommonBeanConfiguration.class)
-@ConditionalOnProperty(value = "shenyu.register.enabled", matchIfMissing =
true, havingValue = "true")
+@ConditionalOnExpression(
+ "${shenyu.heartbeat.enabled:true} and "
+ + "'${shenyu.sync.websocket.urls:}'.isEmpty() and "
+ + "'${shenyu.sync.http.url:}'.isEmpty()"
+)
public class HeartbeatListenerConfiguration {
/**
* Heartbeat bean listener.
*
- * @param httpClientRegisterRepository the http client register repository
- * @param shenyuConfig the shenyu config
- * @param serverProperties the server properties
+ * @param shenyuBootstrapHeartBeatConfig the shenyuBootstrapHeartBeatConfig
+ * @param shenyuConfig the shenyu config
+ * @param serverProperties the server properties
* @return the heartbeat bean listener.
*/
@Bean
- public HeartbeatListener heartbeatListener(final
ShenyuClientRegisterRepository httpClientRegisterRepository,
+ public HeartbeatListener heartbeatListener(final
ShenyuBootstrapHeartBeatConfig shenyuBootstrapHeartBeatConfig,
final ShenyuConfig shenyuConfig,
final ServerProperties
serverProperties) {
- return new HeartbeatListener(httpClientRegisterRepository,
shenyuConfig, serverProperties);
+ return new HeartbeatListener(shenyuBootstrapHeartBeatConfig,
shenyuConfig, serverProperties);
+ }
+
+ /**
+ * ShenyuBootstrapHeartBeatConfig.
+ *
+ * @return the shenyuBootstrapHeartBeatConfig.
+ */
+ @Bean
+ @ConfigurationProperties(prefix = "shenyu.heartbeat")
+ public ShenyuBootstrapHeartBeatConfig shenyuBootstrapHeartBeatConfig() {
+ return new ShenyuBootstrapHeartBeatConfig();
}
}