2014-12-14 3 views
3

Мне удалось успешно заставить моего клиента RestTemplate открыть удаленную службу с помощью Eureka и переадресовать ее с помощью ленты, как описано в документации. В принципе, это был просто вопрос добавления следующих аннотаций моего класса Application, и пусть магия Spring-Boot сделает все остальное:spring-cloud с RestTemplate // Ribbon/Eureka - повторить попытку, когда сервер недоступен

@Configuration 
@ComponentScan 
@EnableAutoConfiguration 
@EnableDiscoveryClient 

(PS: Вы заметили, я использую весна-облако: 1.0 .0-SNAPSHOT-BUILD, а не 1.0.0.M3 - но это, похоже, не влияет на мою проблему).

При запуске двух экземпляров службы клиент-клиент остального клиента успешно загружает запросы баланса между ними. Тем не менее, клиент не будет возвращаться ко второму экземпляру, если первый будет остановлен до того, как будет обнаружен балансировщик Eureka, вместо этого будет выбрано исключение.

Следовательно, мой вопрос: существует ли способ настроить стоп RestTemplate/Ribbon/Eureka для автоматического повторного вызова вызова на другой экземпляр, если тот, который выбрал первое место, недоступен? Zuul proxy и feign клиенты делают это «из коробки», поэтому я считаю, что библиотека содержит необходимые функции ...

Любая идея/подсказка?

Thx, /Bertrand

+1

Или это потому, что интеграция в RestTemplate осуществляется с помощью перехватчика, чья единственная цель состоит в том, чтобы перевести ServiceID в соответствующий URL, но не обернуть весь процесс вызова и, следовательно, не в состоянии выполнить любой " повторить "логику? –

ответ

4

Поддержка RestTemplate сама по себе не знает, как делать какие-либо повторные попытки (в то время как клиент Feign и поддержка прокси в Spring Cloud делает, как вы заметили). Я думаю, что это, вероятно, хорошая вещь, потому что она дает вам возможность добавить ее самостоятельно. Например, с помощью Spring Retry вы можете сделать это в простом декларативном стиле:

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

(и добавить @EnableRetry к вашему @Configuration). Это делает хорошую комбинацию с @HystrixCommand (от Spring Cloud/Javanica):

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

В этой форме, важно каждый провал по отношению к метрикам автоматического выключателя (может быть, мы могли бы изменить это, или, может быть, имеет смысл оставить его как это), даже если повтор успешный.

+1

Хорошо, понял. Я попробовал '@ Retryable', и он отлично справляется с этой задачей. Тем не менее, использование '@ HystrixCommand' с методом резервного копирования, по-видимому, мешает, поскольку оно захватывает исключение раньше, чем' @ Retryable'. Поэтому я немного озадачен тем, как использовать их вместе. –

+0

Я думаю, что может быть, мне просто повезло - у гистрии и повторных аспектов есть один и тот же «Порядок», так ли исключение поймано и повторено, зависит от того, какой порядок они обнаруживают весной.Для записи моя '@ Configuration' имеет' @EnableCircuitBreaker @EnableRetry (proxyTargetClass = true) '(в этом порядке). –

+1

Они действительно зарегистрированы в обратном порядке здесь ... Но хорошо, поэтому просто рассказывать Весне, чтобы зарегистрировать их в соответствующем порядке. Я посмотрю (если у вас уже нет идеи, как я могу это сделать ;-) –

0

Я не мог заставить его работать как с @HystrixCommand, так и с помощью @Retryable, независимо от порядка аннотаций в классе @Configuration или по методу @Retryable из-за порядка перехватчиков. Я решил это, создав еще один класс с соответствующим набором методов, и аннотированные методы @HystrixCommand делегировали соответствующий метод @Retryable во втором классе. Возможно, у вас есть два класса, реализующих один и тот же интерфейс. Это своего рода боль в прикладе, но пока заказ не может быть настроен, это все, что я мог придумать. Все еще ждут реального решения от Дейва Сиера и парней весеннего облака.

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; 
    } 
}