feign zipkin Trace Hystrix 重试源码详解

feign zipkin Trace Hystrix 重试源码详解

@Configuration
@ConditionalOnProperty(value = "spring.sleuth.enabled", havingValue = "true")
@Slf4j
public class CommonTraceHystrixConfiguration {

	/**
	 * hystrix 超时时间
	 */
	static int hystrixTimeOut = 5000;
	/**
	 * 请求超时时间
	 */
	static int requestTimeOut = 4000;

	@Bean
	public Request.Options options() {
		return new Request.Options(requestTimeOut, requestTimeOut);
	}

	@Bean
	Retryer feignRetryer() {
		//最多访问一次
		return new Retryer.Default(100, SECONDS.toMillis(1), 1);
	}

	@Bean
	@Primary
	@Scope("prototype")
	public Feign.Builder feignTraceHystrixBuilderExt(BeanFactory beanFactory) {
		return HystrixFeign.builder().setterFactory(new SetterFactory() {
			public HystrixCommand.Setter create(Target<?> target, Method method) {
				String groupKey = target.name();
				String commandKey = method.getName();
				return HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(groupKey))
						.andCommandKey(HystrixCommandKey.Factory.asKey(commandKey)).andCommandPropertiesDefaults(
								HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(hystrixTimeOut)
										.withCircuitBreakerSleepWindowInMilliseconds(hystrixTimeOut));
			}
		}).client(new TraceFeignClient(beanFactory));//TraceFeignClient 是client得一个子类
	}

}

org.springframework.cloud.sleuth.instrument.web.client.feign.TraceFeignClient.execute(Request, Options)
@Override
	public Response execute(Request request, Request.Options options) throws IOException {
		String spanName = getSpanName(request);
		Span span = getTracer().createSpan(spanName);
		if (log.isDebugEnabled()) {
			log.debug("Created new Feign span " + span);
		}
		try {
			AtomicReference<Request> feignRequest = new AtomicReference<>(request);
			this.spanInjector.inject(span, feignRequest);
			span.logEvent(Span.CLIENT_SEND);
			addRequestTags(request);
			Request modifiedRequest = feignRequest.get();
			if (log.isDebugEnabled()) {
				log.debug("The modified request equals " + modifiedRequest);
			}
			Response response = this.delegate.execute(modifiedRequest, options);
			logCr();
			return response;
		} catch (RuntimeException | IOException e) {
			logError(e);
			throw e;
		} finally {
			closeSpan(span);
		}
	}



feign.SynchronousMethodHandler.invoke(Object[])


 @Override
  public Object invoke(Object[] argv) throws Throwable {
    RequestTemplate template = buildTemplateFromArgs.create(argv);
    Retryer retryer = this.retryer.clone();
    while (true) {
      try {
        return executeAndDecode(template);//这里会调用TraceFeignClient 
      } catch (RetryableException e) {
        retryer.continueOrPropagate(e);//判断最大重试次输
        if (logLevel != Logger.Level.NONE) {
          logger.logRetry(metadata.configKey(), logLevel);
        }
        continue;
      }
    }
  }






public interface Retryer extends Cloneable {

  /**
   * if retry is permitted, return (possibly after sleeping). Otherwise propagate the exception.
   */
  void continueOrPropagate(RetryableException e);

  Retryer clone();

  public static class Default implements Retryer {

    private final int maxAttempts;
    private final long period;
    private final long maxPeriod;
    int attempt;//当前访问次数
    long sleptForMillis;

    public Default() {
      this(100, SECONDS.toMillis(1), 5);
    }

    public Default(long period, long maxPeriod, int maxAttempts) {
      this.period = period;
      this.maxPeriod = maxPeriod;
      this.maxAttempts = maxAttempts;//最大访问次输
      this.attempt = 1;//当前访问次数
    }

    // visible for testing;
    protected long currentTimeMillis() {
      return System.currentTimeMillis();
    }

    public void continueOrPropagate(RetryableException e) {
      if (attempt++ >= maxAttempts) {
        throw e;
      }

      long interval;
      if (e.retryAfter() != null) {
        interval = e.retryAfter().getTime() - currentTimeMillis();
        if (interval > maxPeriod) {
          interval = maxPeriod;
        }
        if (interval < 0) {
          return;
        }
      } else {
        interval = nextMaxInterval();
      }
      try {
        Thread.sleep(interval);
      } catch (InterruptedException ignored) {
        Thread.currentThread().interrupt();
      }
      sleptForMillis += interval;
    }

    /**
     * Calculates the time interval to a retry attempt. <br> The interval increases exponentially
     * with each attempt, at a rate of nextInterval *= 1.5 (where 1.5 is the backoff factor), to the
     * maximum interval.
     *
     * @return time in nanoseconds from now until the next attempt.
     */
    long nextMaxInterval() {
      long interval = (long) (period * Math.pow(1.5, attempt - 1));
      return interval > maxPeriod ? maxPeriod : interval;
    }

    @Override
    public Retryer clone() {
      return new Default(period, maxPeriod, maxAttempts);
    }
  }

  /**
   * Implementation that never retries request. It propagates the RetryableException.
   */
  Retryer NEVER_RETRY = new Retryer() {

    @Override
    public void continueOrPropagate(RetryableException e) {
      throw e;
    }

    @Override
    public Retryer clone() {
      return this;
    }
  };
}

 

转载于:https://my.oschina.net/xiaominmin/blog/3049830

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值