#spring-boot #wiremock
#весенняя загрузка #wiremock
Вопрос:
Я запускаю сервер wiremock в интеграционном тесте.
ИТ-передача в моем локальном, НО в каком-то случае произошла ошибка на сервере jenkins, ошибка
localhost:8089 failed to respond; nested exception is org.apache.http.NoHttpResponseException: localhost:8089 failed to respond
Я пытаюсь добавить sleep(3000)
в свой тест, который может устранить проблему, но я не знаю основной причины проблемы, поэтому обходной путь не является хорошей идеей
Я также пытаюсь использовать @AutoConfigureWireMock(port=8089)
для замены WireMockServer
для запуска сервера wiremock, что может решить проблему, НО я не знаю, как выполнить некоторую настройку сервера wiremock с помощью аннотации @AutoConfigureWireMock(port=8089)
.
Вот мой код для запуска сервера wiremock, есть предложения по исправлению «NoHttpResponseException»?
@ContextConfiguration(
initializers = ConfigFileApplicationContextInitializer.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
class BaseSpec extends Specification {
@Shared
WireMockServer wireMockServer
def setupSpec() {
wireMockServer = new WireMockServer(options().port(PORT).jettyHeaderBufferSize(12345)
.notifier(new ConsoleNotifier(new Boolean(System.getenv(“IT_WIREMOCK_LOG”) ?: ‘false’)))
.extensions(new ResponseTemplateTransformer(true)))
wireMockServer.start()
}
Ответ №1:
Apache HttpClient NoHttpResponseException
время от времени страдает. Это очень старая проблема.
В любом случае, я думаю, в вашем случае проблема может быть вызвана перезапуском сервера WireMock между тестами, и в то же время Apache HttpClient объединяет HTTP-соединения и пытается повторно использовать их между тестами. Если это так, есть два решения:
-
Отключите объединение HTTP-соединений в своих тестах. Это имеет смысл, потому что считается нормальным, что сервер WireMock может быть перезапущен во время выполнения тестов. Кроме того, создайте свои заглушки WireMock, чтобы они всегда отправлялись
"Connection": "close"
среди заголовков. Результат будет тот же. -
Переключитесь с Apache HttpClient на Square OkHttp. OkHttp, хотя по умолчанию он объединяет http-соединения, всегда может корректно восстанавливаться в таких ситуациях, как устаревшее соединение. К сожалению, библиотека от Apache не такая умная.
Ответ №2:
Кстати, как уже писал Г. Демецки, это не связано с Wiremock. Это связано с вашим сервером приложений, который вызывает wiremock. Сегодня принято повторно использовать соединение для повышения производительности в инфраструктуре микросервиса. Таким образом, connection-close-header, клиент с ограниченным запросом и т. Д. Бесполезны.
Проверьте http-клиент apache:
httpclient-4.5.2 — PoolingHttpClientConnectionManager
Обработка устаревших соединений была изменена в версии 4.4. Ранее код проверял каждое соединение по умолчанию перед его повторным использованием. Теперь код проверяет соединение только в том случае, если время, прошедшее с момента последнего использования соединения, превышает установленное время ожидания. Тайм-аут по умолчанию установлен на 2000 мс
Каждый раз, когда конечная точка wiremock была уничтожена, а новая была создана для нового тестового класса, требуется 2 секунды, пока ваше приложение не обнаружит, что предыдущее соединение разорвано и необходимо открыть новое. Если вы не подождете 2 секунды, может быть вызвано такое исключение NoHttpResponseException, зависит от последней проверки.
Так Thread.sleep(2000);
что выглядит некрасиво. Но это не так уж плохо, если мы знаем, зачем это требуется.
Комментарии:
1. Спасибо за эту полезную документацию — я не знал, что она установлена ровно на 2 секунды! КСТАТИ: спящий режим в течение 2 секунд в тестах — невероятно неэффективная идея, поэтому извините, но я не могу проголосовать 😉
2. Есть ли какое-либо решение этой проблемы, кроме использования 2-секундного тайм-аута между тестовыми классами? Я использую MockMvc для отправки запросов в WireMock, и у меня такая же проблема.
3. настройка http-клиента apache для его тестового экземпляра решила для меня эту проблему. Исправление заключалось в создании нового пула HttpClientConnectionManager и изменении времени ожидания с 2 секунд до 10 мс:
setValidateAfterInactivity(10)
как предложено в github.com/tomakehurst/wiremock/issues /…
Ответ №3:
Каждый раз, когда конечная точка wiremock уничтожается (потому что сервер wiremock перезапускается между тестами) и создается новая для нового теста, требуется 2 секунды (как указано в документации), пока приложение не обнаружит, что предыдущее http-соединение разорвано, и необходимо открыть новое.
Решение состоит в том, чтобы просто переопределить поведение подключения по умолчанию для каждого использования заглушки .withHeader("Connection", "close")
. Что-то вроде:
givenThat(get("/endpoint_path")
.withHeader("Authorization", equalTo(authHeader))
.willReturn(
ok()
.withBody(body)
.withHeader(HttpHeaders.CONNECTION, "close")
)
)
Также возможно сделать это глобально с помощью transformer:
public class NoKeepAliveTransformer extends ResponseDefinitionTransformer {
@Override
public ResponseDefinition transform(Request request,
ResponseDefinition responseDefinition,
FileSource files,
Parameters parameters) {
return ResponseDefinitionBuilder
.like(responseDefinition)
.withHeader(CONNECTION, "close")
.build();
}
@Override
public String getName() {
return "keep-alive-disabler";
}
}
Тогда этот преобразователь должен быть зарегистрирован при создании сервера wiremock:
new WireMockServer(
options()
.port(port)
.extensions(NoKeepAliveTransformer.class)
)
Ответ №4:
Решение, которое сработало для нас в этой ситуации, просто добавило повторную попытку в клиент apache:
@Configuration
public class FeignTestConfig {
@Bean
@Primary
public HttpClient testClient() {
return HttpClientBuilder.create().setRetryHandler((exception, executionCount, context) -> {
if (executionCount > 3) {
return false;
}
return exception instanceof org.apache.http.NoHttpResponseException || exception instanceof SocketException;
}).build();
}
}
Исключение сокета также существует, потому что иногда это исключение выдается вместо NoHttpResponse