3

I managed to successfully get my RestTemplate client discover remote service using Eureka and forward calls to it using Ribbon as described in the documentation. Basically, it was just a matter of adding the following annotations of my Application class and let the magic of Spring-Boot do the rest:

@Configuration
@ComponentScan
@EnableAutoConfiguration
@EnableDiscoveryClient

(PS: you noticed I'm using spring-cloud:1.0.0-SNAPSHOT-BUILD and not 1.0.0.M3 - but this doesn't seem to affect my problem).

When two service instances are started, the rest-template client successfully load balance requests between the two. However, the client won't fallback to the second instance if the first is stopped before the Eureka load balancer notices, instead an exception is thrown.

Hence my question: is there a way to configure the RestTemplate/Ribbon/Eureka stack to automatically retry the call to another instance if the one selected the first place is not available? Zuul proxy and feign clients do this "out of the box" so I believe the library holds the necessary features...

Any idea/hint?

Thx, /Bertrand

Bertrand Renuart
  • 1,608
  • 17
  • 24
  • 1
    Or is it because the integration into the RestTemplate is done using an interceptor whose only purpose is to translate the serviceId into an appropriate URL but doesn't wrap the entire call process and therefore is not able to perform any "retry" logic ? – Bertrand Renuart Dec 14 '14 at 11:35

2 Answers2

4

The RestTemplate support on its own does not know how to do any retrying (whereas the Feign client and the proxy support in Spring Cloud does, as you noticed). I think this is probably a good things because it gives you the option to add it yourself. For instance, using Spring Retry you can do it in a simple declarative style:

@Retryable
public Object doSomething() {
   // use your RestTemplate here
}

(and add @EnableRetry to your @Configuration). It makes a nice combination with @HystrixCommand (from Spring Cloud / Javanica):

@HystrixCommand
@Retryable
public Object doSomething() {
   // use your RestTemplate here
}

In this form, every failure counts towards the circuit breaker metrics (maybe we could change that, or maybe it makes sense to leave it like that), even if the retry is successful.

Dave Syer
  • 56,583
  • 10
  • 155
  • 143
  • 1
    Ok, got it. I gave a try `@Retryable` and it does the job perfectly. However, the use of the `@HystrixCommand` with a fallback method seems to interfere as it captures the exception first before `@Retryable`. So I'm a bit puzzled as how to use them both together. – Bertrand Renuart Dec 15 '14 at 11:06
  • I think it might be that I just got lucky - the hystrix and the retryable aspects have the same `Order` so whether or not the exception is caught and retried depends on the order they are discovered by Spring. For the record, my `@Configuration` has `@EnableCircuitBreaker @EnableRetry(proxyTargetClass=true)` (in that order). – Dave Syer Dec 15 '14 at 11:37
  • 1
    They are indeed registered in the opposite order here... But ok, it is therefore just a matter of telling Spring to register them in the appropriate order. I'll have a look (unless you already have an idea of how I could do that ;-) – Bertrand Renuart Dec 15 '14 at 11:47
  • @BertrandRenuart: did you resolve the ordering issue? if, so can you provide solution.. – brain storm Aug 08 '15 at 07:11
  • is @Retryable sends requests to other server (NextServer retry) ? – Krishna Gangaraju Sep 21 '17 at 08:49
  • No, it retries the same thing. There is no "other" server, just a URI. NB spring-retry also has `@CircuitBreaker` now (so you don't always need javanica). – Dave Syer Sep 21 '17 at 09:15
  • we are using RestTemplate with @LoadBalanced. Ribbon (spring cloud netflix stack) aws ecs.. my scenario is i've two services (abc-service, xyz-service) abc-service calling xyz-service.. each one has 2 tasks (ecs) when one of the xyz-service container shutdowned .. load balancer not trying with other xyz-service (remaining service) .. i'm getting connection errors. what could be wrong? – Krishna Gangaraju Sep 21 '17 at 11:54
  • is ordering of EnableCircuitBreaker & EnableRetry fixed? – Rahul Singh Aug 29 '18 at 17:15
0

I couldn't get it to work with both @HystrixCommand and @Retryable, regardless of order of annotations on @Configuration class or on @Retryable method due to order of interceptors. I solved this by creating another class with the matching set of methods and had the @HystrixCommand annotated methods delegate to the corresponding @Retryable method in the second class. You could probably have the two classes implement the same interface. This is kind of a pain in the butt, but until order can be configured, this is all I could come up with. Still waiting on a real solution from Dave Syer and the spring cloud guys.

public class HystrixWrapper {
    @Autowired
    private RetryableWrapper retryableWrapper;

    @HystrixCommand
    public Response doSomething(...) {
        return retryableWrapper.doSomething(...);
    }
}

public class RetryableWrapper {
    @Autowired
    private RestTemplate restTemplate;

    @Retryable
    public Response doSomething(...) {
        // do something with restTemplate;
    }
}