Поток Akka зависает при выполнении http-запросов через пул соединений

Я использую Akka 2.4.4 и пытаюсь перейти от Apache HttpAsyncClient (безуспешно).

Ниже приведена упрощенная версия кода, которую я использую в своем проекте.

проблема в том, что он зависает, если я отправляю более 1-3 запросов в поток. До сих пор после 6 часов отладки я даже не смог найти проблему. Я не вижу исключений, журналов ошибок, событий в Decider. Ничего :)

Я попытался уменьшить connection-timeout установка на 1s, думая, что, возможно, он ждет для ответа от сервера, но это не помогло.

что я делаю не так ?

import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.model.headers.Referer
import akka.http.scaladsl.model.{HttpRequest, HttpResponse}
import akka.http.scaladsl.settings.ConnectionPoolSettings
import akka.stream.Supervision.Decider
import akka.stream.scaladsl.{Sink, Source}
import akka.stream.{ActorAttributes, Supervision}
import com.typesafe.config.ConfigFactory

import scala.collection.immutable.{Seq => imSeq}
import scala.concurrent.{Await, Future}
import scala.concurrent.duration.Duration
import scala.util.Try

object Main {

  implicit val system = ActorSystem("root")
  implicit val executor = system.dispatcher
  val config = ConfigFactory.load()

  private val baseDomain = "www.google.com"
  private val poolClientFlow = Http()(system).cachedHostConnectionPool[Any](baseDomain, 80, ConnectionPoolSettings(config))

  private val decider: Decider = {
    case ex =>
      ex.printStackTrace()
      Supervision.Stop
  }

  private def sendMultipleRequests[T](items: Seq[(HttpRequest, T)]): Future[Seq[(Try[HttpResponse], T)]] =

    Source.fromIterator(() => items.toIterator)
      .via(poolClientFlow)
      .log("Logger")(log = myAdapter)
      .recoverWith {
        case ex =>
          println(ex)
          null
      }
      .withAttributes(ActorAttributes.supervisionStrategy(decider))
      .runWith(Sink.seq)
      .map { v =>
        println(s"Got ${v.length} responses in Flow")
        v.asInstanceOf[Seq[(Try[HttpResponse], T)]]
      }

  def main(args: Array[String]) {

    val headers = imSeq(Referer("https://www.google.com/"))
    val reqPair = HttpRequest(uri = "/intl/en/policies/privacy").withHeaders(headers) -> "some req ID"
    val requests = List.fill(10)(reqPair)
    val qwe = sendMultipleRequests(requests).map { case responses =>
      println(s"Got ${responses.length} responses")

      system.terminate()
    }

    Await.ready(system.whenTerminated, Duration.Inf)
  }
}

также, что с поддержка прокси ? У меня тоже не получается.

1 ответов


вам нужно полностью использовать тело ответа, чтобы соединение стало доступным для последующих запросов. Если вы вообще не заботитесь о сущности ответа, то вы можете просто слить его до Sink.ignore, что-то вроде этого:

resp.entity.dataBytes.runWith(Sink.ignore)

в конфигурации по умолчанию при использовании пула соединений хоста максимальное число соединений равно 4. У каждого пула есть своя очередь, в которой запросы ждут, пока одно из открытых соединений станет доступным. Если эта очередь когда-либо превысит 32 (конфигурация по умолчанию, может быть изменена, должна быть мощностью 2), тогда yo начнет видеть сбои. В вашем случае вы делаете только 10 запросов, поэтому вы не нажимаете этот предел. Но, не потребляя объект ответа, вы не освобождаете соединение, а все остальное просто выстраивается в очередь, ожидая освобождения соединений.