Risks of using Apache CloseableHttpClient in a Singleton
Asked Answered
B

1

7

I'm using Apache Http Client 4.5.3 and currently refactoring some code.

Currently I have a singleton Util that has several methods whose responsibility is to hit an API with gets, posts, patches, etc. Previously, we had been using an HttpClientBuilder to construct a CloseableHttpClient object for every call of every method. Roughly, the architecture for the Singleton is something like this:

import com.google.gson.Gson
import org.apache.http.client.methods.{HttpGet, HttpPost}
import org.apache.http.entity.StringEntity
import org.apache.http.impl.client.{CloseableHttpClient, HttpClientBuilder}
import org.apache.http.util.EntityUtils
import org.json4s.DefaultFormats
import org.json4s.jackson.JsonMethods.parse

object ApiCallerUtil {

  case class StoreableObj(name:String, id:Long)
  case class ResponseKey(key:Long)

  def getKeyCall(param:String): ResponseKey = {
    implicit val formats = DefaultFormats
    val get = new HttpGet("http://wwww.someUrl.com/api/?value=" + param)
    val client:CloseableHttpClient = HttpClientBuilder.create().build()
    val response = client.execute(get)
    try {
      val entity = response.getEntity
      val entityStr = EntityUtils.toString(entity)
      parse(entityStr).extract[ResponseKey]
    } finally {
      response.close()
      client.close()
    }
  }

  def postNewObjCall(param:String, i:Long): Boolean = {
    val post = new HttpPost(("http://wwww.someUrl.com/api/createNewObj"))
    val client = HttpClientBuilder.create().build()
    post.setHeader("Content-type", "application/json")
    val pollAsJson = new Gson().toJson(StoreableObj(param, i))
    post.setEntity(new StringEntity(pollAsJson))
    val response = client.execute(post)
    try {
      if (response.getStatusLine.getStatusCode < 300) true else false
    } finally {
      response.close()
      client.close()
    }
  }

  //... and so on

}

Notes about how this is used - we have many classes all over our system that use this Singleton Util to make calls to the API. This Singleton will go through short periods of heavy use where several classes will hit the same calls with heavy frequency (up to @1000 of times within several minute periods), and also periods where it is hit several times over a long period of time (once or twice an hour), or not at all for hours at a time. Also, all the URLs it hits will start with the same URL (e.g. www.someUrl.com/api/)

But I'm wondering if it would make sense to implement it where the val client = HttpClientBuilder.create().build is called once as a private val for a in-object-only accessible variable. This way it is only created once, upon instantiation of the object. Here's where I pause, the Apache documentation does say these two things:

1.2.1. [Closeable]HttpClient implementations are expected to be thread safe. It is recommended that the same instance of this class is reused for multiple request executions.

1.2.2. When an [Closeable]HttpClient instance is no longer needed and is about to go out of scope it is important to shut down its connection manager to ensure that all connections kept alive by the manager get closed and system resources allocated by those connections are released.

I've read through most of the documentation, but don't have a solid answer to the following:

  1. Are there any risks of having the CloseableHttpClient instance as private global variable? I'm worried something may get shut down if it's stale and that I'd have to resinstantiate it after a period of time, or, in the cases of heavy use, it would create too much of a bottleneck. Per the #1.2.2 above, the variable will "never" go out of scope, since it's a singleton object. But since I'm building just the client and passing it the HttpRequest objects as I go, and not connecting it to the API outside of the request alone, it seems it shouldn't matter.

  2. Due to the nature of how this ApiCallerUtil Singleton is used, would it be wise to perhaps make use of their HttpClientConnectionManager or. PoolingHttpClientConnectionManager to maintain a steady connection to www.someUrl.com/api/? Will the performance increase be worth it? So far, the current implementation doesn't seem to have any drastic performance drawbacks.

Thanks for any feedback!

Berneicebernelle answered 22/5, 2018 at 19:26 Comment(0)
W
12
  1. There are none (based on my 15+ years of experience with HttpClient).

  2. This really depends on various factors (overhead of TLS session handshake, and so on). I imagine one would really want to ensure that series of related requests get executed over a persistent connection. During an extended period of inactivity one may want to evict all idle connections from the connection pool. This has an added benefit of reducing the chance of running into a stale (half-closed) connection problem.

Widmer answered 23/5, 2018 at 7:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.