【问题标题】:Wiremock - sometimes it throws "Software caused connection abort: recv failed"Wiremock - 有时它会抛出“软件导致连接中止:recv failed”
【发布时间】:2021-08-25 19:48:40
【问题描述】:

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

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% 失败

【问题讨论】:

    标签: spring integration-testing wiremock


    【解决方案1】:

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

    根本原因似乎是测试执行速度过快——也许是那些没有做太多事情的测试——而 Wiremock 没有时间为下一次测试正确设置。 我已经通过在测试开始时添加Thread.sleep(2000) 来测试这个假设,然后多次运行所有测试 - 所有测试都顺利通过。

    解决方案the first article 中提出:注册一个Transformer 类,该类将拦截所有响应并向它们添加Connection=close 标头。

    更多细节:我添加了一个扩展ResponseDefinitionTransformerTransformer 类,并在每个响应中添加了Connection 标头。然后我创建了@Configuration 注释类并注册了这个Transformer

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

    【讨论】:

    • 这里的根本原因可能不是 WireMock 没有准备好,因为它会阻塞直到完全启动。您的 HTTP 客户端(在这种情况下为底层 RestAssured)池连接的方式更有可能是问题,这就是添加 Connection:close 解决此问题的原因。我建议尝试在客户端的配置中解决此问题,而不是通过 WireMock 扩展,方法是禁用连接池或启用陈旧连接检查。
    【解决方案2】:

    在使用 WireMock 服务器通过 Feign 客户端发送请求时,在集成测试中遇到了同样的问题。

    根据汤姆在上一个答案中的评论决定修复客户端的配置,以便 feign 重试发送请求。找到this文章中描述的解决方案。

    Feign 最简单的方法是添加@Configuration 类和feign.Retryer @Bean

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

    【讨论】:

    • 即使它可以解决问题(例如,它会重试直到它没有收到重置连接),但它感觉更像是一个黑客,因为它没有解决根本问题。
    【解决方案3】:

    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-jre8:2.30.1

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-02-05
      • 2013-08-24
      • 2019-07-28
      • 2012-04-15
      • 2010-09-13
      • 2012-02-20
      • 2011-02-03
      • 1970-01-01
      相关资源
      最近更新 更多