0

I'm trying to use akka-http in order to make http requests to a single host (e.g. "akka.io"). The problem is that the created flow (Http().cachedHostConnectionPool) starts emitting responses only after N http requests are made, where N is equal to max-connections.

import scala.util.Failure
import scala.util.Success
import com.typesafe.config.ConfigFactory
import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.model.HttpRequest
import akka.http.scaladsl.model.Uri.apply
import akka.http.scaladsl.settings.ConnectionPoolSettings
import akka.stream.ActorMaterializer
import akka.stream.scaladsl.Sink
import akka.stream.scaladsl.Source

object ConnectionPoolExample extends App {

  implicit val system = ActorSystem()
  implicit val executor = system.dispatcher
  implicit val materializer = ActorMaterializer()

  val config = ConfigFactory.load()

  val connectionPoolSettings = ConnectionPoolSettings(config).withMaxConnections(10)
  lazy val poolClientFlow = Http().cachedHostConnectionPool[Unit]("akka.io", 80, connectionPoolSettings)

  val fakeSource = Source.fromIterator[Unit] { () => Iterator.continually { Thread.sleep(1000); () } }
  val requests = fakeSource.map { _ => println("Creating request"); HttpRequest(uri = "/") -> (()) }

  val responses = requests.via(poolClientFlow)

  responses.runForeach {
    case (tryResponse, jsonData) =>
      tryResponse match {
        case Success(httpResponse) =>
          httpResponse.entity.dataBytes.runWith(Sink.ignore)
          println(s"status: ${httpResponse.status}")
        case Failure(e) => {
          println(e)
        }
      }
  }
}

The output looks like this:

Creating request
Creating request
Creating request
Creating request
Creating request
Creating request
Creating request
Creating request
Creating request
Creating request
status: 200 OK
Creating request
status: 200 OK
Creating request
status: 200 OK
...

I am failing to find any configuration parameters which would allow emitting responses as soon as they are ready and not when the pool is out of free connections.

Thanks!

uladzimir
  • 3
  • 2

1 Answers1

0

The reason is that you block the client from doing other work by calling Thread.sleep—that method is simply forbidden inside reactive programs. The proper and simpler approach is to use Source.tick.

Roland Kuhn
  • 15,412
  • 2
  • 36
  • 45
  • Thank you Roland. The particular example is solved by using Source.tick. It was unfortunate to use Thread.sleep(1000) in this fakeSource. The real source is reading from Kafka and it is implemented by extending GraphStage[SourceShape[A]] ... `val stream = consumerMap.getOrElse(topicName, List()).head setHandler(out, new OutHandler { override def onPull(): Unit = { val jsonData = JsonParser(stream.head.message()).convertTo[A] push(out, jsonData) } })` ... Is it also blocking the client? – uladzimir Mar 23 '16 at 14:17
  • Yes, you'll want to add `.async` on that source to decouple it from the rest of the stream. We're also working on proper Kafka integration, see reactive-kafka. – Roland Kuhn Mar 23 '16 at 17:39