springboot admin+nacos+釘釘機器人監控不到服務上線通知問題

最近在搞admin監控時,遇到一個坑。背景是這樣得,使用得事nacos做註冊中心,開發了admin server服務以後,服務offline,down狀態可以正常推送到釘釘,但是up狀態一直監控不到,網上查了一些資料,相關說明較少,有一篇文章是說要複製NacosWatch.java,本地實現一下,因爲nacos沒有監聽上線通知。
按說明操作了,但是還是不好使。相關代碼如下:

  • NacosWatch.java
/**
 * @ClassName: NacosWatch
 * @Author: shuyu.wang
 * @Description:
 * @Date: 2020/6/1 14:02
 * @Version: 1.0
 */
@Slf4j
public class NacosWatch implements ApplicationEventPublisherAware, SmartLifecycle {

  /**
 * watch delay,duration to pull new service from nacos server.
   */
  private long watchDelay = 30000;

  private final NacosDiscoveryProperties properties;
  private final TaskScheduler taskScheduler;
  private final AtomicLong nacosWatchIndex;
  private final AtomicBoolean running;
  private ApplicationEventPublisher publisher;
  private ScheduledFuture<?> watchFuture;
  private Set<String> cacheServices;
  private HashMap<String, EventListener> subscribeListeners;

  public NacosWatch(NacosDiscoveryProperties properties) {
    this(properties, getTaskScheduler());
  }

  public NacosWatch(NacosDiscoveryProperties properties, TaskScheduler taskScheduler) {
    this.nacosWatchIndex = new AtomicLong(0L);
    this.running = new AtomicBoolean(false);
    this.cacheServices = new HashSet();
    this.subscribeListeners = new HashMap();
    this.properties = properties;
    this.taskScheduler = taskScheduler;
  }

  private static ThreadPoolTaskScheduler getTaskScheduler() {
    ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
    taskScheduler.initialize();
    return taskScheduler;
  }

  @Override
  public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
    this.publisher = publisher;
  }

  @Override
  public boolean isAutoStartup() {
    return true;
  }

  @Override
  public void stop(Runnable callback) {
    this.stop();
    callback.run();
  }

  @Override
  public void start() {
    if (this.running.compareAndSet(false, true)) {
      this.watchFuture =
          this.taskScheduler.scheduleWithFixedDelay(this::nacosServicesWatch, watchDelay);
    }

  }

  @Override
  public void stop() {
    if (this.running.compareAndSet(true, false) && this.watchFuture != null) {
      this.watchFuture.cancel(true);
    }

  }

  @Override
  public boolean isRunning() {
    return false;
  }

  @Override
  public int getPhase() {
    return 0;
  }

  public void nacosServicesWatch() {
    try {
      boolean changed = false;
      NamingService namingService = this.properties.namingServiceInstance();
      ListView<String>
          listView = this.properties.namingServiceInstance().getServicesOfServer(1, 2147483647);
      List<String> serviceList = listView.getData();
      Set<String> currentServices = new HashSet(serviceList);
      currentServices.removeAll(this.cacheServices);
      if (currentServices.size() > 0) {
        changed = true;
      }

      Iterator var6;
      String serviceName;
      if (this.cacheServices.removeAll(new HashSet(serviceList)) && this.cacheServices.size() > 0) {
        changed = true;
        var6 = this.cacheServices.iterator();

        while (var6.hasNext()) {
          serviceName = (String) var6.next();
          namingService
              .unsubscribe(serviceName, (EventListener) this.subscribeListeners.get(serviceName));
          this.subscribeListeners.remove(serviceName);
        }
      }

      this.cacheServices = new HashSet(serviceList);
      var6 = this.cacheServices.iterator();

      while (var6.hasNext()) {
        serviceName = (String) var6.next();
        if (!this.subscribeListeners.containsKey(serviceName)) {
          EventListener eventListener = (event) -> {
            this.publisher
                .publishEvent(new HeartbeatEvent(this, this.nacosWatchIndex.getAndIncrement()));
          };
          this.subscribeListeners.put(serviceName, eventListener);
          namingService.subscribe(serviceName, eventListener);
        }
      }

      if (changed) {
        this.publisher
            .publishEvent(new HeartbeatEvent(this, this.nacosWatchIndex.getAndIncrement()));
      }
    } catch (Exception var9) {
      log.error("Error watching Nacos Service change", var9);
    }

  }
}
  • NacosWatchAutoConfiguration.java
@Configuration
public class NacosWatchAutoConfiguration {
  @Bean
  @ConditionalOnMissingBean
  @ConditionalOnProperty(value = "spring.cloud.nacos.discovery.watch.enabled", matchIfMissing = true)
  public NacosWatch nacosWatchDeepBlue(NacosDiscoveryProperties nacosDiscoveryProperties) {
    return new NacosWatch(nacosDiscoveryProperties);
  }

}

添加上這兩個類以後,一頓debug,但是還是一直沒有上線狀態得提醒,最後發現自定義通知類繼承得AbstractStatusChangeNotifier.java需要重寫兩個方法。
正常情況下我們一般只會重寫 doNotify(InstanceEvent event, Instance instance)這個方法,但實際上還要重寫shouldNotify(InstanceEvent event, Instance instance)方法父類中只對UNKNOWN:UP得狀態變化做了推送。
最終自定義通知類如下:
DingTalkNotifier.java

@Slf4j
public class DingTalkNotifier extends AbstractStatusChangeNotifier {


  @Autowired
  private AlarmDingTalkRobotClient alarmDingTalkRobotClient;
  @Autowired
  private NacosConfigService nacosConfigService;
  /**
   * 消息模板
   */
  private static final String template = "<<<%s>>> \n 【服務名】: %s(%s) \n 【狀態】: %s(%s) \n 【服務ip】: %s \n 【詳情】: %s";

  private String titleAlarm = "系統告警";

  private String titleNotice = "系統通知";

  private String[] ignoreChanges = new String[]{"UNKNOWN:UP","DOWN:UP","OFFLINE:UP"};

  public DingTalkNotifier(InstanceRepository repository) {
    super(repository);
  }

  @Override
  protected boolean shouldNotify(InstanceEvent event, Instance instance) {
    if (!(event instanceof InstanceStatusChangedEvent)) {
      return false;
    } else {
      InstanceStatusChangedEvent statusChange = (InstanceStatusChangedEvent)event;
      String from = this.getLastStatus(event.getInstance());
      String to = statusChange.getStatusInfo().getStatus();
      return Arrays.binarySearch(this.ignoreChanges, from + ":" + to) < 0 && Arrays.binarySearch(this.ignoreChanges, "*:" + to) < 0 && Arrays.binarySearch(this.ignoreChanges, from + ":*") < 0;
    }
  }

  @Override
  protected Mono<Void> doNotify(InstanceEvent event, Instance instance) {

    return Mono.fromRunnable(() -> {
      if (!nacosConfigService.getIsopen()){
        return;
      }
      String watchapplications = nacosConfigService.getWatchapplications();
      Boolean flag=watchapplications.contains(instance.getRegistration().getName());
      if (!flag){
        return;
      }
      if (event instanceof InstanceStatusChangedEvent) {
        log.info("Instance {} ({}) is {}", instance.getRegistration().getName(),
            event.getInstance(),
            ((InstanceStatusChangedEvent) event).getStatusInfo().getStatus());

        String status = ((InstanceStatusChangedEvent) event).getStatusInfo().getStatus();
        String messageText = null;
        switch (status) {
          // 健康檢查沒通過
          case "DOWN":
            log.info("發送 健康檢查沒通過 的通知!");
            messageText = String
                .format(template,titleAlarm, instance.getRegistration().getName(), event.getInstance(),
                    ((InstanceStatusChangedEvent) event).getStatusInfo().getStatus(), "健康檢查沒通過",
                    instance.getRegistration().getServiceUrl(), JSONObject.toJSONString(instance.getStatusInfo().getDetails()));
            alarmDingTalkRobotClient.sendMarkdownMessage(titleAlarm, messageText, true);
            break;
          // 服務離線
          case "OFFLINE":
            log.info("發送 服務離線 的通知!");
            messageText = String
                .format(template,titleAlarm, instance.getRegistration().getName(), event.getInstance(),
                    ((InstanceStatusChangedEvent) event).getStatusInfo().getStatus(), "服務離線",
                    instance.getRegistration().getServiceUrl(), JSONObject.toJSONString(instance.getStatusInfo().getDetails()));
            alarmDingTalkRobotClient.sendMarkdownMessage(titleAlarm, messageText, true);
            break;
          //服務上線
          case "UP":
            log.info("發送 服務上線 的通知!");
            messageText = String
                .format(template,titleNotice, instance.getRegistration().getName(), event.getInstance(),
                    ((InstanceStatusChangedEvent) event).getStatusInfo().getStatus(), "服務上線",
                    instance.getRegistration().getServiceUrl(), JSONObject.toJSONString(instance.getStatusInfo().getDetails()));
            alarmDingTalkRobotClient.sendMarkdownMessage(titleNotice, messageText, true);
            break;
          // 服務未知異常
          case "UNKNOWN":
            log.info("發送 服務未知異常 的通知!");
            messageText = String
                .format(template,titleAlarm, instance.getRegistration().getName(), event.getInstance(),
                    ((InstanceStatusChangedEvent) event).getStatusInfo().getStatus(), "服務未知異常",
                    instance.getRegistration().getServiceUrl(), JSONObject.toJSONString(instance.getStatusInfo().getDetails()));
            alarmDingTalkRobotClient.sendMarkdownMessage(titleAlarm, messageText, true);
            break;
          default:
            break;
        }
      } else {
        log.info("Instance {} ({}) {}", instance.getRegistration().getName(), event.getInstance(),
            event.getType());
      }
    });
  }


}

其中AlarmDingTalkRobotClient類是釘釘報警自己封裝得類,這裏不做詳細描述,大家可以根據自己業務需求,自行封裝。
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章