Spring RestTemplate & AsyncRestTemplate with Netty4 hangs forever

Very simple setup:

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>demo-rest-client</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>demo-rest-client</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.4.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.5.Final</version>
        </dependency>
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-buffer</artifactId>
            <version>4.1.5.Final</version>
        </dependency>
        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
            <version>3.4.1</version>
        </dependency>
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-core</artifactId>
            <version>9.3.1</version>
        </dependency>
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-hystrix</artifactId>
            <version>9.3.1</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

And a test case to demonstrate different ways to use AsyncRestTemplate:

SampleTests.java

package com.example;

import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandProperties;
import feign.RequestLine;
import feign.hystrix.HystrixFeign;
import feign.hystrix.SetterFactory;
import org.junit.Test;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.Netty4ClientHttpRequestFactory;
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.web.client.AsyncRestTemplate;
import org.springframework.web.client.RestTemplate;

public class SampleTests {

    private static final String URL = "https://api.github.com/users/octocat";
    private static final int DEFAULT_SLEEP_MILLIS = 20;
    private static final int DEFAULT_TIMEOUT = 10000;

    @Test(timeout = DEFAULT_TIMEOUT)
    public void syncRestNetty() throws Exception {
        RestTemplate restTemplate = new RestTemplate(new Netty4ClientHttpRequestFactory());
        ResponseEntity<String> response = restTemplate.getForEntity(URL, String.class);
        System.out.println("response = " + response);
    }

    @Test(timeout = DEFAULT_TIMEOUT)
    public void asyncRestNetty() throws Exception {
        AsyncRestTemplate restTemplate = new AsyncRestTemplate(new Netty4ClientHttpRequestFactory());
        ListenableFuture<ResponseEntity<String>> listenableFuture = restTemplate.getForEntity(URL, String.class);
        listenableFuture.addCallback(result -> System.out.println("result = " + result), Throwable::printStackTrace);
        while (!listenableFuture.isDone()) {
            Thread.sleep(DEFAULT_SLEEP_MILLIS);
        }
        System.out.println("the end");
    }

    @Test
    public void asyncRestOkHttp() throws Exception {
        AsyncRestTemplate restTemplate = new AsyncRestTemplate(new OkHttp3ClientHttpRequestFactory());
        ListenableFuture<ResponseEntity<String>> listenableFuture = restTemplate.getForEntity(URL, String.class);
        listenableFuture.addCallback(result -> System.out.println("result = " + result), Throwable::printStackTrace);
        while (!listenableFuture.isDone()) {
            Thread.sleep(DEFAULT_SLEEP_MILLIS);
        }
        System.out.println("the end");
    }

    @Test
    public void asyncRestHystrixFeign() throws Exception {
        GitHub gitHub = HystrixFeign.builder()
                .setterFactory((target, method) -> new SetterFactory.Default().create(target, method).andCommandPropertiesDefaults(HystrixCommandProperties.defaultSetter().withExecutionTimeoutInMilliseconds(10000)))
                .target(GitHub.class, "https://api.github.com");
        HystrixCommand<String> command = gitHub.octocatAsync();
        command.toObservable().subscribe(result -> System.out.println("result = " + result), Throwable::printStackTrace);
        while (!command.isExecutionComplete()) {
            Thread.sleep(DEFAULT_SLEEP_MILLIS);
        }
        System.out.println("command.getExecutionTimeInMilliseconds() = " + command.getExecutionTimeInMilliseconds());
        System.out.println("the end");
    }

    interface GitHub {
        @RequestLine("GET /users/octocat")
        HystrixCommand<String> octocatAsync();
    }
}

When you try to run tests that use Netty, they just freeze forever. (To see this, remove the JUnit timeout limit). But if I run the same code with other clients, everything works as expected.

I tried different versions of Spring Boot and Netty, but failed. And from the magazines everything looks fine.

What am I missing here?

EDIT: Opened a ticket https://jira.spring.io/browse/SPR-14744 , as stated in Spring Gitter

-2: , Netty, , ( API Github http), .

+4
1

factory Netty Sslcontext?

Netty4ClientHttpRequestFactory nettyFactory = new Netty4ClientHttpRequestFactory();
nettyFactory.setSslContext(SslContextBuilder.forClient().build());
AsyncRestTemplate restTemplate = new AsyncRestTemplate(nettyFactory);

https; , , HTTP 400.

throwable HttpClientErrorException, , exception.getResponseBodyAsString().

+1

Source: https://habr.com/ru/post/1655478/


All Articles