Signed-off-by: Eric Zhao <sczyh16@gmail.com>master
@@ -49,8 +49,9 @@ Sentinel 提供了多种规则来保护系统的不同部分。流量控制规 | |||||
## 3. 配置项 | ## 3. 配置项 | ||||
控制台的一些特性可以通过配置项来进行配置,配置项主要有两个来源:`System.getProperty()`和`System.getenv()`,同时存在时后者可以覆盖前者。 | |||||
> 环境变量因为不支持`.`所以需要将其更换为`_`。 | |||||
控制台的一些特性可以通过配置项来进行配置,配置项主要有两个来源:`System.getProperty()` 和 `System.getenv()`,同时存在时后者可以覆盖前者。 | |||||
> 通过环境变量进行配置时,因为不支持 `.` 所以需要将其更换为 `_`。 | |||||
项 | 类型 | 默认值 | 最小值 | 描述 | 项 | 类型 | 默认值 | 最小值 | 描述 | ||||
--- | --- | --- | --- | --- | --- | --- | --- | --- | --- | ||||
@@ -61,15 +62,20 @@ sentinel.dashboard.autoRemoveMachineMillis | Integer | 0 | 300000 | 距离最近 | |||||
配置示例: | 配置示例: | ||||
命令行 | |||||
- 命令行方式: | |||||
```shell | ```shell | ||||
java -Dsentinel.dashboard.app.hideAppNoMachineMillis=60000 | java -Dsentinel.dashboard.app.hideAppNoMachineMillis=60000 | ||||
``` | ``` | ||||
java | |||||
- Java 方式: | |||||
```java | ```java | ||||
System.setProperty("sentinel.dashboard.app.hideAppNoMachineMillis", "60000"); | System.setProperty("sentinel.dashboard.app.hideAppNoMachineMillis", "60000"); | ||||
``` | ``` | ||||
环境变量 | |||||
- 环境变量方式: | |||||
```shell | ```shell | ||||
sentinel_dashboard_app_hideAppNoMachineMillis=60000 | sentinel_dashboard_app_hideAppNoMachineMillis=60000 | ||||
``` | ``` | ||||
@@ -77,5 +83,4 @@ sentinel_dashboard_app_hideAppNoMachineMillis=60000 | |||||
更多: | 更多: | ||||
- [Sentinel 控制台启动和客户端接入](./README.md) | - [Sentinel 控制台启动和客户端接入](./README.md) | ||||
- [控制台 Wiki](https://github.com/alibaba/Sentinel/wiki/%E6%8E%A7%E5%88%B6%E5%8F%B0) | |||||
- [控制台 Wiki](https://github.com/alibaba/Sentinel/wiki/%E6%8E%A7%E5%88%B6%E5%8F%B0) |
@@ -16,7 +16,6 @@ | |||||
<maven.compiler.source>1.8</maven.compiler.source> | <maven.compiler.source>1.8</maven.compiler.source> | ||||
<maven.compiler.target>1.8</maven.compiler.target> | <maven.compiler.target>1.8</maven.compiler.target> | ||||
<spring.boot.version>2.0.5.RELEASE</spring.boot.version> | <spring.boot.version>2.0.5.RELEASE</spring.boot.version> | ||||
<apollo.openapi.version>1.2.0</apollo.openapi.version> | |||||
</properties> | </properties> | ||||
<dependencies> | <dependencies> | ||||
@@ -39,12 +38,6 @@ | |||||
<version>${project.version}</version> | <version>${project.version}</version> | ||||
</dependency> | </dependency> | ||||
<dependency> | |||||
<groupId>com.alibaba.csp</groupId> | |||||
<artifactId>sentinel-datasource-nacos</artifactId> | |||||
<scope>test</scope> | |||||
</dependency> | |||||
<dependency> | <dependency> | ||||
<groupId>org.springframework.boot</groupId> | <groupId>org.springframework.boot</groupId> | ||||
<artifactId>spring-boot-starter-web</artifactId> | <artifactId>spring-boot-starter-web</artifactId> | ||||
@@ -99,6 +92,20 @@ | |||||
<artifactId>fastjson</artifactId> | <artifactId>fastjson</artifactId> | ||||
</dependency> | </dependency> | ||||
<!-- for Nacos rule publisher sample --> | |||||
<dependency> | |||||
<groupId>com.alibaba.csp</groupId> | |||||
<artifactId>sentinel-datasource-nacos</artifactId> | |||||
<scope>test</scope> | |||||
</dependency> | |||||
<!-- for Apollo rule publisher sample --> | |||||
<dependency> | |||||
<groupId>com.ctrip.framework.apollo</groupId> | |||||
<artifactId>apollo-openapi</artifactId> | |||||
<version>1.2.0</version> | |||||
<scope>test</scope> | |||||
</dependency> | |||||
<dependency> | <dependency> | ||||
<groupId>junit</groupId> | <groupId>junit</groupId> | ||||
<artifactId>junit</artifactId> | <artifactId>junit</artifactId> | ||||
@@ -109,13 +116,6 @@ | |||||
<artifactId>mockito-core</artifactId> | <artifactId>mockito-core</artifactId> | ||||
<scope>test</scope> | <scope>test</scope> | ||||
</dependency> | </dependency> | ||||
<!-- https://mvnrepository.com/artifact/com.ctrip.framework.apollo/apollo-openapi --> | |||||
<dependency> | |||||
<groupId>com.ctrip.framework.apollo</groupId> | |||||
<artifactId>apollo-openapi</artifactId> | |||||
<version>${apollo.openapi.version}</version> | |||||
<scope>test</scope> | |||||
</dependency> | |||||
<dependency> | <dependency> | ||||
<groupId>com.github.stefanbirkner</groupId> | <groupId>com.github.stefanbirkner</groupId> | ||||
<artifactId>system-rules</artifactId> | <artifactId>system-rules</artifactId> | ||||
@@ -34,22 +34,26 @@ import org.springframework.lang.NonNull; | |||||
* | * | ||||
*/ | */ | ||||
public class DashboardConfig { | public class DashboardConfig { | ||||
public static final int DEFAULT_MACHINE_HEALTHY_TIMEOUT_MS = 60_000; | |||||
/** | /** | ||||
* hide app in sidebar when it had no healthy machine after specific period in millis | |||||
* Hide application name in sidebar when it has no healthy machines after specific period in millisecond. | |||||
*/ | */ | ||||
public static final String CONFIG_HIDE_APP_NO_MACHINE_MILLIS = "sentinel.dashboard.app.hideAppNoMachineMillis"; | public static final String CONFIG_HIDE_APP_NO_MACHINE_MILLIS = "sentinel.dashboard.app.hideAppNoMachineMillis"; | ||||
/** | /** | ||||
* remove app when it had no healthy machine after specific period in millis | |||||
* Remove application when it has no healthy machines after specific period in millisecond. | |||||
*/ | */ | ||||
public static final String CONFIG_REMOVE_APP_NO_MACHINE_MILLIS = "sentinel.dashboard.removeAppNoMachineMillis"; | public static final String CONFIG_REMOVE_APP_NO_MACHINE_MILLIS = "sentinel.dashboard.removeAppNoMachineMillis"; | ||||
/** | /** | ||||
* unhealthy millis | |||||
* Timeout | |||||
*/ | */ | ||||
public static final String CONFIG_UNHEALTHY_MACHINE_MILLIS = "sentinel.dashboard.unhealthyMachineMillis"; | public static final String CONFIG_UNHEALTHY_MACHINE_MILLIS = "sentinel.dashboard.unhealthyMachineMillis"; | ||||
/** | /** | ||||
* auto remove unhealthy machine after specific period in millis | |||||
* Auto remove unhealthy machine after specific period in millisecond. | |||||
*/ | */ | ||||
public static final String CONFIG_AUTO_REMOVE_MACHINE_MILLIS = "sentinel.dashboard.autoRemoveMachineMillis"; | public static final String CONFIG_AUTO_REMOVE_MACHINE_MILLIS = "sentinel.dashboard.autoRemoveMachineMillis"; | ||||
private static final ConcurrentMap<String, Object> cacheMap = new ConcurrentHashMap<>(); | private static final ConcurrentMap<String, Object> cacheMap = new ConcurrentHashMap<>(); | ||||
@NonNull | @NonNull | ||||
@@ -94,7 +98,7 @@ public class DashboardConfig { | |||||
} | } | ||||
public static int getUnhealthyMachineMillis() { | public static int getUnhealthyMachineMillis() { | ||||
return getConfigInt(CONFIG_UNHEALTHY_MACHINE_MILLIS, 60000, 30000); | |||||
return getConfigInt(CONFIG_UNHEALTHY_MACHINE_MILLIS, DEFAULT_MACHINE_HEALTHY_TIMEOUT_MS, 30000); | |||||
} | } | ||||
public static void clearCache() { | public static void clearCache() { | ||||
@@ -28,40 +28,36 @@ import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo; | |||||
import com.alibaba.csp.sentinel.dashboard.domain.Result; | import com.alibaba.csp.sentinel.dashboard.domain.Result; | ||||
import com.alibaba.csp.sentinel.dashboard.domain.vo.MachineInfoVo; | import com.alibaba.csp.sentinel.dashboard.domain.vo.MachineInfoVo; | ||||
import org.springframework.beans.factory.annotation.Autowired; | import org.springframework.beans.factory.annotation.Autowired; | ||||
import org.springframework.http.MediaType; | |||||
import org.springframework.stereotype.Controller; | |||||
import org.springframework.web.bind.annotation.GetMapping; | |||||
import org.springframework.web.bind.annotation.PathVariable; | import org.springframework.web.bind.annotation.PathVariable; | ||||
import org.springframework.web.bind.annotation.RequestMapping; | import org.springframework.web.bind.annotation.RequestMapping; | ||||
import org.springframework.web.bind.annotation.RequestParam; | import org.springframework.web.bind.annotation.RequestParam; | ||||
import org.springframework.web.bind.annotation.ResponseBody; | |||||
import org.springframework.web.bind.annotation.RestController; | |||||
/** | /** | ||||
* 这个Controller负责app,机器信息的交互. | |||||
* @author Carpenter Lee | |||||
*/ | */ | ||||
@Controller | |||||
@RequestMapping(value = "/app", produces = MediaType.APPLICATION_JSON_VALUE) | |||||
@RestController | |||||
@RequestMapping(value = "/app") | |||||
public class AppController { | public class AppController { | ||||
@Autowired | @Autowired | ||||
AppManagement appManagement; | |||||
private AppManagement appManagement; | |||||
@ResponseBody | |||||
@RequestMapping("/names.json") | |||||
Result<List<String>> queryApps(HttpServletRequest request) { | |||||
@GetMapping("/names.json") | |||||
public Result<List<String>> queryApps(HttpServletRequest request) { | |||||
return Result.ofSuccess(appManagement.getAppNames()); | return Result.ofSuccess(appManagement.getAppNames()); | ||||
} | } | ||||
@ResponseBody | |||||
@RequestMapping("/briefinfos.json") | |||||
Result<List<AppInfo>> queryAppInfos(HttpServletRequest request) { | |||||
@GetMapping("/briefinfos.json") | |||||
public Result<List<AppInfo>> queryAppInfos(HttpServletRequest request) { | |||||
List<AppInfo> list = new ArrayList<>(appManagement.getBriefApps()); | List<AppInfo> list = new ArrayList<>(appManagement.getBriefApps()); | ||||
Collections.sort(list, Comparator.comparing(AppInfo::getApp)); | Collections.sort(list, Comparator.comparing(AppInfo::getApp)); | ||||
return Result.ofSuccess(list); | return Result.ofSuccess(list); | ||||
} | } | ||||
@ResponseBody | |||||
@RequestMapping(value = "/{app}/machines.json") | |||||
Result<List<MachineInfoVo>> getMachinesByApp(@PathVariable("app") String app) { | |||||
@GetMapping(value = "/{app}/machines.json") | |||||
public Result<List<MachineInfoVo>> getMachinesByApp(@PathVariable("app") String app) { | |||||
AppInfo appInfo = appManagement.getDetailApp(app); | AppInfo appInfo = appManagement.getDetailApp(app); | ||||
if (appInfo == null) { | if (appInfo == null) { | ||||
return Result.ofSuccess(null); | return Result.ofSuccess(null); | ||||
@@ -81,9 +77,8 @@ public class AppController { | |||||
return Result.ofSuccess(MachineInfoVo.fromMachineInfoList(list)); | return Result.ofSuccess(MachineInfoVo.fromMachineInfoList(list)); | ||||
} | } | ||||
@ResponseBody | |||||
@RequestMapping(value = "/{app}/machine/remove.json") | |||||
Result<String> removeMachineById( | |||||
@GetMapping(value = "/{app}/machine/remove.json") | |||||
public Result<String> removeMachineById( | |||||
@PathVariable("app") String app, | @PathVariable("app") String app, | ||||
@RequestParam(name = "ip") String ip, | @RequestParam(name = "ip") String ip, | ||||
@RequestParam(name = "port") int port) { | @RequestParam(name = "port") int port) { | ||||
@@ -63,7 +63,7 @@ public class MachineRegistryController { | |||||
machineInfo.setIp(ip); | machineInfo.setIp(ip); | ||||
machineInfo.setPort(port); | machineInfo.setPort(port); | ||||
machineInfo.setHeartbeatVersion(version); | machineInfo.setHeartbeatVersion(version); | ||||
machineInfo.setLastHeatbeat(System.currentTimeMillis()); | |||||
machineInfo.setLastHeartbeat(System.currentTimeMillis()); | |||||
machineInfo.setVersion(sentinelVersion); | machineInfo.setVersion(sentinelVersion); | ||||
appManagement.addMachine(machineInfo); | appManagement.addMachine(machineInfo); | ||||
return Result.ofSuccessMsg("success"); | return Result.ofSuccessMsg("success"); | ||||
@@ -25,24 +25,25 @@ import com.alibaba.csp.sentinel.dashboard.domain.ResourceTreeNode; | |||||
import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient; | import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient; | ||||
import com.alibaba.csp.sentinel.dashboard.domain.Result; | import com.alibaba.csp.sentinel.dashboard.domain.Result; | ||||
import com.alibaba.csp.sentinel.dashboard.domain.vo.ResourceVo; | import com.alibaba.csp.sentinel.dashboard.domain.vo.ResourceVo; | ||||
import org.slf4j.Logger; | import org.slf4j.Logger; | ||||
import org.slf4j.LoggerFactory; | import org.slf4j.LoggerFactory; | ||||
import org.springframework.beans.factory.annotation.Autowired; | import org.springframework.beans.factory.annotation.Autowired; | ||||
import org.springframework.http.MediaType; | |||||
import org.springframework.stereotype.Controller; | |||||
import org.springframework.web.bind.annotation.GetMapping; | |||||
import org.springframework.web.bind.annotation.RequestMapping; | import org.springframework.web.bind.annotation.RequestMapping; | ||||
import org.springframework.web.bind.annotation.ResponseBody; | |||||
import org.springframework.web.bind.annotation.RestController; | |||||
/** | /** | ||||
* @author leyou | |||||
* @author Carpenter Lee | |||||
*/ | */ | ||||
@Controller | |||||
@RequestMapping(value = "/resource", produces = MediaType.APPLICATION_JSON_VALUE) | |||||
@RestController | |||||
@RequestMapping(value = "/resource") | |||||
public class ResourceController { | public class ResourceController { | ||||
private static Logger logger = LoggerFactory.getLogger(ResourceController.class); | private static Logger logger = LoggerFactory.getLogger(ResourceController.class); | ||||
@Autowired | @Autowired | ||||
SentinelApiClient httpFetcher; | |||||
private SentinelApiClient httpFetcher; | |||||
/** | /** | ||||
* Fetch real time statistics info of the machine. | * Fetch real time statistics info of the machine. | ||||
@@ -54,9 +55,9 @@ public class ResourceController { | |||||
* @param searchKey key to search | * @param searchKey key to search | ||||
* @return node statistics info. | * @return node statistics info. | ||||
*/ | */ | ||||
@ResponseBody | |||||
@RequestMapping("/machineResource.json") | |||||
Result<?> fetchIdentityOfMachine(String ip, Integer port, String type, String searchKey) { | |||||
@GetMapping("/machineResource.json") | |||||
public Result<List<ResourceVo>> fetchResourceChainListOfMachine(String ip, Integer port, String type, | |||||
String searchKey) { | |||||
if (StringUtil.isEmpty(ip) || port == null) { | if (StringUtil.isEmpty(ip) || port == null) { | ||||
return Result.ofFail(-1, "invalid param, give ip, port"); | return Result.ofFail(-1, "invalid param, give ip, port"); | ||||
} | } | ||||
@@ -73,7 +74,8 @@ public class ResourceController { | |||||
ResourceTreeNode treeNode = ResourceTreeNode.fromNodeVoList(nodeVos); | ResourceTreeNode treeNode = ResourceTreeNode.fromNodeVoList(nodeVos); | ||||
treeNode.searchIgnoreCase(searchKey); | treeNode.searchIgnoreCase(searchKey); | ||||
return Result.ofSuccess(ResourceVo.fromResourceTreeNode(treeNode)); | return Result.ofSuccess(ResourceVo.fromResourceTreeNode(treeNode)); | ||||
} else {// cluster | |||||
} else { | |||||
// Normal (cluster node). | |||||
List<NodeVo> nodeVos = httpFetcher.fetchClusterNodeOfMachine(ip, port, true); | List<NodeVo> nodeVos = httpFetcher.fetchClusterNodeOfMachine(ip, port, true); | ||||
if (nodeVos == null) { | if (nodeVos == null) { | ||||
return Result.ofSuccess(null); | return Result.ofSuccess(null); | ||||
@@ -23,6 +23,7 @@ import com.alibaba.csp.sentinel.dashboard.discovery.AppInfo; | |||||
* @author leyou | * @author leyou | ||||
*/ | */ | ||||
public class ApplicationEntity { | public class ApplicationEntity { | ||||
private Long id; | private Long id; | ||||
private Date gmtCreate; | private Date gmtCreate; | ||||
private Date gmtModified; | private Date gmtModified; | ||||
@@ -79,10 +80,7 @@ public class ApplicationEntity { | |||||
} | } | ||||
public AppInfo toAppInfo() { | public AppInfo toAppInfo() { | ||||
AppInfo appInfo = new AppInfo(); | |||||
appInfo.setApp(app); | |||||
return appInfo; | |||||
return new AppInfo(app); | |||||
} | } | ||||
@Override | @Override | ||||
@@ -103,7 +103,7 @@ public class MachineEntity { | |||||
machineInfo.setHostname(hostname); | machineInfo.setHostname(hostname); | ||||
machineInfo.setIp(ip); | machineInfo.setIp(ip); | ||||
machineInfo.setPort(port); | machineInfo.setPort(port); | ||||
machineInfo.setLastHeatbeat(timestamp.getTime()); | |||||
machineInfo.setLastHeartbeat(timestamp.getTime()); | |||||
machineInfo.setHeartbeatVersion(timestamp.getTime()); | machineInfo.setHeartbeatVersion(timestamp.getTime()); | ||||
return machineInfo; | return machineInfo; | ||||
@@ -25,26 +25,12 @@ import java.util.concurrent.ConcurrentHashMap; | |||||
import com.alibaba.csp.sentinel.dashboard.config.DashboardConfig; | import com.alibaba.csp.sentinel.dashboard.config.DashboardConfig; | ||||
public class AppInfo { | public class AppInfo { | ||||
private static final Comparator<MachineInfo> COMPARATOR_BY_MACHINE_HEARTBEAT_DESC = new Comparator<MachineInfo>() { | |||||
@Override | |||||
public int compare(MachineInfo o1, MachineInfo o2) { | |||||
if (o1.getLastHeatbeat() < o2.getLastHeatbeat()) { | |||||
return -1; | |||||
} | |||||
if (o1.getLastHeatbeat() > o2.getLastHeatbeat()) { | |||||
return 1; | |||||
} | |||||
return 0; | |||||
} | |||||
}; | |||||
private String app = ""; | private String app = ""; | ||||
private Set<MachineInfo> machines = ConcurrentHashMap.newKeySet(); | private Set<MachineInfo> machines = ConcurrentHashMap.newKeySet(); | ||||
public AppInfo() { | |||||
} | |||||
public AppInfo() {} | |||||
public AppInfo(String app) { | public AppInfo(String app) { | ||||
this.app = app; | this.app = app; | ||||
@@ -76,7 +62,7 @@ public class AppInfo { | |||||
machines.remove(machineInfo); | machines.remove(machineInfo); | ||||
return machines.add(machineInfo); | return machines.add(machineInfo); | ||||
} | } | ||||
public synchronized boolean removeMachine(String ip, int port) { | public synchronized boolean removeMachine(String ip, int port) { | ||||
Iterator<MachineInfo> it = machines.iterator(); | Iterator<MachineInfo> it = machines.iterator(); | ||||
while (it.hasNext()) { | while (it.hasNext()) { | ||||
@@ -88,44 +74,45 @@ public class AppInfo { | |||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
public Optional<MachineInfo> getMachine(String ip, int port) { | public Optional<MachineInfo> getMachine(String ip, int port) { | ||||
return machines.stream() | return machines.stream() | ||||
.filter(e -> e.getIp().equals(ip) && e.getPort().equals(port)) | .filter(e -> e.getIp().equals(ip) && e.getPort().equals(port)) | ||||
.findFirst(); | .findFirst(); | ||||
} | } | ||||
private boolean heartbeatJudge(int threshold) { | |||||
private boolean heartbeatJudge(final int threshold) { | |||||
if (machines.size() == 0) { | if (machines.size() == 0) { | ||||
return false; | return false; | ||||
} | } | ||||
if (threshold > 0) { | if (threshold > 0) { | ||||
long healthyCount = machines.stream() | long healthyCount = machines.stream() | ||||
.filter(m -> m.isHealthy()) | |||||
.count(); | |||||
.filter(MachineInfo::isHealthy) | |||||
.count(); | |||||
if (healthyCount == 0) { | if (healthyCount == 0) { | ||||
// no machine | |||||
long recentHeartBeat = machines.stream() | |||||
.max(COMPARATOR_BY_MACHINE_HEARTBEAT_DESC).get().getLastHeatbeat(); | |||||
return System.currentTimeMillis() - recentHeartBeat < threshold; | |||||
// No healthy machines. | |||||
return machines.stream() | |||||
.max(Comparator.comparingLong(MachineInfo::getLastHeartbeat)) | |||||
.map(e -> System.currentTimeMillis() - e.getLastHeartbeat() < threshold) | |||||
.orElse(false); | |||||
} | } | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
/** | /** | ||||
* having no healthy machine and should not be displayed | |||||
* | |||||
* @return | |||||
* Check whether current application has no healthy machines and should not be displayed. | |||||
* | |||||
* @return true if the application should be displayed in the sidebar, otherwise false | |||||
*/ | */ | ||||
public boolean isShown() { | public boolean isShown() { | ||||
return heartbeatJudge(DashboardConfig.getHideAppNoMachineMillis()); | return heartbeatJudge(DashboardConfig.getHideAppNoMachineMillis()); | ||||
} | } | ||||
/** | /** | ||||
* having no healthy machine and should be removed | |||||
* | |||||
* @return | |||||
* Check whether current application has no healthy machines and should be removed. | |||||
* | |||||
* @return true if the application is dead and should be removed, otherwise false | |||||
*/ | */ | ||||
public boolean isDead() { | public boolean isDead() { | ||||
return !heartbeatJudge(DashboardConfig.getRemoveAppNoMachineMillis()); | return !heartbeatJudge(DashboardConfig.getRemoveAppNoMachineMillis()); | ||||
@@ -27,16 +27,10 @@ import org.springframework.stereotype.Component; | |||||
@Component | @Component | ||||
public class AppManagement implements MachineDiscovery { | public class AppManagement implements MachineDiscovery { | ||||
//@Value("${appmanagement.maxnode}") | |||||
//private Integer maxNode; | |||||
// | |||||
//@Value("${discovery.type}") | |||||
//private String type; | |||||
@Autowired | @Autowired | ||||
private ApplicationContext context; | private ApplicationContext context; | ||||
MachineDiscovery machineDiscovery; | |||||
private MachineDiscovery machineDiscovery; | |||||
@PostConstruct | @PostConstruct | ||||
public void init() { | public void init() { | ||||
@@ -27,10 +27,25 @@ public interface MachineDiscovery { | |||||
Set<AppInfo> getBriefApps(); | Set<AppInfo> getBriefApps(); | ||||
AppInfo getDetailApp(String app); | AppInfo getDetailApp(String app); | ||||
/** | |||||
* Remove the given app from the application registry. | |||||
* | |||||
* @param app application name | |||||
* @since 1.5.0 | |||||
*/ | |||||
void removeApp(String app); | void removeApp(String app); | ||||
long addMachine(MachineInfo machineInfo); | long addMachine(MachineInfo machineInfo); | ||||
/** | |||||
* Remove the given machine instance from the application registry. | |||||
* | |||||
* @param app the application name of the machine | |||||
* @param ip machine IP | |||||
* @param port machine port | |||||
* @return true if removed, otherwise false | |||||
* @since 1.5.0 | |||||
*/ | |||||
boolean removeMachine(String app, String ip, int port); | boolean removeMachine(String app, String ip, int port); | ||||
} | } |
@@ -26,7 +26,7 @@ public class MachineInfo implements Comparable<MachineInfo> { | |||||
private String hostname = ""; | private String hostname = ""; | ||||
private String ip = ""; | private String ip = ""; | ||||
private Integer port = -1; | private Integer port = -1; | ||||
private long lastHeatbeat; | |||||
private long lastHeartbeat; | |||||
private long heartbeatVersion; | private long heartbeatVersion; | ||||
/** | /** | ||||
@@ -96,7 +96,7 @@ public class MachineInfo implements Comparable<MachineInfo> { | |||||
} | } | ||||
public boolean isHealthy() { | public boolean isHealthy() { | ||||
long delta = System.currentTimeMillis() - lastHeatbeat; | |||||
long delta = System.currentTimeMillis() - lastHeartbeat; | |||||
return delta < DashboardConfig.getUnhealthyMachineMillis(); | return delta < DashboardConfig.getUnhealthyMachineMillis(); | ||||
} | } | ||||
@@ -107,18 +107,18 @@ public class MachineInfo implements Comparable<MachineInfo> { | |||||
*/ | */ | ||||
public boolean isDead() { | public boolean isDead() { | ||||
if (DashboardConfig.getAutoRemoveMachineMillis() > 0) { | if (DashboardConfig.getAutoRemoveMachineMillis() > 0) { | ||||
long delta = System.currentTimeMillis() - lastHeatbeat; | |||||
long delta = System.currentTimeMillis() - lastHeartbeat; | |||||
return delta > DashboardConfig.getAutoRemoveMachineMillis(); | return delta > DashboardConfig.getAutoRemoveMachineMillis(); | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
public long getLastHeatbeat() { | |||||
return lastHeatbeat; | |||||
public long getLastHeartbeat() { | |||||
return lastHeartbeat; | |||||
} | } | ||||
public void setLastHeatbeat(long lastHeatbeat) { | |||||
this.lastHeatbeat = lastHeatbeat; | |||||
public void setLastHeartbeat(long lastHeartbeat) { | |||||
this.lastHeartbeat = lastHeartbeat; | |||||
} | } | ||||
@Override | @Override | ||||
@@ -143,7 +143,7 @@ public class MachineInfo implements Comparable<MachineInfo> { | |||||
.append(", ip='").append(ip).append('\'') | .append(", ip='").append(ip).append('\'') | ||||
.append(", port=").append(port) | .append(", port=").append(port) | ||||
.append(", heartbeatVersion=").append(heartbeatVersion) | .append(", heartbeatVersion=").append(heartbeatVersion) | ||||
.append(", lastHeartbeat=").append(lastHeatbeat) | |||||
.append(", lastHeartbeat=").append(lastHeartbeat) | |||||
.append(", version='").append(version).append('\'') | .append(", version='").append(version).append('\'') | ||||
.append(", healthy=").append(isHealthy()) | .append(", healthy=").append(isHealthy()) | ||||
.append('}').toString(); | .append('}').toString(); | ||||
@@ -20,6 +20,9 @@ import java.util.HashSet; | |||||
import java.util.List; | import java.util.List; | ||||
import java.util.Set; | import java.util.Set; | ||||
import java.util.concurrent.ConcurrentHashMap; | import java.util.concurrent.ConcurrentHashMap; | ||||
import java.util.concurrent.ConcurrentMap; | |||||
import com.alibaba.csp.sentinel.util.AssertUtil; | |||||
import org.springframework.stereotype.Component; | import org.springframework.stereotype.Component; | ||||
@@ -28,17 +31,20 @@ import org.springframework.stereotype.Component; | |||||
*/ | */ | ||||
@Component | @Component | ||||
public class SimpleMachineDiscovery implements MachineDiscovery { | public class SimpleMachineDiscovery implements MachineDiscovery { | ||||
protected ConcurrentHashMap<String, AppInfo> apps = new ConcurrentHashMap<>(); | |||||
private final ConcurrentMap<String, AppInfo> apps = new ConcurrentHashMap<>(); | |||||
@Override | @Override | ||||
public long addMachine(MachineInfo machineInfo) { | public long addMachine(MachineInfo machineInfo) { | ||||
AppInfo appInfo = apps.computeIfAbsent(machineInfo.getApp(), app -> new AppInfo(app)); | |||||
AssertUtil.notNull(machineInfo, "machineInfo cannot be null"); | |||||
AppInfo appInfo = apps.computeIfAbsent(machineInfo.getApp(), AppInfo::new); | |||||
appInfo.addMachine(machineInfo); | appInfo.addMachine(machineInfo); | ||||
return 1; | return 1; | ||||
} | } | ||||
@Override | @Override | ||||
public boolean removeMachine(String app, String ip, int port) { | public boolean removeMachine(String app, String ip, int port) { | ||||
AssertUtil.assertNotBlank(app, "app name cannot be blank"); | |||||
AppInfo appInfo = apps.get(app); | AppInfo appInfo = apps.get(app); | ||||
if (appInfo != null) { | if (appInfo != null) { | ||||
return appInfo.removeMachine(ip, port); | return appInfo.removeMachine(ip, port); | ||||
@@ -53,6 +59,7 @@ public class SimpleMachineDiscovery implements MachineDiscovery { | |||||
@Override | @Override | ||||
public AppInfo getDetailApp(String app) { | public AppInfo getDetailApp(String app) { | ||||
AssertUtil.assertNotBlank(app, "app name cannot be blank"); | |||||
return apps.get(app); | return apps.get(app); | ||||
} | } | ||||
@@ -63,6 +70,7 @@ public class SimpleMachineDiscovery implements MachineDiscovery { | |||||
@Override | @Override | ||||
public void removeApp(String app) { | public void removeApp(String app) { | ||||
AssertUtil.assertNotBlank(app, "app name cannot be blank"); | |||||
apps.remove(app); | apps.remove(app); | ||||
} | } | ||||
@@ -49,7 +49,7 @@ public class MachineInfoVo { | |||||
vo.setHostname(machine.getHostname()); | vo.setHostname(machine.getHostname()); | ||||
vo.setIp(machine.getIp()); | vo.setIp(machine.getIp()); | ||||
vo.setPort(machine.getPort()); | vo.setPort(machine.getPort()); | ||||
vo.setLastHeartbeat(machine.getLastHeatbeat()); | |||||
vo.setLastHeartbeat(machine.getLastHeartbeat()); | |||||
vo.setHeartbeatVersion(machine.getHeartbeatVersion()); | vo.setHeartbeatVersion(machine.getHeartbeatVersion()); | ||||
vo.setVersion(machine.getVersion()); | vo.setVersion(machine.getVersion()); | ||||
vo.setHealthy(machine.isHealthy()); | vo.setHealthy(machine.isHealthy()); | ||||
@@ -47,16 +47,8 @@ public class FlowRuleApiProvider implements DynamicRuleProvider<List<FlowRuleEnt | |||||
} | } | ||||
List<MachineInfo> list = appManagement.getDetailApp(appName).getMachines() | List<MachineInfo> list = appManagement.getDetailApp(appName).getMachines() | ||||
.stream() | .stream() | ||||
.filter(e -> e.isHealthy()) | |||||
.sorted((e1, e2) -> { | |||||
if (e1.getLastHeatbeat() < e2.getLastHeatbeat()) { | |||||
return 1; | |||||
} else if (e1.getLastHeatbeat() > e2.getLastHeatbeat()) { | |||||
return -1; | |||||
} else { | |||||
return 0; | |||||
} | |||||
}).collect(Collectors.toList()); | |||||
.filter(MachineInfo::isHealthy) | |||||
.sorted((e1, e2) -> Long.compare(e2.getLastHeartbeat(), e1.getLastHeartbeat())).collect(Collectors.toList()); | |||||
if (list.isEmpty()) { | if (list.isEmpty()) { | ||||
return new ArrayList<>(); | return new ArrayList<>(); | ||||
} else { | } else { | ||||
@@ -24,6 +24,7 @@ import com.alibaba.csp.sentinel.util.function.Tuple2; | |||||
* @author Eric Zhao | * @author Eric Zhao | ||||
*/ | */ | ||||
public final class MachineUtils { | public final class MachineUtils { | ||||
public static Optional<Integer> parseCommandPort(String machineIp) { | public static Optional<Integer> parseCommandPort(String machineIp) { | ||||
try { | try { | ||||
if (!machineIp.contains("@")) { | if (!machineIp.contains("@")) { | ||||
@@ -53,4 +54,6 @@ public final class MachineUtils { | |||||
return Optional.empty(); | return Optional.empty(); | ||||
} | } | ||||
} | } | ||||
private MachineUtils() {} | |||||
} | } |
@@ -202,7 +202,7 @@ angular.module('sentinelDashboardApp').controller('AuthorityRuleController', ['$ | |||||
$scope.machines = []; | $scope.machines = []; | ||||
$scope.macsInputOptions = []; | $scope.macsInputOptions = []; | ||||
data.data.forEach(function (item) { | data.data.forEach(function (item) { | ||||
if (item.health) { | |||||
if (item.healthy) { | |||||
$scope.macsInputOptions.push({ | $scope.macsInputOptions.push({ | ||||
text: item.ip + ':' + item.port, | text: item.ip + ':' + item.port, | ||||
value: item.ip + ':' + item.port | value: item.ip + ':' + item.port | ||||
@@ -217,7 +217,7 @@ app.controller('SentinelClusterSingleController', ['$scope', '$stateParams', 'ng | |||||
$scope.macsInputOptionsOrigin = []; | $scope.macsInputOptionsOrigin = []; | ||||
$scope.macsInputOptions = []; | $scope.macsInputOptions = []; | ||||
data.data.forEach(function (item) { | data.data.forEach(function (item) { | ||||
if (item.health) { | |||||
if (item.healthy) { | |||||
$scope.macsInputOptionsOrigin.push({ | $scope.macsInputOptionsOrigin.push({ | ||||
text: item.ip + ':' + item.port, | text: item.ip + ':' + item.port, | ||||
value: item.ip + ':' + item.port | value: item.ip + ':' + item.port | ||||
@@ -177,7 +177,7 @@ app.controller('DegradeCtl', ['$scope', '$stateParams', 'DegradeService', 'ngDia | |||||
$scope.machines = []; | $scope.machines = []; | ||||
$scope.macsInputOptions = []; | $scope.macsInputOptions = []; | ||||
data.data.forEach(function (item) { | data.data.forEach(function (item) { | ||||
if (item.health) { | |||||
if (item.healthy) { | |||||
$scope.macsInputOptions.push({ | $scope.macsInputOptions.push({ | ||||
text: item.ip + ':' + item.port, | text: item.ip + ':' + item.port, | ||||
value: item.ip + ':' + item.port | value: item.ip + ':' + item.port | ||||
@@ -195,7 +195,7 @@ app.controller('FlowControllerV1', ['$scope', '$stateParams', 'FlowServiceV1', ' | |||||
$scope.machines = []; | $scope.machines = []; | ||||
$scope.macsInputOptions = []; | $scope.macsInputOptions = []; | ||||
data.data.forEach(function (item) { | data.data.forEach(function (item) { | ||||
if (item.health) { | |||||
if (item.healthy) { | |||||
$scope.macsInputOptions.push({ | $scope.macsInputOptions.push({ | ||||
text: item.ip + ':' + item.port, | text: item.ip + ':' + item.port, | ||||
value: item.ip + ':' + item.port | value: item.ip + ':' + item.port | ||||
@@ -196,7 +196,7 @@ app.controller('FlowControllerV2', ['$scope', '$stateParams', 'FlowServiceV2', ' | |||||
$scope.machines = []; | $scope.machines = []; | ||||
$scope.macsInputOptions = []; | $scope.macsInputOptions = []; | ||||
data.data.forEach(function (item) { | data.data.forEach(function (item) { | ||||
if (item.health) { | |||||
if (item.healthy) { | |||||
$scope.macsInputOptions.push({ | $scope.macsInputOptions.push({ | ||||
text: item.ip + ':' + item.port, | text: item.ip + ':' + item.port, | ||||
value: item.ip + ':' + item.port | value: item.ip + ':' + item.port | ||||
@@ -387,13 +387,12 @@ app.controller('IdentityCtl', ['$scope', '$stateParams', 'IdentityService', | |||||
function queryAppMachines() { | function queryAppMachines() { | ||||
MachineService.getAppMachines($scope.app).success( | MachineService.getAppMachines($scope.app).success( | ||||
function (data) { | function (data) { | ||||
if (data.code == 0) { | |||||
// $scope.machines = data.data; | |||||
if (data.code === 0) { | |||||
if (data.data) { | if (data.data) { | ||||
$scope.machines = []; | $scope.machines = []; | ||||
$scope.macsInputOptions = []; | $scope.macsInputOptions = []; | ||||
data.data.forEach(function (item) { | data.data.forEach(function (item) { | ||||
if (item.health) { | |||||
if (item.healthy) { | |||||
$scope.macsInputOptions.push({ | $scope.macsInputOptions.push({ | ||||
text: item.ip + ':' + item.port, | text: item.ip + ':' + item.port, | ||||
value: item.ip + ':' + item.port | value: item.ip + ':' + item.port | ||||
@@ -294,7 +294,7 @@ angular.module('sentinelDashboardApp').controller('ParamFlowController', ['$scop | |||||
$scope.machines = []; | $scope.machines = []; | ||||
$scope.macsInputOptions = []; | $scope.macsInputOptions = []; | ||||
data.data.forEach(function (item) { | data.data.forEach(function (item) { | ||||
if (item.health) { | |||||
if (item.healthy) { | |||||
$scope.macsInputOptions.push({ | $scope.macsInputOptions.push({ | ||||
text: item.ip + ':' + item.port, | text: item.ip + ':' + item.port, | ||||
value: item.ip + ':' + item.port | value: item.ip + ':' + item.port | ||||
@@ -205,7 +205,7 @@ app.controller('SystemCtl', ['$scope', '$stateParams', 'SystemService', 'ngDialo | |||||
$scope.machines = []; | $scope.machines = []; | ||||
$scope.macsInputOptions = []; | $scope.macsInputOptions = []; | ||||
data.data.forEach(function (item) { | data.data.forEach(function (item) { | ||||
if (item.health) { | |||||
if (item.healthy) { | |||||
$scope.macsInputOptions.push({ | $scope.macsInputOptions.push({ | ||||
text: item.ip + ':' + item.port, | text: item.ip + ':' + item.port, | ||||
value: item.ip + ':' + item.port | value: item.ip + ':' + item.port | ||||
@@ -79,7 +79,7 @@ public class AppInfoTest { | |||||
machineInfo.setHostname("bogon"); | machineInfo.setHostname("bogon"); | ||||
machineInfo.setIp("127.0.0.1"); | machineInfo.setIp("127.0.0.1"); | ||||
machineInfo.setPort(3389); | machineInfo.setPort(3389); | ||||
machineInfo.setLastHeatbeat(System.currentTimeMillis()); | |||||
machineInfo.setLastHeartbeat(System.currentTimeMillis()); | |||||
machineInfo.setHeartbeatVersion(1); | machineInfo.setHeartbeatVersion(1); | ||||
machineInfo.setVersion("0.4.1"); | machineInfo.setVersion("0.4.1"); | ||||
appInfo.addMachine(machineInfo); | appInfo.addMachine(machineInfo); | ||||
@@ -92,7 +92,7 @@ public class AppInfoTest { | |||||
machineInfo.setHostname("bogon"); | machineInfo.setHostname("bogon"); | ||||
machineInfo.setIp("127.0.0.1"); | machineInfo.setIp("127.0.0.1"); | ||||
machineInfo.setPort(3389); | machineInfo.setPort(3389); | ||||
machineInfo.setLastHeatbeat(System.currentTimeMillis()); | |||||
machineInfo.setLastHeartbeat(System.currentTimeMillis()); | |||||
machineInfo.setHeartbeatVersion(1); | machineInfo.setHeartbeatVersion(1); | ||||
machineInfo.setVersion("0.4.2"); | machineInfo.setVersion("0.4.2"); | ||||
appInfo.addMachine(machineInfo); | appInfo.addMachine(machineInfo); | ||||
@@ -105,7 +105,7 @@ public class AppInfoTest { | |||||
machineInfo.setHostname("bogon"); | machineInfo.setHostname("bogon"); | ||||
machineInfo.setIp("127.0.0.1"); | machineInfo.setIp("127.0.0.1"); | ||||
machineInfo.setPort(3390); | machineInfo.setPort(3390); | ||||
machineInfo.setLastHeatbeat(System.currentTimeMillis()); | |||||
machineInfo.setLastHeartbeat(System.currentTimeMillis()); | |||||
machineInfo.setHeartbeatVersion(1); | machineInfo.setHeartbeatVersion(1); | ||||
machineInfo.setVersion("0.4.3"); | machineInfo.setVersion("0.4.3"); | ||||
appInfo.addMachine(machineInfo); | appInfo.addMachine(machineInfo); | ||||
@@ -116,7 +116,7 @@ public class AppInfoTest { | |||||
appInfo.removeMachine("127.0.0.1", 3390); | appInfo.removeMachine("127.0.0.1", 3390); | ||||
assertEquals(0, appInfo.getMachines().size()); | assertEquals(0, appInfo.getMachines().size()); | ||||
} | } | ||||
@Test | @Test | ||||
public void testHealthyAndDead() { | public void testHealthyAndDead() { | ||||
System.setProperty(DashboardConfig.CONFIG_HIDE_APP_NO_MACHINE_MILLIS, "60000"); | System.setProperty(DashboardConfig.CONFIG_HIDE_APP_NO_MACHINE_MILLIS, "60000"); | ||||
@@ -128,25 +128,25 @@ public class AppInfoTest { | |||||
{ | { | ||||
MachineInfo machineInfo = MachineInfo.of(appName, "127.0.0.1", 8801); | MachineInfo machineInfo = MachineInfo.of(appName, "127.0.0.1", 8801); | ||||
machineInfo.setHeartbeatVersion(1); | machineInfo.setHeartbeatVersion(1); | ||||
machineInfo.setLastHeatbeat(System.currentTimeMillis()); | |||||
machineInfo.setLastHeartbeat(System.currentTimeMillis()); | |||||
appInfo.addMachine(machineInfo); | appInfo.addMachine(machineInfo); | ||||
} | } | ||||
assertTrue(appInfo.isShown()); | assertTrue(appInfo.isShown()); | ||||
assertFalse(appInfo.isDead()); | assertFalse(appInfo.isDead()); | ||||
{ | { | ||||
MachineInfo machineInfo = MachineInfo.of(appName, "127.0.0.1", 8801); | MachineInfo machineInfo = MachineInfo.of(appName, "127.0.0.1", 8801); | ||||
machineInfo.setHeartbeatVersion(1); | machineInfo.setHeartbeatVersion(1); | ||||
machineInfo.setLastHeatbeat(System.currentTimeMillis() - 70000); | |||||
machineInfo.setLastHeartbeat(System.currentTimeMillis() - 70000); | |||||
appInfo.addMachine(machineInfo); | appInfo.addMachine(machineInfo); | ||||
} | } | ||||
assertFalse(appInfo.isShown()); | assertFalse(appInfo.isShown()); | ||||
assertFalse(appInfo.isDead()); | assertFalse(appInfo.isDead()); | ||||
{ | { | ||||
MachineInfo machineInfo = MachineInfo.of(appName, "127.0.0.1", 8801); | MachineInfo machineInfo = MachineInfo.of(appName, "127.0.0.1", 8801); | ||||
machineInfo.setHeartbeatVersion(1); | machineInfo.setHeartbeatVersion(1); | ||||
machineInfo.setLastHeatbeat(System.currentTimeMillis() - 700000); | |||||
machineInfo.setLastHeartbeat(System.currentTimeMillis() - 700000); | |||||
appInfo.addMachine(machineInfo); | appInfo.addMachine(machineInfo); | ||||
} | } | ||||
assertFalse(appInfo.isShown()); | assertFalse(appInfo.isShown()); | ||||
@@ -21,7 +21,11 @@ import org.junit.Test; | |||||
import com.alibaba.csp.sentinel.dashboard.config.DashboardConfig; | import com.alibaba.csp.sentinel.dashboard.config.DashboardConfig; | ||||
/** | |||||
* @author Jason Joo | |||||
*/ | |||||
public class MachineInfoTest { | public class MachineInfoTest { | ||||
@Test | @Test | ||||
public void testHealthyAndDead() { | public void testHealthyAndDead() { | ||||
System.setProperty(DashboardConfig.CONFIG_UNHEALTHY_MACHINE_MILLIS, "60000"); | System.setProperty(DashboardConfig.CONFIG_UNHEALTHY_MACHINE_MILLIS, "60000"); | ||||
@@ -29,15 +33,15 @@ public class MachineInfoTest { | |||||
DashboardConfig.clearCache(); | DashboardConfig.clearCache(); | ||||
MachineInfo machineInfo = new MachineInfo(); | MachineInfo machineInfo = new MachineInfo(); | ||||
machineInfo.setHeartbeatVersion(1); | machineInfo.setHeartbeatVersion(1); | ||||
machineInfo.setLastHeatbeat(System.currentTimeMillis() - 10000); | |||||
machineInfo.setLastHeartbeat(System.currentTimeMillis() - 10000); | |||||
assertTrue(machineInfo.isHealthy()); | assertTrue(machineInfo.isHealthy()); | ||||
assertFalse(machineInfo.isDead()); | assertFalse(machineInfo.isDead()); | ||||
machineInfo.setLastHeatbeat(System.currentTimeMillis() - 100000); | |||||
machineInfo.setLastHeartbeat(System.currentTimeMillis() - 100000); | |||||
assertFalse(machineInfo.isHealthy()); | assertFalse(machineInfo.isHealthy()); | ||||
assertFalse(machineInfo.isDead()); | assertFalse(machineInfo.isDead()); | ||||
machineInfo.setLastHeatbeat(System.currentTimeMillis() - 1000000); | |||||
machineInfo.setLastHeartbeat(System.currentTimeMillis() - 1000000); | |||||
assertFalse(machineInfo.isHealthy()); | assertFalse(machineInfo.isHealthy()); | ||||
assertTrue(machineInfo.isDead()); | assertTrue(machineInfo.isDead()); | ||||
} | } | ||||
@@ -119,13 +119,11 @@ public class InMemoryMetricsRepositoryTest { | |||||
try { | try { | ||||
cyclicBarrier.await(); | cyclicBarrier.await(); | ||||
inMemoryMetricsRepository.listResourcesOfApp(DEFAULT_APP); | inMemoryMetricsRepository.listResourcesOfApp(DEFAULT_APP); | ||||
} catch (InterruptedException e) { | |||||
e.printStackTrace(); | |||||
} catch (BrokenBarrierException e) { | |||||
} catch (InterruptedException | BrokenBarrierException e) { | |||||
e.printStackTrace(); | e.printStackTrace(); | ||||
} | } | ||||
}, executorService | |||||
)); | |||||
}, executorService) | |||||
); | |||||
} | } | ||||
// batch add metric entity | // batch add metric entity | ||||
@@ -142,11 +140,20 @@ public class InMemoryMetricsRepositoryTest { | |||||
} | } | ||||
CompletableFuture all = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])); | CompletableFuture all = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])); | ||||
try { | try { | ||||
all.join(); | |||||
} catch (ConcurrentModificationException e) { | |||||
all.get(10, TimeUnit.SECONDS); | |||||
} catch (InterruptedException e) { | |||||
e.printStackTrace(); | e.printStackTrace(); | ||||
fail("concurrent error occurred"); | |||||
} catch (ExecutionException e) { | |||||
e.getCause().printStackTrace(); | |||||
if (e.getCause() instanceof ConcurrentModificationException) { | |||||
fail("concurrent error occurred"); | |||||
} else { | |||||
fail("unexpected exception"); | |||||
} | |||||
} catch (TimeoutException e) { | |||||
fail("allOf future timeout"); | |||||
} | } | ||||
} | } | ||||
@@ -19,11 +19,11 @@ import java.util.List; | |||||
import org.springframework.context.annotation.Bean; | import org.springframework.context.annotation.Bean; | ||||
import org.springframework.context.annotation.Configuration; | import org.springframework.context.annotation.Configuration; | ||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity; | import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity; | ||||
import com.alibaba.csp.sentinel.datasource.Converter; | import com.alibaba.csp.sentinel.datasource.Converter; | ||||
import com.alibaba.fastjson.JSON; | import com.alibaba.fastjson.JSON; | ||||
import com.alibaba.nacos.api.config.ConfigFactory; | |||||
import com.alibaba.nacos.api.config.ConfigService; | |||||
import com.ctrip.framework.apollo.openapi.client.ApolloOpenApiClient; | import com.ctrip.framework.apollo.openapi.client.ApolloOpenApiClient; | ||||
/** | /** | ||||
@@ -44,11 +44,11 @@ public class ApolloConfig { | |||||
} | } | ||||
@Bean | @Bean | ||||
public ApolloOpenApiClient apolloOpenApiClient(){ | |||||
public ApolloOpenApiClient apolloOpenApiClient() { | |||||
ApolloOpenApiClient client = ApolloOpenApiClient.newBuilder() | ApolloOpenApiClient client = ApolloOpenApiClient.newBuilder() | ||||
.withPortalUrl("http://localhost:10034") | |||||
.withToken("token") | |||||
.build(); | |||||
.withPortalUrl("http://localhost:10034") | |||||
.withToken("token") | |||||
.build(); | |||||
return client; | return client; | ||||
} | } | ||||
@@ -20,10 +20,12 @@ import java.util.List; | |||||
import org.springframework.beans.factory.annotation.Autowired; | import org.springframework.beans.factory.annotation.Autowired; | ||||
import org.springframework.stereotype.Component; | import org.springframework.stereotype.Component; | ||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity; | import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity; | ||||
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider; | import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider; | ||||
import com.alibaba.csp.sentinel.datasource.Converter; | import com.alibaba.csp.sentinel.datasource.Converter; | ||||
import com.alibaba.csp.sentinel.util.StringUtil; | import com.alibaba.csp.sentinel.util.StringUtil; | ||||
import com.ctrip.framework.apollo.openapi.client.ApolloOpenApiClient; | import com.ctrip.framework.apollo.openapi.client.ApolloOpenApiClient; | ||||
import com.ctrip.framework.apollo.openapi.dto.OpenItemDTO; | import com.ctrip.framework.apollo.openapi.dto.OpenItemDTO; | ||||
import com.ctrip.framework.apollo.openapi.dto.OpenNamespaceDTO; | import com.ctrip.framework.apollo.openapi.dto.OpenNamespaceDTO; | ||||
@@ -46,17 +48,16 @@ public class FlowRuleApolloProvider implements DynamicRuleProvider<List<FlowRule | |||||
String flowDataId = ApolloConfigUtil.getFlowDataId(appName); | String flowDataId = ApolloConfigUtil.getFlowDataId(appName); | ||||
OpenNamespaceDTO openNamespaceDTO = apolloOpenApiClient.getNamespace(appId, "DEV", "default", "application"); | OpenNamespaceDTO openNamespaceDTO = apolloOpenApiClient.getNamespace(appId, "DEV", "default", "application"); | ||||
String rules = openNamespaceDTO | String rules = openNamespaceDTO | ||||
.getItems() | |||||
.stream() | |||||
.filter(p -> p.getKey().equals(flowDataId)) | |||||
.map(OpenItemDTO::getValue) | |||||
.findFirst() | |||||
.orElse(""); | |||||
.getItems() | |||||
.stream() | |||||
.filter(p -> p.getKey().equals(flowDataId)) | |||||
.map(OpenItemDTO::getValue) | |||||
.findFirst() | |||||
.orElse(""); | |||||
if (StringUtil.isEmpty(rules)) { | if (StringUtil.isEmpty(rules)) { | ||||
return new ArrayList<>(); | return new ArrayList<>(); | ||||
} | } | ||||
return converter.convert(rules); | return converter.convert(rules); | ||||
} | } | ||||
} | } |
@@ -19,11 +19,12 @@ import java.util.List; | |||||
import org.springframework.beans.factory.annotation.Autowired; | import org.springframework.beans.factory.annotation.Autowired; | ||||
import org.springframework.stereotype.Component; | import org.springframework.stereotype.Component; | ||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity; | import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity; | ||||
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher; | import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher; | ||||
import com.alibaba.csp.sentinel.datasource.Converter; | import com.alibaba.csp.sentinel.datasource.Converter; | ||||
import com.alibaba.csp.sentinel.util.AssertUtil; | import com.alibaba.csp.sentinel.util.AssertUtil; | ||||
import com.alibaba.nacos.api.config.ConfigService; | |||||
import com.ctrip.framework.apollo.openapi.client.ApolloOpenApiClient; | import com.ctrip.framework.apollo.openapi.client.ApolloOpenApiClient; | ||||
import com.ctrip.framework.apollo.openapi.dto.NamespaceReleaseDTO; | import com.ctrip.framework.apollo.openapi.dto.NamespaceReleaseDTO; | ||||
import com.ctrip.framework.apollo.openapi.dto.OpenItemDTO; | import com.ctrip.framework.apollo.openapi.dto.OpenItemDTO; | ||||
@@ -47,27 +48,22 @@ public class FlowRuleApolloPublisher implements DynamicRulePublisher<List<FlowRu | |||||
return; | return; | ||||
} | } | ||||
/** | |||||
* Increase the configuration | |||||
*/ | |||||
// Increase the configuration | |||||
String appId = "appId"; | String appId = "appId"; | ||||
String flowDataId = ApolloConfigUtil.getFlowDataId(app); | String flowDataId = ApolloConfigUtil.getFlowDataId(app); | ||||
OpenItemDTO openItemDTO = new OpenItemDTO(); | OpenItemDTO openItemDTO = new OpenItemDTO(); | ||||
openItemDTO.setKey(flowDataId); | openItemDTO.setKey(flowDataId); | ||||
openItemDTO.setValue(converter.convert(rules)); | openItemDTO.setValue(converter.convert(rules)); | ||||
openItemDTO.setComment("Program auto-join"); | openItemDTO.setComment("Program auto-join"); | ||||
openItemDTO.setDataChangeCreatedBy("hantianwei"); | |||||
apolloOpenApiClient.createOrUpdateItem(appId,"DEV","default","application",openItemDTO); | |||||
openItemDTO.setDataChangeCreatedBy("some-operator"); | |||||
apolloOpenApiClient.createOrUpdateItem(appId, "DEV", "default", "application", openItemDTO); | |||||
/** | |||||
* Release configuration | |||||
*/ | |||||
// Release configuration | |||||
NamespaceReleaseDTO namespaceReleaseDTO = new NamespaceReleaseDTO(); | NamespaceReleaseDTO namespaceReleaseDTO = new NamespaceReleaseDTO(); | ||||
namespaceReleaseDTO.setEmergencyPublish(true); | namespaceReleaseDTO.setEmergencyPublish(true); | ||||
namespaceReleaseDTO.setReleaseComment("Modify or add configurations"); | namespaceReleaseDTO.setReleaseComment("Modify or add configurations"); | ||||
namespaceReleaseDTO.setReleasedBy("hantianwei"); | |||||
namespaceReleaseDTO.setReleasedBy("some-operator"); | |||||
namespaceReleaseDTO.setReleaseTitle("Modify or add configurations"); | namespaceReleaseDTO.setReleaseTitle("Modify or add configurations"); | ||||
apolloOpenApiClient.publishNamespace(appId,"DEV","default","application",namespaceReleaseDTO); | |||||
apolloOpenApiClient.publishNamespace(appId, "DEV", "default", "application", namespaceReleaseDTO); | |||||
} | } | ||||
} | } |