Talk about RetryableFeignLoadBalancer of spring cloud

order

This paper mainly studies the RetryableFeignLoadBalancer of spring cloud

RetryableFeignLoadBalancer

spring-cloud-openfeign-core-2.2.0.M1-sources.jar!/org/springframework/cloud/openfeign/ribbon/RetryableFeignLoadBalancer.java

public class RetryableFeignLoadBalancer extends FeignLoadBalancer
		implements ServiceInstanceChooser {

	private final LoadBalancedRetryFactory loadBalancedRetryFactory;

	public RetryableFeignLoadBalancer(ILoadBalancer lb, IClientConfig clientConfig,
			ServerIntrospector serverIntrospector,
			LoadBalancedRetryFactory loadBalancedRetryFactory) {
		super(lb, clientConfig, serverIntrospector);
		this.loadBalancedRetryFactory = loadBalancedRetryFactory;
		this.setRetryHandler(new DefaultLoadBalancerRetryHandler(clientConfig));
	}

	@Override
	public RibbonResponse execute(final RibbonRequest request,
			IClientConfig configOverride) throws IOException {
		final Request.Options options;
		if (configOverride != null) {
			RibbonProperties ribbon = RibbonProperties.from(configOverride);
			options = new Request.Options(ribbon.connectTimeout(this.connectTimeout),
					ribbon.readTimeout(this.readTimeout));
		}
		else {
			options = new Request.Options(this.connectTimeout, this.readTimeout);
		}
		final LoadBalancedRetryPolicy retryPolicy = this.loadBalancedRetryFactory
				.createRetryPolicy(this.getClientName(), this);
		RetryTemplate retryTemplate = new RetryTemplate();
		BackOffPolicy backOffPolicy = this.loadBalancedRetryFactory
				.createBackOffPolicy(this.getClientName());
		retryTemplate.setBackOffPolicy(
				backOffPolicy == null ? new NoBackOffPolicy() : backOffPolicy);
		RetryListener[] retryListeners = this.loadBalancedRetryFactory
				.createRetryListeners(this.getClientName());
		if (retryListeners != null && retryListeners.length != 0) {
			retryTemplate.setListeners(retryListeners);
		}
		retryTemplate.setRetryPolicy(retryPolicy == null ? new NeverRetryPolicy()
				: new FeignRetryPolicy(request.toHttpRequest(), retryPolicy, this,
						this.getClientName()));
		return retryTemplate.execute(new RetryCallback<RibbonResponse, IOException>() {
			@Override
			public RibbonResponse doWithRetry(RetryContext retryContext)
					throws IOException {
				Request feignRequest = null;
				// on retries the policy will choose the server and set it in the context
				// extract the server and update the request being made
				if (retryContext instanceof LoadBalancedRetryContext) {
					ServiceInstance service = ((LoadBalancedRetryContext) retryContext)
							.getServiceInstance();
					if (service != null) {
						feignRequest = ((RibbonRequest) request
								.replaceUri(reconstructURIWithServer(
										new Server(service.getHost(), service.getPort()),
										request.getUri()))).toRequest();
					}
				}
				if (feignRequest == null) {
					feignRequest = request.toRequest();
				}
				Response response = request.client().execute(feignRequest, options);
				if (retryPolicy != null
						&& retryPolicy.retryableStatusCode(response.status())) {
					byte[] byteArray = response.body() == null ? new byte[] {}
							: StreamUtils
									.copyToByteArray(response.body().asInputStream());
					response.close();
					throw new RibbonResponseStatusCodeException(
							RetryableFeignLoadBalancer.this.clientName, response,
							byteArray, request.getUri());
				}
				return new RibbonResponse(request.getUri(), response);
			}
		}, new LoadBalancedRecoveryCallback<RibbonResponse, Response>() {
			@Override
			protected RibbonResponse createResponse(Response response, URI uri) {
				return new RibbonResponse(uri, response);
			}
		});
	}

	@Override
	public RequestSpecificRetryHandler getRequestSpecificRetryHandler(
			FeignLoadBalancer.RibbonRequest request, IClientConfig requestConfig) {
		return new RequestSpecificRetryHandler(false, false, this.getRetryHandler(),
				requestConfig);
	}

	@Override
	public ServiceInstance choose(String serviceId) {
		return new RibbonLoadBalancerClient.RibbonServer(serviceId,
				this.getLoadBalancer().chooseServer(serviceId));
	}

}
  • RetryableFeignLoadBalancer inherits FeignLoadBalancer and implements ServiceInstanceChooser interface.
  • Its constructor creates the DefaultLoadBalancerRetryHandler according to clientConfig; its choose method uses getLoadBalancer().chooseServer, and finally returns it through the RibbonLoadBalancerClient.RibbonServer wrapper.
  • Its execute method first creates the LoadBalancedRetryPolicy, then creates the retryTemplate, and finally implements the retry function through retryTemplate.execute; its RetryCallback's doWithRetry method will switch to the next service instance for retry when the retryContext is LoadBalancedRetryContext.

Summary

RetryableFeignLoadBalancer inherits FeignLoadBalancer. retryTemplate is used to retry the execute method. When retryContext is LoadBalancedRetryContext, the next service instance will be switched to retry.

doc

Keywords: Programming Spring Java

Added by luuney on Sat, 26 Oct 2019 19:42:26 +0300