spring Wiremock -有时会抛出“软件导致连接中止:recv失败”

h22fl7wq  于 2023-04-19  发布在  Spring
关注(0)|答案(4)|浏览(182)

我在使用Spring和Wiremock进行集成测试时遇到了一个非常奇怪的情况:突然,一个特定的测试开始间歇性地失败。下面是错误的片段:

org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://localhost:10314/my/endpoint": Software caused connection abort: recv failed; nested exception is java.net.SocketException: Software caused connection abort: recv failed
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:785) ~[spring-web-5.3.7.jar:5.3.7]
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:711) ~[spring-web-5.3.7.jar:5.3.7]
    at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:468) ~[spring-web-5.3.7.jar:5.3.7]
... more logs here ...

上下文如下:我添加了一个新的测试,它使用wiremock来存根响应:

wireMockServer.stubFor(WireMock.post("/my/endpoint")
    .withRequestBody(containing(aJsonRequestBodyHere))
    .willReturn(aResponse()
            .withBody(aJsonResponseHere)
            .withStatus(HttpStatus.OK.value())
            .withHeader(HttpHeader.CONTENT_TYPE.toString(), CONTENT_TYPE_APPLICATION_JSON)));

对该存根端点的调用如下所示:

given()
    .when()
    .get("my/endpoint")
    .then()
    .body(containsString(theExpectedJsonResponse)))
    .statusCode(200);

奇怪之处

  • 同样的测试在我的本地机器上运行没有任何问题-如果单独运行
  • 在我的机器上运行所有测试时,有时相同的测试会失败,有时不会
  • 只有这个测试每次都失败;无其他测试失败
  • 当在Jenkins上运行测试时,它会100%失败
jtw3ybtb

jtw3ybtb1#

在对此进行了一些挖掘之后,我发现了thisthis文章,它们几乎100%地描述了我的情况。

根本原因似乎是测试执行得太快-可能是那些没有做太多事情的测试-Wiremock没有时间为下一个测试正确设置。我已经通过在测试开始时添加Thread.sleep(2000)来测试这个假设,然后运行所有测试多次-所有测试都通过了,没有问题。
the first article表示:注册一个Transformer类,它将拦截所有响应并向它们添加Connection=close头。
详情:我添加了一个Transformer类,它扩展了ResponseDefinitionTransformer,并在每个响应上添加了Connection头。

Transformer类(取自the first article):

public class NoKeepAliveTransformer extends ResponseDefinitionTransformer {

    @Override
    public ResponseDefinition transform(Request request, ResponseDefinition responseDefinition, FileSource files, Parameters parameters) {
        return ResponseDefinitionBuilder.like(responseDefinition)
                .withHeader(HttpHeaders.CONNECTION, "close")
                .build();
    }

    @Override
    public String getName() {
        return "keep-alive-disabler";
    }
}

配置类:

@Configuration
public class WiremockConfiguration {

    @Bean
    WireMockConfigurationCustomizer optionsCustomizer() {
        return options -> options.extensions(NoKeepAliveTransformer.class);
    }
}
qojgxg4l

qojgxg4l2#

TL;DR

在响应上使用.withHeader(HttpHeaders.CONNECTION, "close")的解决方法修复了以下问题:

org.springframework.web.client.ResourceAccessException:
"I/O error on POST request for "http://127.0.0.1:8080/wiremock/my_stubbed_service": Software caused connection abort: recv failed"

使用com.github.tomakehurst:wiremock:2.27.2和com.github.tomakehurst:wiremock-jre 8:2.30.1进行测试

7tofc5zh

7tofc5zh3#

在使用WireMock服务器通过Feign客户端发送请求时,在集成测试中遇到了同样的问题。
根据Tom在前面的回答中的评论,决定修复客户端的配置,以便假装重试发送请求。找到了this文章中描述的解决方案。

Feign最简单的方法是添加@Configuration类,其中包含feign.Retryer@Bean

@Configuration
public class FeignConfig {
    @Bean
    public Retryer retryer() {
        return new Retryer.Default(200L,1000L,5);
    }
}
fv2wmkja

fv2wmkja4#

从这个帖子中,他们推荐了以下对我有效的解决方法:

stubFor(withAuth(get(urlEqualTo(EXPECTED_ENDPOINT))).willReturn(aResponse()
        .withStatus(HttpStatus.OK.value())
        .withHeader(HttpHeaders.CONNECTION, "close")
        .withBody(objectMapper.writeValueAsString(responseObject))
));

只需使用.withHeader(HttpHeaders.CONNECTION, "close")覆盖每个存根的默认keep-alive连接行为。

相关问题