soul网关源码解析-http长轮询(soul-bootstrap)

我们看到这个项目soul-sync-data-http
上次文章中可以看到主要实现2个接口(获取数据 监听)
bootstrap主要通过

    private void start() {
       // It could be initialized multiple times, so you need to control that.
       if (RUNNING.compareAndSet(false, true)) {
           // fetch all group configs.
           this.fetchGroupConfig(ConfigGroupEnum.values());
           int threadSize = serverList.size();
           this.executor = new ThreadPoolExecutor(threadSize, threadSize, 60L, TimeUnit.SECONDS,
                   new LinkedBlockingQueue<>(),
                   SoulThreadFactory.create("http-long-polling", true));
           // start long polling, each server creates a thread to listen for changes.
           //开启轮训任务
           this.serverList.forEach(server -> this.executor.execute(new HttpLongPollingTask(server)));
       } else {
           log.info("soul http long polling was started, executor=[{}]", executor);
       }
   }

我们再看下方法HttpLongPollingTask

    class HttpLongPollingTask implements Runnable {

       private String server;

       private final int retryTimes = 3;

       HttpLongPollingTask(final String server) {
           this.server = server;
       }

       @Override
       public void run() {
           while (RUNNING.get()) {
               for (int time = 1; time <= retryTimes; time++) {
                   try {
                   //调用方法
                       doLongPolling(server);
                   } catch (Exception e) {
                       // print warnning log.
                       if (time < retryTimes) {
                           log.warn("Long polling failed, tried {} times, {} times left, will be suspended for a while! {}",
                                   time, retryTimes - time, e.getMessage());
                           ThreadUtils.sleep(TimeUnit.SECONDS, 5);
                           continue;
                       }
                       // print error, then suspended for a while.
                       log.error("Long polling failed, try again after 5 minutes!", e);
                       ThreadUtils.sleep(TimeUnit.MINUTES, 5);
                   }
               }
           }
           log.warn("Stop http long polling.");
       }
   }

然后我们看到方法doLongPolling

 private void doLongPolling(final String server) {
       MultiValueMap<String, String> params = new LinkedMultiValueMap<>(8);
       for (ConfigGroupEnum group : ConfigGroupEnum.values()) {
           ConfigData<?> cacheConfig = factory.cacheConfigData(group);
           String value = String.join(",", cacheConfig.getMd5(), String.valueOf(cacheConfig.getLastModifyTime()));
           params.put(group.name(), Lists.newArrayList(value));
       }
       HttpHeaders headers = new HttpHeaders();
       headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
       HttpEntity httpEntity = new HttpEntity(params, headers);
       String listenerUrl = server + "/configs/listener";
       log.debug("request listener configs: [{}]", listenerUrl);
       JsonArray groupJson = null;
       try {
       //在这里发起对admin后台监听接口的调用
           String json = this.httpClient.postForEntity(listenerUrl, httpEntity, String.class).getBody();
           log.debug("listener result: [{}]", json);
           groupJson = GSON.fromJson(json, JsonObject.class).getAsJsonArray("data");
       } catch (RestClientException e) {
           String message = String.format("listener configs fail, server:[%s], %s", server, e.getMessage());
           throw new SoulException(message, e);
       }
       if (groupJson != null) {
           // fetch group configuration async.
           ConfigGroupEnum[] changedGroups = GSON.fromJson(groupJson, ConfigGroupEnum[].class);
           if (ArrayUtils.isNotEmpty(changedGroups)) {
               log.info("Group config changed: {}", Arrays.toString(changedGroups));
               //监听接口返回有变化,就会去调用获取接口数据
               this.doFetchGroupConfig(server, changedGroups);
           }
       }
   }

调用获取接口数据的方法

    private void doFetchGroupConfig(final String server, final ConfigGroupEnum... groups) {
       StringBuilder params = new StringBuilder();
       for (ConfigGroupEnum groupKey : groups) {
           params.append("groupKeys").append("=").append(groupKey.name()).append("&");
       }
       String url = server + "/configs/fetch?" + StringUtils.removeEnd(params.toString(), "&");
       log.info("request configs: [{}]", url);
       String json = null;
       try {
       //获取改变接口的数据.
           json = this.httpClient.getForObject(url, String.class);
       } catch (RestClientException e) {
           String message = String.format("fetch config fail from server[%s], %s", url, e.getMessage());
           log.warn(message);
           throw new SoulException(message, e);
       }
       // update local cache
       boolean updated = this.updateCacheWithJson(json);
       if (updated) {
           log.info("get latest configs: [{}]", json);
           return;
       }
       // not updated. it is likely that the current config server has not been updated yet. wait a moment.
       log.info("The config of the server[{}] has not been updated or is out of date. Wait for 30s to listen for changes again.", server);
       ThreadUtils.sleep(TimeUnit.SECONDS, 30);
   }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值