The first line solution to consume HTTP-based services in Scala world is to use akka-http. From the three provided levels of the API, a Host-Level Client-Site API is a quite natural choice for service clients. Basically, it just provides a pool of connections to specified HTTP service. Here is an example code from akka documentation which shows how we could use akka-http to send a single request to our service:

import akka.http.scaladsl.Http
import akka.http.scaladsl.model._

import scala.concurrent.Future
import scala.util.Try

implicit val system = ActorSystem()
implicit val materializer = ActorMaterializer()

// construct a pool client flow with context type `Int`
val poolClientFlow = Http().cachedHostConnectionPool[Int]("")
val responseFuture: Future[(Try[HttpResponse], Int)] =
  Source.single(HttpRequest(uri = "/") -> 42)

As it is a great example of akka-http usage it could be easily overused by developers. Using this approach, we create a new flow instance each time we want to send a request. This is the cause of "Exceeded configured max-open-requests value of ..." exception if we try to spawn more parallel requests then configured the max-open-requests value. To prevent resource starvation, we can introduce Source.queue instead of Source.single. This way we can create a single flow to which we will enqueue all our requests:

import akka.http.scaladsl.Http
import akka.http.scaladsl.model.{HttpRequest, HttpResponse}
import{Keep, Sink, Source}
import{ActorMaterializer, OverflowStrategy}

import scala.concurrent.duration._
import scala.concurrent.{Future, Await, Promise}
import scala.util.{Failure, Success}


implicit val system = ActorSystem("main")
implicit val materializer = ActorMaterializer()

val pool = Http().cachedHostConnectionPool[Promise[HttpResponse]](host = "", port = 80)
val queue = Source.queue[(HttpRequest, Promise[HttpResponse])](10, OverflowStrategy.dropNew)
     case ((Success(resp), p)) => p.success(resp)
    case ((Failure(e), p)) => p.failure(e)

val promise = Promise[HttpResponse]
val request = HttpRequest(uri = "/") -> promise

val response = queue.offer(request).flatMap(buffered => {
  if (buffered) promise.future
  else Future.failed(new RuntimeException())

Await.ready(response, 3 seconds)

I hope this will help to develop more reliable akka-http services.