title: Spring Boot Rest Template Keep Connection Alive
body: <p>I have a Spring Boot application that is creating a request to an external system. The external system is responding after some time, 3-4 minutes. I would like to keep the connection open until i receive an response from the remote API. I tried using webflux, i tried setup the connection timeout for my application in application.yml file. I could make the application to wait for a response more than 2 minutes. Some code that i have tried</p>
  <pre><code>@Configuration
  public class RestConfigurations {
  @Bean(name = &quot;restTemplate&quot;)
  public RestTemplate getRestTemplate(RestTemplateBuilder restTemplateBuilder) {
      RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());
  
      // Error handler
      restTemplate.setErrorHandler(new CustomRestTemplateErrorHandler());
  
      // Media converters
      MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
      converter.setSupportedMediaTypes(Arrays.asList(
              MediaType.APPLICATION_JSON,
              MediaType.TEXT_PLAIN,
              MediaType.TEXT_HTML));
      restTemplate.getMessageConverters().add(converter);
  
      return restTemplate;
  }
  
  private ClientHttpRequestFactory getClientHttpRequestFactory() {
      int connectionTimeout = 15*60000; // milliseconds
      int socketTimeout = 15*60000; // milliseconds
      RequestConfig config = RequestConfig.custom()
              .setConnectTimeout(connectionTimeout)
              .setConnectionRequestTimeout(connectionTimeout)
              .setSocketTimeout(socketTimeout)
              .build();
      CloseableHttpClient client = HttpClientBuilder
              .create()
              .setDefaultRequestConfig(config)
              .setKeepAliveStrategy(connectionKeepAliveStrategy())
              .build();
      return new HttpComponentsClientHttpRequestFactory(client);
  }
  
  public HttpComponentsClientHttpRequestFactory getHttpClientFactory() {
      HttpComponentsClientHttpRequestFactory httpClientFactory = new 
     HttpComponentsClientHttpRequestFactory(
              HttpClients.createDefault()
      );
      httpClientFactory.setConnectTimeout(15 * 600000);
      httpClientFactory.setReadTimeout(15 * 600000);
      httpClientFactory.setConnectionRequestTimeout(15 * 600000);
      return httpClientFactory;
  }
  
  public ClientHttpRequestFactory createRequestFactory(){
      PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
      connectionManager.setMaxTotal(400);
      connectionManager.setDefaultMaxPerRoute(200);
      RequestConfig requestConfig = RequestConfig
              .custom()
              .setConnectionRequestTimeout(5000)
              .setSocketTimeout(10000)
              .build();
      CloseableHttpClient httpClient = HttpClients
              .custom()
              .setConnectionManager(connectionManager)
              .setKeepAliveStrategy(connectionKeepAliveStrategy())
              .setDefaultRequestConfig(requestConfig)
              .build();
      return new HttpComponentsClientHttpRequestFactory(httpClient);
  }
  
  
  private ConnectionKeepAliveStrategy connectionKeepAliveStrategy() {
      return (response,context)-&gt; {
          HeaderElementIterator it = new BasicHeaderElementIterator(
                  response.headerIterator(HTTP.CONN_KEEP_ALIVE));
          while (it.hasNext()) {
              HeaderElement he = it.nextElement();
              String param = he.getName();
              String value = he.getValue();
              if ( value != null &amp;&amp; param.equalsIgnoreCase(&quot;timeout&quot;)){
                  try {
                      return Long.parseLong(value) * 999999999;
                  } catch (NumberFormatException exception) {
                      exception.printStackTrace();
                  }
              }
          }
  
          return 15 * 60000;
      } ;
  }
  
  @Bean(name = &quot;webClient&quot;)
  public WebClient webClient() {
      TcpClient tcpClient = TcpClient
              .create()
              .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 60000 * 15)//15 minutes
              .doOnConnected(connection -&gt; {
                  connection.addHandlerLast(new ReadTimeoutHandler(15, TimeUnit.MINUTES));
                  connection.addHandlerLast(new WriteTimeoutHandler(15, TimeUnit.MINUTES));
              });
  
      return WebClient.builder()
              .clientConnector(new ReactorClientHttpConnector(HttpClient.from(tcpClient).wiretap(true)))
              .build();
  }
  </code></pre>
  <p>None of this configs worked. I tried using okhttpclient like this.</p>
  <pre><code>public class OkHttpClientFactoryImpl implements OkHttpClientFactory {
    @Override 
    public OkHttpClient.Builder createBuilder(boolean disableSslValidation) {
       OkHttpClient.Builder builder = new OkHttpClient.Builder();
       ConnectionPool okHttpConnectionPool = new ConnectionPool(50, 30, TimeUnit.SECONDS);
       builder.connectionPool(okHttpConnectionPool);
      builder.connectTimeout(20, TimeUnit.MINUTES);
      builder.readTimeout(20, TimeUnit.MINUTES);
      builder.writeTimeout(20, TimeUnit.MINUTES);
      builder.retryOnConnectionFailure(false);
      return builder;
     }
   }
  
  @Bean
  @Qualifier(&quot;OKSpringCommonsRestTemplate&quot;)
  public ClientHttpRequestFactory createOKCommonsRequestFactory() {
      OkHttpClientFactoryImpl httpClientFactory = new OkHttpClientFactoryImpl();
      OkHttpClient client = httpClientFactory.createBuilder(false).build();
      return new OkHttp3ClientHttpRequestFactory(client);
  }
  </code></pre>
  <p>It did not work. I don't know what could cause the connection to close other than the things i've setup.</p>
  <p>After receiving an answer, i tried :</p>
  <pre><code>HttpRequest request = HttpRequest.newBuilder()
              .uri(URI.create(url))
              .timeout(Duration.ofMinutes(10))
              .header(&quot;Content-Type&quot;, &quot;application/json&quot;)
              .POST(HttpRequest.BodyPublishers.ofString(json))
              .build();
  
      HttpClient client= HttpClient.newHttpClient();
      try {
          client.send(request, HttpResponse.BodyHandlers.ofString());
      } catch (IOException | InterruptedException e) {
          e.printStackTrace();
      }
  </code></pre>
  <p>The result is the same. After 2 minutes i get an error saying java.io.IOException: HTTP/1.1 header parser received no bytes</p>