Симулировать клиента и весеннюю попытку
У меня есть спокойный сервис, вызывающий внешний сервис с помощью клиента Spring Cloud Feign
@FeignClient(name = "external-service", configuration = FeignClientConfig.class)
public interface ServiceClient {
@RequestMapping(value = "/test/payments", method = RequestMethod.POST)
public void addPayment(@Valid @RequestBody AddPaymentRequest addPaymentRequest);
@RequestMapping(value = "/test/payments/{paymentId}", method = RequestMethod.PUT)
public ChangePaymentStatusResponse updatePaymentStatus(@PathVariable("paymentId") String paymentId,
@Valid @RequestBody PaymentStatusUpdateRequest paymentStatusUpdateRequest);
}
Я заметил следующую ошибку 3-4 раза за последние 3 месяца в моем лог-файле:
json.ERROR_RESPONSE_BODY: Соединению отказано в выполнении POST http://external-service/external/payments payment json.message: Отправить платеж Добавить сбой платежа по другой причине: {ERROR_RESPONSE_BODY= Соединению отказано в выполнении POST http://external-service/external/payments, EVENT = ADD_PAYMENT_FAILURE, TRANSACTION_ID = XXXXXXX} {} json.EVENT: ADD_PAYMENT_FAILURE json.stack_trace: feign.RetryableException: соединение отклонило выполнение POST http://external-service/external/payments messages в feign.FeignException.Exception.Exception 67) в feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:104) в feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:76) в feign.ReflectiveFeign$FeignInin
Можно ли добавить Spring Retry на клиенте Feign. Что я хотел аннотировать addPayment
работа с
@Retryable(value = {feign.RetryableException.class }, maxAttempts = 3, backoff = @Backoff(delay = 2000, multiplier=2))
Но это невозможно, какие еще есть варианты?
7 ответов
Вы можете добавить Retryer
в FeignClientConfig
@Configuration
public class FeignClientConfig {
@Bean
public Retryer retryer() {
return new Custom();
}
}
class Custom implements Retryer {
private final int maxAttempts;
private final long backoff;
int attempt;
public Custom() {
this(2000, 3);
}
public Custom(long backoff, int maxAttempts) {
this.backoff = backoff;
this.maxAttempts = maxAttempts;
this.attempt = 1;
}
public void continueOrPropagate(RetryableException e) {
if (attempt++ >= maxAttempts) {
throw e;
}
try {
Thread.sleep(backoff);
} catch (InterruptedException ignored) {
Thread.currentThread().interrupt();
}
}
@Override
public Retryer clone() {
return new Custom(backoff, maxAttempts);
}
}
Обновлено с образцом Retryer
пример конфигурации на основе Retryer.Default
,
Просто новый конструктор
Default
@Configuration
public class FeignClientConfig {
@Bean
public Retryer retryer() {
return new Retryer.Default(100, 2000, 3);
}
}
Если вы используете ленту, вы можете установить свойства, вы можете использовать следующие свойства для повтора:
myapp.ribbon.MaxAutoRetries=5
myapp.ribbon.MaxAutoRetriesNextServer=5
myapp.ribbon.OkToRetryOnAllOperations=true
Примечание: myapp - это идентификатор вашего сервиса.
Изучите эту реализацию Github для рабочего примера
Это мой конфиг. Проверка прошла нормально при весенней загрузке 2.2.0.RELEASEspring cloud Hoxton.M3.
feign.hystrix.enabled=true
MY-SPRING-API.ribbon.MaxAutoRetries=2
MY-SPRING-API.ribbon.MaxAutoRetriesNextServer=2
MY-SPRING-API.ribbon.OkToRetryOnAllOperations=true
MY-SPRING-API.ribbon.retryableStatusCodes=404,500
feign.client.config.PythonPatentClient.connectTimeout=500
feign.client.config.PythonPatentClient.readTimeout=500
hystrix.command.PythonPatentClient#timeTest(String).execution.isolation.thread.timeoutInMilliseconds=5000
Java-код:
@FeignClient(name = "MY-SPRING-API",configuration = {PythonPatentConfig.class},fallbackFactory = FallBack.class)
public interface PythonPatentClient
@RequestLine("GET /test?q={q}")
void timeTest(@Param("appNo") String q);
Контроллер это:
@RequestMapping(value = "/test",method = {RequestMethod.POST,RequestMethod.GET})
public Object test() throws InterruptedException {
log.info("========important print enter test========");
TimeUnit.SECONDS.sleep(10L);
дополнение pom.xml добавить:
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
по желанию:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
@EnableRetry
@SpringBootApplication
public class ApiApplication
это документ:
Добавьте это, если это может кому-то помочь. Я получал сброс соединения с помощью симуляции, так как на этом порту выполнялся какой-то неизвестный процесс. Попробуйте сменить порт. Обратитесь к этому, чтобы найти процесс, запущенный на порту
Я подготовил сообщение в блоге об использовании Spring Retry с методами Feign Client. Вы можете рассмотреть возможность проверки почты . Все действия описаны в посте.
Я решил это, создав оболочку поверх ServiceClient.
@Configuration
public class ServiceClient {
@Autowired
ServiceFeignClient serviceFeignClient;
@Retryable(value = { ClientReprocessException.class }, maxAttemptsExpression = "#{${retryMaxAttempts}}", backoff = @Backoff(delayExpression = "#{${retryDelayTime}}"))
public void addPayment( AddPaymentRequest addPaymentRequest){
return serviceFeignClient.addPayment(addPaymentRequest);
}
}