title: How to Properly Close Raw RestClient When Using Elastic Search 5.5.0 for Optimal Performance?
body: <p>Am using a Spring Boot 1.5.4.RELEASE Microservice to connect to an ElasticSearch 5.5.0 instance using the low level Rest Client that ElasticSearch provides.</p>
  
  <p>pom.xml</p>
  
  <pre><code>&lt;parent&gt;
      &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
      &lt;artifactId&gt;spring-boot-starter-parent&lt;/artifactId&gt;
      &lt;version&gt;1.5.4.RELEASE&lt;/version&gt;
  &lt;/parent&gt;
  
  &lt;dependencies&gt;
      &lt;!-- Spring --&gt;
      &lt;dependency&gt;
          &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
          &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;
      &lt;/dependency&gt;
  
      &lt;dependency&gt;
          &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
          &lt;artifactId&gt;spring-boot-starter-test&lt;/artifactId&gt;
          &lt;scope&gt;test&lt;/scope&gt;
      &lt;/dependency&gt;
  
      &lt;!-- Elasticsearch --&gt;
      &lt;dependency&gt;
          &lt;groupId&gt;org.elasticsearch&lt;/groupId&gt;
          &lt;artifactId&gt;elasticsearch&lt;/artifactId&gt;
          &lt;version&gt;5.5.0&lt;/version&gt;
      &lt;/dependency&gt;
  
      &lt;dependency&gt;
          &lt;groupId&gt;org.elasticsearch.client&lt;/groupId&gt;
          &lt;artifactId&gt;transport&lt;/artifactId&gt;
          &lt;version&gt;5.5.0&lt;/version&gt;
      &lt;/dependency&gt;
  
      &lt;!-- Apache Commons --&gt;
      &lt;dependency&gt;
          &lt;groupId&gt;org.apache.commons&lt;/groupId&gt;
          &lt;artifactId&gt;commons-lang3&lt;/artifactId&gt;
          &lt;version&gt;3.6&lt;/version&gt;
      &lt;/dependency&gt;
  
      &lt;!-- Jackson --&gt;
      &lt;dependency&gt;
          &lt;groupId&gt;com.fasterxml.jackson.core&lt;/groupId&gt;
          &lt;artifactId&gt;jackson-core&lt;/artifactId&gt;
          &lt;version&gt;2.8.9&lt;/version&gt;
      &lt;/dependency&gt;
  
      &lt;dependency&gt;
          &lt;groupId&gt;com.fasterxml.jackson.core&lt;/groupId&gt;
          &lt;artifactId&gt;jackson-databind&lt;/artifactId&gt;
          &lt;version&gt;2.8.9&lt;/version&gt;
      &lt;/dependency&gt;
  
      &lt;dependency&gt;
          &lt;groupId&gt;com.fasterxml.jackson.core&lt;/groupId&gt;
          &lt;artifactId&gt;jackson-annotations&lt;/artifactId&gt;
          &lt;version&gt;2.8.9&lt;/version&gt;
      &lt;/dependency&gt;
  
      &lt;!-- Log4j --&gt;
      &lt;dependency&gt;
          &lt;groupId&gt;log4j&lt;/groupId&gt;
          &lt;artifactId&gt;log4j&lt;/artifactId&gt;
          &lt;version&gt;1.2.17&lt;/version&gt;
      &lt;/dependency&gt;
  
      &lt;!-- JUnit --&gt;
      &lt;dependency&gt;
          &lt;groupId&gt;junit&lt;/groupId&gt;
          &lt;artifactId&gt;junit&lt;/artifactId&gt;
          &lt;version&gt;4.11&lt;/version&gt;
          &lt;scope&gt;test&lt;/scope&gt;
      &lt;/dependency&gt;
  
      &lt;!-- Swagger --&gt;
      &lt;dependency&gt;
          &lt;groupId&gt;io.springfox&lt;/groupId&gt;
          &lt;artifactId&gt;springfox-swagger2&lt;/artifactId&gt;
          &lt;version&gt;2.6.1&lt;/version&gt;
          &lt;scope&gt;compile&lt;/scope&gt;
      &lt;/dependency&gt;
  
      &lt;dependency&gt;
          &lt;groupId&gt;io.springfox&lt;/groupId&gt;
          &lt;artifactId&gt;springfox-swagger-ui&lt;/artifactId&gt;
          &lt;version&gt;2.6.1&lt;/version&gt;
          &lt;scope&gt;compile&lt;/scope&gt;
      &lt;/dependency&gt;
  &lt;/dependencies&gt;
  </code></pre>
  
  <p>Everything is setup correctly but after a bunch of hits, client apps were reporting an HTTP 500 error and this is what appeared in the log files:</p>
  
  <pre><code>java.io.IOException: Too many open files
          at sun.nio.ch.IOUtil.makePipe(Native Method) ~[na:1.8.0_141]
          at sun.nio.ch.EPollSelectorImpl.&lt;init&gt;(EPollSelectorImpl.java:65) ~[na:1.8.0_141]
          at sun.nio.ch.EPollSelectorProvider.openSelector(EPollSelectorProvider.java:36) ~[na:1.8.0_141]
          at java.nio.channels.Selector.open(Selector.java:227) ~[na:1.8.0_141]
          at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor.&lt;init&gt;(AbstractMultiworkerIOReactor.java:142) ~[httpcore-nio-4.4.5.jar!/:4.4.5]
          at org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor.&lt;init&gt;(DefaultConnectingIOReactor.java:79) ~[httpcore-nio-4.4.5.jar!/:4.4.5]
          at org.apache.http.impl.nio.client.IOReactorUtils.create(IOReactorUtils.java:43) ~[httpasyncclient-4.1.3.jar!/:4.1.3]
          at org.apache.http.impl.nio.client.HttpAsyncClientBuilder.build(HttpAsyncClientBuilder.java:666) ~[httpasyncclient-4.1.3.jar!/:4.1.3]
          at org.elasticsearch.client.RestClientBuilder.createHttpClient(RestClientBuilder.java:202) ~[rest-5.5.0.jar!/:5.5.0]
          at org.elasticsearch.client.RestClientBuilder.build(RestClientBuilder.java:180) ~[rest-5.5.0.jar!/:5.5.0]
          at com.myapp.controller.SearchController.getSearchQueryResults(SearchController.java:94) ~[classes!/:1.0]
  </code></pre>
  
  <p>Inside SearchController (the second line after the // comment is line 94):</p>
  
  <pre><code>@RestController
  @RequestMapping("/api/v1")
  public class SearchController {
  
      @RequestMapping(value = "/search", method = RequestMethod.GET, produces="application/json" )
      public ResponseEntity&lt;Object&gt; getSearchQueryResults(@RequestParam(value = "criteria") String criteria) throws IOException {
  
          // Setup HTTP Headers
          HttpHeaders headers = new HttpHeaders();
          headers.add("Content-Type", "application/json");
  
          // Setup RestClient
          RestClient restClient = RestClient.builder(new HttpHost("localhost", 9200))
          .setRequestConfigCallback(new RestClientBuilder.RequestConfigCallback() {
              @Override
              public RequestConfig.Builder customizeRequestConfig(RequestConfig.Builder requestConfigBuilder) {
                  return requestConfigBuilder.setConnectTimeout(5000).setSocketTimeout(60000);
              }
          }).setMaxRetryTimeoutMillis(60000).build();
  
          // Setup query and send and return ResponseEntity...
  
      }
  }
  </code></pre>
  
  <p>Its obvious that what it was never closed after calling the restClient.performRequest() method...</p>
  
  <p>So, I put this into my code:</p>
  
  <pre><code>Response response = null;
  try {
     // Submit Query and Obtain Response
     response = restClient.performRequest("POST", endPoint,  Collections.singletonMap("pretty", "true"), entity);
  }
  catch (IOException e) {
     LOG.error("\n\n\tException: " + e + "\n\n");
     e.printStackTrace();
  }
  finally {
     restClient.close();
  }
  </code></pre>
  
  <p>Read on Elastic Search's documentation that the RestClient class is thread-safe...</p>
  
  <p>Also, read about the restClient.performRequestAsync() method but am somewhat inexperienced with threads and the description inside the documentation is vague. </p>
  
  <p>Question(s):</p>
  
  <ol>
  <li><p>Is my solution the best way to handle and close a bunch of socket resources?</p></li>
  <li><p>Would appreciate if someone could show me a better way to use the low level RestClient with Elastic Search in sense that it won't cause the same issue with the socket resources not being freed resulting in an HTTP 500. Should I be using restClient.performRequestAsync? Could someone please provide an example?</p></li>
  </ol>
  
  <p>Thank you for taking the time to read this...</p>