dashboard: Improve error handling in FlowController and update sample WebConfig
Signed-off-by: Eric Zhao <sczyh16@gmail.com>
This commit is contained in:
parent
0e110c68ea
commit
a5d6773cbc
|
|
@ -365,17 +365,44 @@ public class SentinelApiClient {
|
||||||
params.put("type", type);
|
params.put("type", type);
|
||||||
params.put("data", data);
|
params.put("data", data);
|
||||||
String result = executeCommand(app, ip, port, SET_RULES_PATH, params, true).get();
|
String result = executeCommand(app, ip, port, SET_RULES_PATH, params, true).get();
|
||||||
logger.info("setRules: {}", result);
|
logger.info("setRules result: {}, type={}", result, type);
|
||||||
return true;
|
return true;
|
||||||
} catch (InterruptedException | ExecutionException e) {
|
} catch (InterruptedException e) {
|
||||||
logger.warn("setRules api failed: {}", type, e);
|
logger.warn("setRules API failed: {}", type, e);
|
||||||
|
return false;
|
||||||
|
} catch (ExecutionException e) {
|
||||||
|
logger.warn("setRules API failed: {}", type, e.getCause());
|
||||||
return false;
|
return false;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.warn("setRules failed", e);
|
logger.error("setRules API failed, type={}", type, e);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private CompletableFuture<Void> setRulesAsync(String app, String ip, int port, String type, List<? extends RuleEntity> entities) {
|
||||||
|
try {
|
||||||
|
AssertUtil.notNull(entities, "rules cannot be null");
|
||||||
|
AssertUtil.notEmpty(app, "Bad app name");
|
||||||
|
AssertUtil.notEmpty(ip, "Bad machine IP");
|
||||||
|
AssertUtil.isTrue(port > 0, "Bad machine port");
|
||||||
|
String data = JSON.toJSONString(
|
||||||
|
entities.stream().map(r -> r.toRule()).collect(Collectors.toList()));
|
||||||
|
Map<String, String> params = new HashMap<>(2);
|
||||||
|
params.put("type", type);
|
||||||
|
params.put("data", data);
|
||||||
|
return executeCommand(app, ip, port, SET_RULES_PATH, params, true)
|
||||||
|
.thenCompose(r -> {
|
||||||
|
if ("success".equalsIgnoreCase(r.trim())) {
|
||||||
|
return CompletableFuture.completedFuture(null);
|
||||||
|
}
|
||||||
|
return AsyncUtils.newFailedFuture(new CommandFailedException(r));
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("setRulesAsync API failed, type={}", type, e);
|
||||||
|
return AsyncUtils.newFailedFuture(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public List<NodeVo> fetchResourceOfMachine(String ip, int port, String type) {
|
public List<NodeVo> fetchResourceOfMachine(String ip, int port, String type) {
|
||||||
return fetchItems(ip, port, RESOURCE_URL_PATH, type, NodeVo.class);
|
return fetchItems(ip, port, RESOURCE_URL_PATH, type, NodeVo.class);
|
||||||
}
|
}
|
||||||
|
|
@ -487,6 +514,10 @@ public class SentinelApiClient {
|
||||||
return setRules(app, ip, port, FLOW_RULE_TYPE, rules);
|
return setRules(app, ip, port, FLOW_RULE_TYPE, rules);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<Void> setFlowRuleOfMachineAsync(String app, String ip, int port, List<FlowRuleEntity> rules) {
|
||||||
|
return setRulesAsync(app, ip, port, FLOW_RULE_TYPE, rules);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set rules of the machine. rules == null will return immediately;
|
* set rules of the machine. rules == null will return immediately;
|
||||||
* rules.isEmpty() means setting the rules to empty.
|
* rules.isEmpty() means setting the rules to empty.
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,10 @@
|
||||||
*/
|
*/
|
||||||
package com.alibaba.csp.sentinel.dashboard.config;
|
package com.alibaba.csp.sentinel.dashboard.config;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter;
|
import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter;
|
||||||
import com.alibaba.csp.sentinel.adapter.servlet.callback.WebCallbackManager;
|
import com.alibaba.csp.sentinel.adapter.servlet.callback.WebCallbackManager;
|
||||||
import com.alibaba.csp.sentinel.dashboard.auth.AuthorizationInterceptor;
|
import com.alibaba.csp.sentinel.dashboard.auth.AuthorizationInterceptor;
|
||||||
|
|
@ -75,6 +79,9 @@ public class WebConfig implements WebMvcConfigurer {
|
||||||
registration.addUrlPatterns("/*");
|
registration.addUrlPatterns("/*");
|
||||||
registration.setName("sentinelFilter");
|
registration.setName("sentinelFilter");
|
||||||
registration.setOrder(1);
|
registration.setOrder(1);
|
||||||
|
// If this is enabled, the entrance of all Web URL resources will be unified as a single context name.
|
||||||
|
// In most scenarios that's enough, and it could reduce the memory footprint.
|
||||||
|
registration.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY, "true");
|
||||||
|
|
||||||
logger.info("Sentinel servlet CommonFilter registered");
|
logger.info("Sentinel servlet CommonFilter registered");
|
||||||
|
|
||||||
|
|
@ -83,12 +90,14 @@ public class WebConfig implements WebMvcConfigurer {
|
||||||
|
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
public void doInit() {
|
public void doInit() {
|
||||||
|
Set<String> suffixSet = new HashSet<>(Arrays.asList(".js", ".css", ".html", ".ico", ".txt",
|
||||||
|
".woff", ".woff2"));
|
||||||
// Example: register a UrlCleaner to exclude URLs of common static resources.
|
// Example: register a UrlCleaner to exclude URLs of common static resources.
|
||||||
WebCallbackManager.setUrlCleaner(url -> {
|
WebCallbackManager.setUrlCleaner(url -> {
|
||||||
if (StringUtil.isEmpty(url)) {
|
if (StringUtil.isEmpty(url)) {
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
if (url.endsWith(".js") || url.endsWith(".css") || url.endsWith("html")) {
|
if (suffixSet.stream().anyMatch(url::endsWith)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return url;
|
return url;
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,9 @@ package com.alibaba.csp.sentinel.dashboard.controller;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import com.alibaba.csp.sentinel.dashboard.auth.AuthAction;
|
import com.alibaba.csp.sentinel.dashboard.auth.AuthAction;
|
||||||
import com.alibaba.csp.sentinel.dashboard.auth.AuthService.PrivilegeType;
|
import com.alibaba.csp.sentinel.dashboard.auth.AuthService.PrivilegeType;
|
||||||
|
|
@ -145,19 +148,19 @@ public class FlowControllerV1 {
|
||||||
entity.setResource(entity.getResource().trim());
|
entity.setResource(entity.getResource().trim());
|
||||||
try {
|
try {
|
||||||
entity = repository.save(entity);
|
entity = repository.save(entity);
|
||||||
} catch (Throwable throwable) {
|
|
||||||
logger.error("Failed to add flow rule", throwable);
|
publishRules(entity.getApp(), entity.getIp(), entity.getPort()).get(5000, TimeUnit.MILLISECONDS);
|
||||||
return Result.ofThrowable(-1, throwable);
|
return Result.ofSuccess(entity);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
Throwable e = t instanceof ExecutionException ? t.getCause() : t;
|
||||||
|
logger.error("Failed to add new flow rule, app={}, ip={}", entity.getApp(), entity.getIp(), e);
|
||||||
|
return Result.ofFail(-1, e.getMessage());
|
||||||
}
|
}
|
||||||
if (!publishRules(entity.getApp(), entity.getIp(), entity.getPort())) {
|
|
||||||
logger.error("Publish flow rules failed after rule add");
|
|
||||||
}
|
|
||||||
return Result.ofSuccess(entity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping("/save.json")
|
@PutMapping("/save.json")
|
||||||
@AuthAction(PrivilegeType.WRITE_RULE)
|
@AuthAction(PrivilegeType.WRITE_RULE)
|
||||||
public Result<FlowRuleEntity> updateIfNotNull(Long id, String app,
|
public Result<FlowRuleEntity> apiUpdateFlowRule(Long id, String app,
|
||||||
String limitApp, String resource, Integer grade,
|
String limitApp, String resource, Integer grade,
|
||||||
Double count, Integer strategy, String refResource,
|
Double count, Integer strategy, String refResource,
|
||||||
Integer controlBehavior, Integer warmUpPeriodSec,
|
Integer controlBehavior, Integer warmUpPeriodSec,
|
||||||
|
|
@ -222,21 +225,22 @@ public class FlowControllerV1 {
|
||||||
try {
|
try {
|
||||||
entity = repository.save(entity);
|
entity = repository.save(entity);
|
||||||
if (entity == null) {
|
if (entity == null) {
|
||||||
return Result.ofFail(-1, "save entity fail");
|
return Result.ofFail(-1, "save entity fail: null");
|
||||||
}
|
}
|
||||||
} catch (Throwable throwable) {
|
|
||||||
logger.error("save error:", throwable);
|
publishRules(entity.getApp(), entity.getIp(), entity.getPort()).get(5000, TimeUnit.MILLISECONDS);
|
||||||
return Result.ofThrowable(-1, throwable);
|
return Result.ofSuccess(entity);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
Throwable e = t instanceof ExecutionException ? t.getCause() : t;
|
||||||
|
logger.error("Error when updating flow rules, app={}, ip={}, ruleId={}", entity.getApp(),
|
||||||
|
entity.getIp(), id, e);
|
||||||
|
return Result.ofFail(-1, e.getMessage());
|
||||||
}
|
}
|
||||||
if (!publishRules(entity.getApp(), entity.getIp(), entity.getPort())) {
|
|
||||||
logger.info("publish flow rules fail after rule update");
|
|
||||||
}
|
|
||||||
return Result.ofSuccess(entity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@DeleteMapping("/delete.json")
|
@DeleteMapping("/delete.json")
|
||||||
@AuthAction(PrivilegeType.WRITE_RULE)
|
@AuthAction(PrivilegeType.WRITE_RULE)
|
||||||
public Result<Long> delete(Long id) {
|
public Result<Long> apiDeleteFlowRule(Long id) {
|
||||||
|
|
||||||
if (id == null) {
|
if (id == null) {
|
||||||
return Result.ofFail(-1, "id can't be null");
|
return Result.ofFail(-1, "id can't be null");
|
||||||
|
|
@ -251,14 +255,19 @@ public class FlowControllerV1 {
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return Result.ofFail(-1, e.getMessage());
|
return Result.ofFail(-1, e.getMessage());
|
||||||
}
|
}
|
||||||
if (!publishRules(oldEntity.getApp(), oldEntity.getIp(), oldEntity.getPort())) {
|
try {
|
||||||
logger.info("publish flow rules fail after rule delete");
|
publishRules(oldEntity.getApp(), oldEntity.getIp(), oldEntity.getPort()).get(5000, TimeUnit.MILLISECONDS);
|
||||||
|
return Result.ofSuccess(id);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
Throwable e = t instanceof ExecutionException ? t.getCause() : t;
|
||||||
|
logger.error("Error when deleting flow rules, app={}, ip={}, id={}", oldEntity.getApp(),
|
||||||
|
oldEntity.getIp(), id, e);
|
||||||
|
return Result.ofFail(-1, e.getMessage());
|
||||||
}
|
}
|
||||||
return Result.ofSuccess(id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean publishRules(String app, String ip, Integer port) {
|
private CompletableFuture<Void> publishRules(String app, String ip, Integer port) {
|
||||||
List<FlowRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
|
List<FlowRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
|
||||||
return sentinelApiClient.setFlowRuleOfMachine(app, ip, port, rules);
|
return sentinelApiClient.setFlowRuleOfMachineAsync(app, ip, port, rules);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -148,18 +148,18 @@ app.controller('FlowControllerV1', ['$scope', '$stateParams', 'FlowServiceV1', '
|
||||||
getMachineRules();
|
getMachineRules();
|
||||||
confirmDialog.close();
|
confirmDialog.close();
|
||||||
} else {
|
} else {
|
||||||
alert('失败!');
|
alert('失败:' + data.msg);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function addNewRule(rule) {
|
function addNewRule(rule) {
|
||||||
FlowService.newRule(rule).success(function (data) {
|
FlowService.newRule(rule).success(function (data) {
|
||||||
if (data.code == 0) {
|
if (data.code === 0) {
|
||||||
getMachineRules();
|
getMachineRules();
|
||||||
flowRuleDialog.close();
|
flowRuleDialog.close();
|
||||||
} else {
|
} else {
|
||||||
alert('失败!');
|
alert('失败:' + data.msg);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
@ -173,7 +173,7 @@ app.controller('FlowControllerV1', ['$scope', '$stateParams', 'FlowServiceV1', '
|
||||||
|
|
||||||
function saveRule(rule, edit) {
|
function saveRule(rule, edit) {
|
||||||
FlowService.saveRule(rule).success(function (data) {
|
FlowService.saveRule(rule).success(function (data) {
|
||||||
if (data.code == 0) {
|
if (data.code === 0) {
|
||||||
getMachineRules();
|
getMachineRules();
|
||||||
if (edit) {
|
if (edit) {
|
||||||
flowRuleDialog.close();
|
flowRuleDialog.close();
|
||||||
|
|
@ -181,7 +181,7 @@ app.controller('FlowControllerV1', ['$scope', '$stateParams', 'FlowServiceV1', '
|
||||||
confirmDialog.close();
|
confirmDialog.close();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
alert('失败!');
|
alert('失败:' + data.msg);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,7 @@ app.controller('IdentityCtl', ['$scope', '$stateParams', 'IdentityService',
|
||||||
let url = '/dashboard/flow/' + $scope.app;
|
let url = '/dashboard/flow/' + $scope.app;
|
||||||
$location.path(url);
|
$location.path(url);
|
||||||
} else {
|
} else {
|
||||||
alert('失败!');
|
alert('失败:' + data.msg);
|
||||||
}
|
}
|
||||||
}).error((data, header, config, status) => {
|
}).error((data, header, config, status) => {
|
||||||
alert('未知错误');
|
alert('未知错误');
|
||||||
|
|
@ -110,10 +110,10 @@ app.controller('IdentityCtl', ['$scope', '$stateParams', 'IdentityService',
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
FlowService.newRule(flowRuleDialogScope.currentRule).success(function (data) {
|
FlowService.newRule(flowRuleDialogScope.currentRule).success(function (data) {
|
||||||
if (data.code == 0) {
|
if (data.code === 0) {
|
||||||
flowRuleDialog.close();
|
flowRuleDialog.close();
|
||||||
} else {
|
} else {
|
||||||
alert('失败!');
|
alert('失败:' + data.msg);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -159,12 +159,12 @@ app.controller('IdentityCtl', ['$scope', '$stateParams', 'IdentityService',
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
DegradeService.newRule(degradeRuleDialogScope.currentRule).success(function (data) {
|
DegradeService.newRule(degradeRuleDialogScope.currentRule).success(function (data) {
|
||||||
if (data.code == 0) {
|
if (data.code === 0) {
|
||||||
degradeRuleDialog.close();
|
degradeRuleDialog.close();
|
||||||
var url = '/dashboard/degrade/' + $scope.app;
|
var url = '/dashboard/degrade/' + $scope.app;
|
||||||
$location.path(url);
|
$location.path(url);
|
||||||
} else {
|
} else {
|
||||||
alert('失败!');
|
alert('失败:' + data.msg);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -174,10 +174,10 @@ app.controller('IdentityCtl', ['$scope', '$stateParams', 'IdentityService',
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
DegradeService.newRule(degradeRuleDialogScope.currentRule).success(function (data) {
|
DegradeService.newRule(degradeRuleDialogScope.currentRule).success(function (data) {
|
||||||
if (data.code == 0) {
|
if (data.code === 0) {
|
||||||
degradeRuleDialog.close();
|
degradeRuleDialog.close();
|
||||||
} else {
|
} else {
|
||||||
alert('失败!');
|
alert('失败:' + data.msg);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue