Sentinel 降级规则规则持久化 push模式 Nacos

上一篇Sentinel 限流规则规则持久化 push模式 Nacos

本文是基于上一篇的基础之后进行,准备工作可参考上一篇

Sentinel下载地址(已修改)

  • 修改NacosConfigUtil.java
    添加代码:
  public static final String DEGRADE_DATA_ID_POSTFIX = "-degrade-rules";
  • 修改NacosConfig.java
    添加代码:
 @Bean
    public Converter<List<DegradeRuleEntity>, String> degradeRuleEntityEncoder() {
        return JSON::toJSONString;
    }

    @Bean
    public Converter<String, List<DegradeRuleEntity>> degradeRuleEntityDecoder() {
        return s -> JSON.parseArray(s, DegradeRuleEntity.class);
    }
  • 添加DegradeRuleNacosProvider.java

在这里插入图片描述
sentinel-dashboard下的**com.alibaba.csp.sentinel.dashboard.rule.nacos新建DegradeRuleNacosProvider.java

package com.alibaba.csp.sentinel.dashboard.rule.nacos;

import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.DegradeRuleEntity;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.nacos.api.config.ConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

/**
 * Sentinel 降级规则 持久化  Push 模式 Nacos
 * @Author jianghx
 * @Date 2021/12/24 11:47
 * @Version 1.0
 **/
@Component("degradeRuleNacosProvider")
public class DegradeRuleNacosProvider implements DynamicRuleProvider<List<DegradeRuleEntity>> {

    @Autowired
    private ConfigService configService;

    @Autowired
    private Converter<String, List<DegradeRuleEntity>> converter;

    @Override
    public List<DegradeRuleEntity> getRules(String appName) throws Exception {
        String rules = configService.getConfig(appName + NacosConfigUtil.DEGRADE_DATA_ID_POSTFIX,
                NacosConfigUtil.GROUP_ID, 3000);
        if (StringUtil.isEmpty(rules)) {
            return new ArrayList<>();
        }
        return converter.convert(rules);
    }
}

  • 新建DegradeRuleNacosPublisher.java
    在这里插入图片描述

在*com.alibaba.csp.sentinel.dashboard.rule.nacos新建DegradeRuleNacosPublisher.java

package com.alibaba.csp.sentinel.dashboard.rule.nacos;

import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.DegradeRuleEntity;
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.DynamicRulePublisher;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.util.AssertUtil;
import com.alibaba.nacos.api.config.ConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * Sentinel 降级规则 持久化  Push 模式 Nacos
 * @Author jianghx
 * @Date 2021/12/24 11:47
 * @Version 1.0
 **/
@Component("degradeRuleNacosPublisher")
public class DegradeRuleNacosPublisher  implements DynamicRulePublisher<List<DegradeRuleEntity>>
{

    @Autowired
    private ConfigService configService;
    @Autowired
    private Converter<List<DegradeRuleEntity>, String> converter;

    @Override
    public void publish(String app, List<DegradeRuleEntity> rules) throws Exception {
        AssertUtil.notEmpty(app, "app name cannot be empty");
        if (rules == null) {
            return;
        }
        configService.publishConfig(app + NacosConfigUtil.DEGRADE_DATA_ID_POSTFIX,
                NacosConfigUtil.GROUP_ID, converter.convert(rules));
    }
}

  • 添加DegradeControllerV2.java
    在这里插入图片描述
    在com.alibaba.csp.sentinel.dashboard.controller.v2包下添加DegradeControllerV2.java
/*
 * Copyright 1999-2018 Alibaba Group Holding Ltd.
 *
 * Licensed 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 com.alibaba.csp.sentinel.dashboard.controller.v2;

import com.alibaba.csp.sentinel.dashboard.auth.AuthAction;
import com.alibaba.csp.sentinel.dashboard.auth.AuthService.PrivilegeType;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.DegradeRuleEntity;
import com.alibaba.csp.sentinel.dashboard.domain.Result;
import com.alibaba.csp.sentinel.dashboard.repository.rule.RuleRepository;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.CircuitBreakerStrategy;
import com.alibaba.csp.sentinel.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.*;

import java.util.Date;
import java.util.List;

/**
 * Sentinel 降级规则 持久化  Push 模式 Nacos
 * @Author jianghx
 * @Date 2021/12/24 11:47
 * @Version 1.0
 **/
@RestController
@RequestMapping(value = "/v2/degrade")
public class DegradeControllerV2 {

    private final Logger logger = LoggerFactory.getLogger(DegradeControllerV2.class);

    @Autowired
    private RuleRepository<DegradeRuleEntity, Long> repository;

    @Autowired
    @Qualifier("degradeRuleNacosProvider")
    private DynamicRuleProvider<List<DegradeRuleEntity>> ruleProvider;

    @Autowired
    @Qualifier("degradeRuleNacosPublisher")
    private DynamicRulePublisher<List<DegradeRuleEntity>> rulePublisher;

    @GetMapping("/rules.json")
    @AuthAction(PrivilegeType.READ_RULE)
    public Result<List<DegradeRuleEntity>> apiQueryMachineRules(String app) {

        if (StringUtil.isEmpty(app)) {
            return Result.ofFail(-1, "app can't be null or empty");
        }
        try {
            List<DegradeRuleEntity> rules = ruleProvider.getRules(app);
            if (rules != null && !rules.isEmpty()) {
                for (DegradeRuleEntity entity : rules) {
                    entity.setApp(app);
                }
            }
            rules = repository.saveAll(rules);
            return Result.ofSuccess(rules);
        } catch (Throwable throwable) {
            logger.error("queryApps error:", throwable);
            return Result.ofThrowable(-1, throwable);
        }
    }

    @PostMapping("/rule")
    @AuthAction(PrivilegeType.WRITE_RULE)
    public Result<DegradeRuleEntity> apiAddRule(@RequestBody DegradeRuleEntity entity) {

        Result<DegradeRuleEntity> checkResult = checkEntityInternal(entity);
        if (checkResult != null) {
            return checkResult;
        }
        Date date = new Date();
        entity.setGmtCreate(date);
        entity.setGmtModified(date);
        try {
            entity = repository.save(entity);
            publishRules(entity.getApp());
        } catch (Throwable t) {
            logger.error("Failed to add new degrade rule, app={}, ip={}", entity.getApp(), entity.getIp(), t);
            return Result.ofThrowable(-1, t);
        }
        return Result.ofSuccess(entity);
    }

    @PutMapping("/rule/{id}")
    @AuthAction(PrivilegeType.WRITE_RULE)
    public Result<DegradeRuleEntity> apiUpdateRule(@PathVariable("id") Long id,
                                                   @RequestBody DegradeRuleEntity entity) {
        if (id == null || id <= 0) {
            return Result.ofFail(-1, "id can't be null or negative");
        }
        DegradeRuleEntity oldEntity = repository.findById(id);
        if (oldEntity == null) {
            return Result.ofFail(-1, "Degrade rule does not exist, id=" + id);
        }
        entity.setApp(oldEntity.getApp());
        entity.setIp(oldEntity.getIp());
        entity.setPort(oldEntity.getPort());
        entity.setId(oldEntity.getId());
        Result<DegradeRuleEntity> checkResult = checkEntityInternal(entity);
        if (checkResult != null) {
            return checkResult;
        }

        entity.setGmtCreate(oldEntity.getGmtCreate());
        entity.setGmtModified(new Date());
        try {
            entity = repository.save(entity);
            publishRules(entity.getApp());
        } catch (Throwable t) {
            logger.error("Failed to save degrade rule, id={}, rule={}", id, entity, t);
            return Result.ofThrowable(-1, t);
        }
        return Result.ofSuccess(entity);
    }

    @DeleteMapping("/rule/{id}")
    @AuthAction(PrivilegeType.DELETE_RULE)
    public Result<Long> delete(@PathVariable("id") Long id) {
        if (id == null) {
            return Result.ofFail(-1, "id can't be null");
        }

        DegradeRuleEntity oldEntity = repository.findById(id);
        if (oldEntity == null) {
            return Result.ofSuccess(null);
        }

        try {
            repository.delete(id);
            publishRules(oldEntity.getApp());
        } catch (Throwable throwable) {
            logger.error("Failed to delete degrade rule, id={}", id, throwable);
            return Result.ofThrowable(-1, throwable);
        }
        return Result.ofSuccess(id);
    }

    private void publishRules(String app) throws Exception {
        List<DegradeRuleEntity> rules = repository.findAllByApp(app);
        rulePublisher.publish(app, rules);
    }

    private <R> Result<R> checkEntityInternal(DegradeRuleEntity entity) {
        if (entity == null) {
            return Result.ofFail(-1, "invalid body");
        }
        if (StringUtil.isBlank(entity.getApp())) {
            return Result.ofFail(-1, "app can't be blank");
        }
        if (StringUtil.isBlank(entity.getIp())) {
            return Result.ofFail(-1, "ip can't be null or empty");
        }
        if (entity.getPort() == null || entity.getPort() <= 0) {
            return Result.ofFail(-1, "invalid port: " + entity.getPort());
        }
        if (StringUtil.isBlank(entity.getLimitApp())) {
            return Result.ofFail(-1, "limitApp can't be null or empty");
        }
        if (StringUtil.isBlank(entity.getResource())) {
            return Result.ofFail(-1, "resource can't be null or empty");
        }
        Double threshold = entity.getCount();
        if (threshold == null || threshold < 0) {
            return Result.ofFail(-1, "invalid threshold: " + threshold);
        }
        Integer recoveryTimeoutSec = entity.getTimeWindow();
        if (recoveryTimeoutSec == null || recoveryTimeoutSec <= 0) {
            return Result.ofFail(-1, "recoveryTimeout should be positive");
        }
        Integer strategy = entity.getGrade();
        if (strategy == null) {
            return Result.ofFail(-1, "circuit breaker strategy cannot be null");
        }
        if (strategy < CircuitBreakerStrategy.SLOW_REQUEST_RATIO.getType()
                || strategy > RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT) {
            return Result.ofFail(-1, "Invalid circuit breaker strategy: " + strategy);
        }
        if (entity.getMinRequestAmount()  == null || entity.getMinRequestAmount() <= 0) {
            return Result.ofFail(-1, "Invalid minRequestAmount");
        }
        if (entity.getStatIntervalMs() == null || entity.getStatIntervalMs() <= 0) {
            return Result.ofFail(-1, "Invalid statInterval");
        }
        if (strategy == RuleConstant.DEGRADE_GRADE_RT) {
            Double slowRatio = entity.getSlowRatioThreshold();
            if (slowRatio == null) {
                return Result.ofFail(-1, "SlowRatioThreshold is required for slow request ratio strategy");
            } else if (slowRatio < 0 || slowRatio > 1) {
                return Result.ofFail(-1, "SlowRatioThreshold should be in range: [0.0, 1.0]");
            }
        } else if (strategy == RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO) {
            if (threshold > 1) {
                return Result.ofFail(-1, "Ratio threshold should be in range: [0.0, 1.0]");
            }
        }
        return null;
    }
}


  • 修改sidebar.html,添加降级规则目录

在这里插入图片描述

 <li ui-sref-active="active" ng-if="entry.appType==0">
            <a ui-sref="dashboard.degrade2({app: entry.app})">
              <i class="glyphicon glyphicon-filter"></i>&nbsp;&nbsp;&nbsp;降级规则-Nacos</a>
          </li>
  • app.js添加代码
    位置:webapp\resources\app\scripts\app.js在这里插入图片描述
    .state('dashboard.degrade2', {
        templateUrl: 'app/views/degrade_v2.html',
        url: '/v2/degrade/:app',
        controller: 'DegradeControllerV2',
        resolve: {
          loadMyFiles: ['$ocLazyLoad', function ($ocLazyLoad) {
            return $ocLazyLoad.load({
              name: 'sentinelDashboardApp',
              files: [
                'app/scripts/controllers/degrade_v2.js',
              ]
            });
          }]
        }
      })
  • app.js添加代码
    位置:webapp\resources\dist\js\app.js
    注:跟上一个步骤的app.js同名不同路径
    在这里插入图片描述
.state("dashboard.degrade2", {
        templateUrl: "app/views/degrade_v2.html",
        url: "/v2/degrade/:app",
        controller: "DegradeControllerV2",
        resolve: {
            loadMyFiles: ["$ocLazyLoad", function (e) {
                return e.load({name: "sentinelDashboardApp", files: ["app/scripts/controllers/degrade_v2.js"]})
            }]
        }
    })

在这里插入图片描述

(app = angular.module("sentinelDashboardApp")).service("DegradeService2", ["$http", function (a) {
    this.queryMachineRules = function (e, t, r) {
        return a({url: "/v2/degrade/rules.json", params: {app: e, ip: t, port: r}, method: "GET"})
    }, this.newRule = function (e) {
        return a({url: "/v2/degrade/rule", data: e, method: "POST"})
    }, this.saveRule = function (e) {
        var t = {
            id: e.id,
            resource: e.resource,
            limitApp: e.limitApp,
            grade: e.grade,
            count: e.count,
            timeWindow: e.timeWindow,
            statIntervalMs: e.statIntervalMs,
            minRequestAmount: e.minRequestAmount,
            slowRatioThreshold: e.slowRatioThreshold
        };
        return a({url: "/v2/degrade/rule/" + e.id, data: t, method: "PUT"})
    }, this.deleteRule = function (e) {
        return a({url: "/v2/degrade/rule/" + e.id, method: "DELETE"})
    }, this.checkRuleValid = function (e) {
        if (void 0 === e.resource || "" === e.resource) return alert("资源名称不能为空"), !1;
        if (void 0 === e.grade || e.grade < 0) return alert("未知的降级策略"), !1;
        if (void 0 === e.count || "" === e.count || e.count < 0) return alert("降级阈值不能为空或小于 0"), !1;
        if (null == e.timeWindow || "" === e.timeWindow || e.timeWindow <= 0) return alert("熔断时长必须大于 0s"), !1;
        if (null == e.minRequestAmount || e.minRequestAmount <= 0) return alert("最小请求数目需大于 0"), !1;
        if (null == e.statIntervalMs || e.statIntervalMs <= 0) return alert("统计窗口时长需大于 0s"), !1;
        if (void 0 !== e.statIntervalMs && 12e4 < e.statIntervalMs) return alert("统计窗口时长不能超过 120 分钟"), !1;
        if (1 == e.grade && 1 < e.count) return alert("异常比率超出范围:[0.0 - 1.0]"), !1;
        if (0 == e.grade) {
            if (null == e.slowRatioThreshold) return alert("慢调用比率不能为空"), !1;
            if (e.slowRatioThreshold < 0 || 1 < e.slowRatioThreshold) return alert("慢调用比率超出范围:[0.0 - 1.0]"), !1
        }
        return !0
    }
}])
  • 新增degrade_v2.js
    在resources\app\scripts\controllers\目录下新增degrade_v2.js
    在这里插入图片描述
var app = angular.module('sentinelDashboardApp');

app.controller('DegradeControllerV2', ['$scope', '$stateParams', 'DegradeService2', 'ngDialog', 'MachineService',
  function ($scope, $stateParams, DegradeService, ngDialog, MachineService) {
    //初始化
    $scope.app = $stateParams.app;
    $scope.rulesPageConfig = {
      pageSize: 10,
      currentPageIndex: 1,
      totalPage: 1,
      totalCount: 0,
    };
    $scope.macsInputConfig = {
      searchField: ['text', 'value'],
      persist: true,
      create: false,
      maxItems: 1,
      render: {
        item: function (data, escape) {
          return '<div>' + escape(data.text) + '</div>';
        }
      },
      onChange: function (value, oldValue) {
        $scope.macInputModel = value;
      }
    };
    getMachineRules();
    function getMachineRules() {
      if (!$scope.macInputModel) {
        return;
      }
      var mac = $scope.macInputModel.split(':');
      DegradeService.queryMachineRules($scope.app, mac[0], mac[1]).success(
        function (data) {
          if (data.code == 0 && data.data) {
            $scope.rules = data.data;
            $scope.rulesPageConfig.totalCount = $scope.rules.length;
          } else {
            $scope.rules = [];
            $scope.rulesPageConfig.totalCount = 0;
          }
        });
    };
    $scope.getMachineRules = getMachineRules;

    var degradeRuleDialog;
    $scope.editRule = function (rule) {
      $scope.currentRule = angular.copy(rule);
      $scope.degradeRuleDialog = {
        title: '编辑降级规则',
        type: 'edit',
        confirmBtnText: '保存'
      };
      degradeRuleDialog = ngDialog.open({
        template: '/app/views/dialog/degrade-rule-dialog.html',
        width: 680,
        overlay: true,
        scope: $scope
      });
    };

    $scope.addNewRule = function () {
      var mac = $scope.macInputModel.split(':');
      $scope.currentRule = {
        grade: 0,
        app: $scope.app,
        ip: mac[0],
        port: mac[1],
        limitApp: 'default',
        minRequestAmount: 5,
        statIntervalMs: 1000,
      };
      $scope.degradeRuleDialog = {
        title: '新增降级规则',
        type: 'add',
        confirmBtnText: '新增'
      };
      degradeRuleDialog = ngDialog.open({
        template: '/app/views/dialog/degrade-rule-dialog.html',
        width: 680,
        overlay: true,
        scope: $scope
      });
    };

    $scope.saveRule = function () {
      if (!DegradeService.checkRuleValid($scope.currentRule)) {
        return;
      }
      if ($scope.degradeRuleDialog.type === 'add') {
        addNewRule($scope.currentRule);
      } else if ($scope.degradeRuleDialog.type === 'edit') {
        saveRule($scope.currentRule, true);
      }
    };

    function parseDegradeMode(grade) {
        switch (grade) {
            case 0:
              return '慢调用比例';
            case 1:
              return '异常比例';
            case 2:
              return '异常数';
            default:
              return '未知';
        }
    }

    var confirmDialog;
    $scope.deleteRule = function (rule) {
      $scope.currentRule = rule;
      $scope.confirmDialog = {
        title: '删除降级规则',
        type: 'delete_rule',
        attentionTitle: '请确认是否删除如下降级规则',
        attention: '资源名: ' + rule.resource +
            ', 降级模式: ' + parseDegradeMode(rule.grade) + ', 阈值: ' + rule.count,
        confirmBtnText: '删除',
      };
      confirmDialog = ngDialog.open({
        template: '/app/views/dialog/confirm-dialog.html',
        scope: $scope,
        overlay: true
      });
    };

    $scope.confirm = function () {
      if ($scope.confirmDialog.type == 'delete_rule') {
        deleteRule($scope.currentRule);
      } else {
        console.error('error');
      }
    };

    function deleteRule(rule) {
      DegradeService.deleteRule(rule).success(function (data) {
        if (data.code == 0) {
          getMachineRules();
          confirmDialog.close();
        } else {
          alert('失败:' + data.msg);
        }
      });
    };

    function addNewRule(rule) {
      DegradeService.newRule(rule).success(function (data) {
        if (data.code == 0) {
          getMachineRules();
          degradeRuleDialog.close();
        } else {
          alert('失败:' + data.msg);
        }
      });
    };

    function saveRule(rule, edit) {
      DegradeService.saveRule(rule).success(function (data) {
        if (data.code == 0) {
          getMachineRules();
          if (edit) {
            degradeRuleDialog.close();
          } else {
            confirmDialog.close();
          }
        } else {
          alert('失败:' + data.msg);
        }
      });
    }
    queryAppMachines();
    function queryAppMachines() {
      MachineService.getAppMachines($scope.app).success(
        function (data) {
          if (data.code == 0) {
            // $scope.machines = data.data;
            if (data.data) {
              $scope.machines = [];
              $scope.macsInputOptions = [];
              data.data.forEach(function (item) {
                if (item.healthy) {
                  $scope.macsInputOptions.push({
                    text: item.ip + ':' + item.port,
                    value: item.ip + ':' + item.port
                  });
                }
              });
            }
            if ($scope.macsInputOptions.length > 0) {
              $scope.macInputModel = $scope.macsInputOptions[0].value;
            }
          } else {
            $scope.macsInputOptions = [];
          }
        }
      );
    };
    $scope.$watch('macInputModel', function () {
      if ($scope.macInputModel) {
        getMachineRules();
      }
    });
  }]);

  • 新增degrade_service_v2.js
    新增位置:webapp\resources\app\scripts\services\degrade_service_v2.js
    在这里插入图片描述

var app = angular.module('sentinelDashboardApp');

app.service('DegradeService2', ['$http', function ($http) {
  this.queryMachineRules = function (app, ip, port) {
    var param = {
      app: app,
      ip: ip,
      port: port
    };
    return $http({
      url: 'v2/degrade/rules.json',
      params: param,
      method: 'GET'
    });
  };

  this.newRule = function (rule) {
    return $http({
        url: '/v2/degrade/rule',
        data: rule,
        method: 'POST'
    });
  };

  this.saveRule = function (rule) {
    var param = {
      id: rule.id,
      resource: rule.resource,
      limitApp: rule.limitApp,
      grade: rule.grade,
      count: rule.count,
      timeWindow: rule.timeWindow,
        statIntervalMs: rule.statIntervalMs,
        minRequestAmount: rule.minRequestAmount,
        slowRatioThreshold: rule.slowRatioThreshold,
    };
    return $http({
        url: '/v2/degrade/rule/' + rule.id,
        data: param,
        method: 'PUT'
    });
  };

  this.deleteRule = function (rule) {
      return $http({
          url: '/v2/degrade/rule/' + rule.id,
          method: 'DELETE'
      });
  };

  this.checkRuleValid = function (rule) {
      if (rule.resource === undefined || rule.resource === '') {
          alert('资源名称不能为空');
          return false;
      }
      if (rule.grade === undefined || rule.grade < 0) {
          alert('未知的降级策略');
          return false;
      }
      if (rule.count === undefined || rule.count === '' || rule.count < 0) {
          alert('降级阈值不能为空或小于 0');
          return false;
      }
      if (rule.timeWindow == undefined || rule.timeWindow === '' || rule.timeWindow <= 0) {
          alert('熔断时长必须大于 0s');
          return false;
      }
      if (rule.minRequestAmount == undefined || rule.minRequestAmount <= 0) {
          alert('最小请求数目需大于 0');
          return false;
      }
      if (rule.statIntervalMs == undefined || rule.statIntervalMs <= 0) {
          alert('统计窗口时长需大于 0s');
          return false;
      }
      if (rule.statIntervalMs !== undefined && rule.statIntervalMs > 60 * 1000 * 2) {
          alert('统计窗口时长不能超过 120 分钟');
          return false;
      }
      // 异常比率类型.
      if (rule.grade == 1 && rule.count > 1) {
          alert('异常比率超出范围:[0.0 - 1.0]');
          return false;
      }
      if (rule.grade == 0) {
          if (rule.slowRatioThreshold == undefined) {
              alert('慢调用比率不能为空');
              return false;
          }
          if (rule.slowRatioThreshold < 0 || rule.slowRatioThreshold > 1) {
              alert('慢调用比率超出范围:[0.0 - 1.0]');
              return false;
          }
      }
      return true;
  };
}]);

  • 新增degrade_v2.html
    新增位置:webapp\resources\app\views\degrade_v2.html
    在这里插入图片描述


<div class="row" style="margin-left: 1px; margin-top:10px; height: 50px;">
  <div class="col-md-6" style="margin-bottom: 10px;">
    <span style="font-size: 30px;font-weight: bold;">{{app}}</span>
  </div>
  <div class="col-md-6">
    <button class="btn btn-default-inverse" style="float: right; margin-right: 10px;" ng-disabled="!macInputModel" ng-click="addNewRule()">
      <i class="fa fa-plus"></i>&nbsp;&nbsp;新增降级规则</button>
  </div>
</div>

<div class="separator"></div>

<div class="container-fluid">
  <div class="row" style="margin-top: 20px; margin-bottom: 20px;">
    <div class="col-md-12">
      <div class="card">
        <div class="inputs-header">
          <span class="brand" style="font-size: 13px;">降级规则</span>
          <!--<button class="btn btn-danger" style="float: right;margin-right: 10px;height: 30px;font-size: 12px;" ng-click="disableAll()">全部禁用</button>-->
          <button class="btn btn-primary" style="float: right; margin-right: 10px; height: 30px;font-size: 12px;" ng-click="getMachineRules()">刷新</button>
          <input class="form-control witdh-200" placeholder="关键字" ng-model="searchKey">
          <div class="control-group" style="float:right;margin-right: 10px;margin-bottom: -10px;">
            <selectize id="gsInput" class="selectize-input-200" config="macsInputConfig" options="macsInputOptions" ng-model="macInputModel"
              placeholder="机器"></selectize>
          </div>
        </div>

        <!--.tools-header -->
        <div class="card-body" style="padding: 0px 0px;">
          <table class="table" style="border-left: none; border-right:none;margin-top: 10px;">
            <thead>
              <tr style="background: #F3F5F7;">
                <td style="width: 40%">
                  资源名
                </td>
                <td style="width: 10%;">
                  降级策略
                </td>
                <td style="width: 10%;">
                  阈值
                </td>
                <td style="width: 10%;">
                  熔断时长(s)
                </td>
                <td style="width: 12%;">
                  操作
                </td>
              </tr>
            </thead>
            <tbody>
              <tr dir-paginate="rule in rules | filter : searchKey | itemsPerPage: rulesPageConfig.pageSize " current-page="rulesPageConfig.currentPageIndex"
                pagination-id="entriesPagination">
                <td style="word-wrap:break-word;word-break:break-all;">{{rule.resource}}</td>
                <!--<td style="word-wrap:break-word;word-break:break-all;">{{rule.limitApp }}</td>-->
                <td>
                  <span ng-if="rule.grade == 0">慢调用比例</span>
                  <span ng-if="rule.grade == 1" title="异常比例">异常比例</span>
                  <span ng-if="rule.grade == 2" title="异常数">异常数</span>
                </td>
                <td style="word-wrap:break-word;word-break:break-all;">
                  {{rule.count}}
                </td>
                <td style="word-wrap:break-word;word-break:break-all;">
                  {{rule.timeWindow}}s
                </td>

                <td>
                  <button class="btn btn-xs btn-default" type="button" ng-click="editRule(rule)" style="font-size: 12px; height:25px;">编辑</button>
                  <button class="btn btn-xs btn-default" type="button" ng-click="deleteRule(rule)" style="font-size: 12px; height:25px;">删除</button>
                </td>
              </tr>
            </tbody>
          </table>
        </div>
        <!-- .card-body -->
        <div class="pagination-footer">
          <dir-pagination-controls boundary-links="true" template-url="app/views/pagination.tpl.html" pagination-id="entriesPagination"
            on-page-change="">
          </dir-pagination-controls>
          <div class="tools" style="">
            <span>共 {{rulesPageConfig.totalCount}} 条记录, </span>
            <span>
              每页
              <input class="form-control" ng-model="rulesPageConfig.pageSize"> 条记录,
            </span>
            <span>第 {{rulesPageConfig.currentPageIndex}} / {{rulesPageConfig.totalPage}} 页</span>
          </div>
          <!-- .tools -->
        </div>
        <!-- pagination-footer -->
      </div>
      <!-- .card -->
    </div>
    <!-- .col-md-12 -->
  </div>
  <!-- -->
</div>
<!-- .container-fluid -->

  • 修改gulpfile.js插入代码
    位置:webapp\resources\gulpfile.js
    在这里插入图片描述
    gulpfile.js中的const JS_APP添加代码
 'app/scripts/services/degrade_service_v2.js',
  • 修改微服务application.yml添加降级配置(不是sentinel-dashboard的)

在这里插入图片描述

  • 实际效果
    注意:降级规格必须从【降级规则-Nacos】的界面新增才有效,从其他目录新增的,没法保存到nacos进行是持久化的
    在这里插入图片描述
    在这里插入图片描述
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值