Рубрики
Без рубрики

Разумная конфигурация симулированного клиента

Притворные клиенты облегчают написание клиента restful на основе аннотаций Spring, которые вы уже знаете…. Помеченный как java, весна, притворство.

Притворные клиенты облегчают написание клиента restful на основе аннотаций Spring, которые вы уже знаете. Он также включает интеграцию с множеством других библиотек netflix и хорошими шаблонами микросервисов (такими как обнаружение служб, балансировка нагрузки и автоматические выключатели).

Feign настраивается, но обычно вы хотите изменить конфигурацию, прежде чем использовать ее для вызовов службы в службу.

Регистрация

Вы захотите посмотреть, какие запросы делаются. Для этого вам необходимо сделать две вещи: установить уровень регистратора для конфигурации feign в вашем приложении.yml и установите уровень ведения журнала клиентского класса feign для ОТЛАДКИ.

logger.level:
  root: INFO 
  com.example.clients.InvoiceClient: DEBUG


feign:
  client:
    config:
      default:
        loggerLevel: basic

Вы можете установить уровень регистратора до полного если вы тоже хотите видеть заголовки и тела ответов в журналах.

Следует ли декодировать 404-е

Если вы хотите, чтобы при получении вашим клиентом ответа 404 “Не найдено” возникало исключение FeignException, вы можете установить для декодера 404 значение false, которое используется по умолчанию. В противном случае, если вы установите для декодера 404 значение true, вы получите значение null в качестве ответа или необязательно, если вы включили типы возвращаемых данных в опции.

Декодер ошибок

Как бороться с ошибками – это самое важное, потому что вы не будете возвращать разумные ответы своему клиенту, если он у вас есть, и облегчите расследование, когда что-то пойдет не так. Я считаю, что разумное, что нужно сделать, это:

  1. повторите попытку при любой ошибке сервера (статус > 499)
  2. возвращает ту же ошибку сервера когда повторная попытка исчерпана
  3. повторите попытку на любом 429 или когда установлен заголовок Повторной попытки
  4. возвращайте 500 при возникновении любой другой ошибки клиента
  5. зарегистрируйте ошибку со статусом, какой метод ее вызвал и орган реагирования

Это довольно внушительный список требований. Давайте создадим декодер ошибок, который удовлетворяет этому:

public class CustomErrorDecoder implements ErrorDecoder {

    private static final Logger LOG = LoggerFactory.getLogger(CustomErrorDecoder.class);
    private ErrorDecoder defaultDecoder = new ErrorDecoder.Default();

    @Override
    public Exception decode(String methodKey, Response response) {
        //Requirement 5: log error first and include response body
        try {
            LOG.error("Got {} response from {}, response body: {}", response.status(), methodKey, IOUtils.toString(response.body().asReader()));
        } catch (IOException e) {
            LOG.error("Got {} response from {}, response body could not be read", response.status(), methodKey);
        }
        Exception defaultException = defaultDecoder.decode(methodKey, response);
        if (defaultException instanceof RetryableException.class) {
            //Requirement 3: retry when Retry-After header is set
            //Will be true if Retry-After header is set e.g. in case of 429 status
            return defaultException;
        }
        if (HttpStatus.valueOf(response.status()).is5xxServerError()) {
            //Requirement 1: retry on server error
            return new RetryableException("Server error", response.request().httpMethod(), new ServerErrorResponseFromOtherSystemException(HttpStatus.valueOf(response.status()), defaultException), null);
        } else {
            //Requirement 4: return 500 on client error
            return new ClientErrorResponseFromOtherSystemException("Client error " + response.status() + " from calling other system", defaultException);
        }
    }

}

И исключения в бросках:

//Requirement 4: return 500 on client error
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public class ClientErrorResponseFromOtherSystemException extends Exception {

    public ThirdPartyClientErrorResponseException(String message, Exception exception) {
        super(message, exception);
    }
}

public class ServerErrorResponseFromOtherSystemException extends Exception {
    private HttpStatus responseStatusFromOtherSystem;

    public ServerErrorResponseFromOtherSystemException(HttpStatus httpStatus, Exception exception) {
        this.responseStatusFromOtherSystem = httpStatus;
        super(message, exception);
    }

    public HttpStatus getStatus() {
        return responseStatusFromOtherSystem;
    }
}

Аннотация @ResponseStatus означает, что spring вернет этот статус, когда аннотированное исключение достигнет контроллера. Чтобы определить статус ответа Ответ на ошибку сервера От другого SystemException нам нужен обработчик исключений для контроллера:

@RestController
public class InvoiceController {

    //Handler methods

    @ExceptionHandler(ServerErrorResponseFromOtherSystemException.class)
    public void ResponseEntity handleServerErrorResponseException(ServerErrorResponseFromOtherSystemException ex) {
        //Requirement 2: return the same error when retry is exhausted
        return ResponseEntity.status(exception.getStatus()).build();
    }

}

Чтобы притвориться, что вы используете повторитель, его нужно будет выставить в виде боба. Чтобы иметь возможность настроить политику распространения исключений на разворачивание, нам также необходимо предоставить конструктор симуляции с нашими настройками в качестве компонента. Смотрите пример ниже:

@Bean
public Retryer retryer() {
    return new Retryer.Default();
}

@Bean
public Feign.Builder feignBuilder(Retryer retryer) {
    return Feign.builder()
            .exceptionPropagationPolicy(ExceptionPropagationPolicy.UNWRAP)
            .errorDecoder(new ServerErrorRetryingErrorDecoder())
            .retryer(retryer);
}

Установка политики распространения исключений на разворачивание означает, что исключение внутри Повторяющегося исключения будет создаваться при исчерпании повторных попыток, позволяя создавать исключения для конкретных приложений, а затем обрабатываться обработчиками исключений (опять же, при условии, что вы используете Spring MVC).

Изящная обработка ошибок имеет важное значение, и создание ее с самого начала является хорошей практикой – не ждите, пока клиенты заметят, что системы сторонних производителей выходят из строя. Я обнаружил, что даже самые надежные сторонние системы могут иногда прерывать работу и возвращать 502. Это случилось со мной на производстве, где произошла ошибка шлюза, которую я никогда не видел в других средах. К счастью, я внедрил этот механизм повторной попытки, и запрос был повторен, и клиент продолжил путешествие после небольшого ожидания.

Оригинал: “https://dev.to/philhardwick/sensible-feign-client-configuration-ma3”