9

I post some data to Server using the following code

  def post(endpoint: String, entity: Strict) = {
    Http().singleRequest(HttpRequest(uri = Notifier.notificationUrl + endpoint, method = HttpMethods.POST,
      entity = entity)) onComplete {
      case Success(response) => response match {
        case HttpResponse(StatusCodes.OK, _, _, _) =>
          log.info("communicated successfully with Server")
      }
      case Failure(response) =>
        log.error("communicated failed with Server: {}", response)
    }
  }

This is called every 10 seconds when Notifier actor receives message as following

case ecMonitorInformation: ECMonitorInformation =>
  post("monitor", httpEntityFromJson(ecMonitorInformation.toJson))

Problem?

I see that Initially (around 5 requests going to server) but then it hungs up, I do not see any logging, server does not receive any data. After a while on the client side, I see following

ERROR c.s.e.notification.Notifier - communicated failed with Server: java.lang.RuntimeException: Exceeded configured max-open-requests value of [32]

What is going on? How do I fix this issue?

daydreamer
  • 87,243
  • 191
  • 450
  • 722
  • 1
    You are hitting the default limit for the total number of open requests into the underlying pool for whatever host it is you are talking to. Are the requests that are going into your pool completing properly? My guess would be that they are not and that's why the pool itself is getting backed up and thus hitting this limit. You can raise the limit but sounds like you'd just be delaying the inevitable until you fix whatever is causing the requests to hang. – cmbaxter Aug 26 '15 at 18:12
  • You might need to have only one instance of Http(). Similar problem with solution you can find(for spray) in http://stackoverflow.com/questions/29324591/spray-client-throwing-too-many-open-files-exception-when-giving-more-concurren – Yoda Aug 27 '15 at 01:16
  • @Yoda, nope that did not solve the problem either – daydreamer Aug 27 '15 at 16:58
  • I think you could find useful my answer from the other question - http://stackoverflow.com/a/35115314/1699837 – khiramatsu Jan 31 '16 at 16:00

4 Answers4

3

I went through the docs and tried the following

val connectionFlow: Flow[HttpRequest, HttpResponse, 
        Future[Http.OutgoingConnection]] =
        Http().outgoingConnection(host = "localhost", port = 8080)

and then

  def httpPost(uri: String, httpEntity:Strict) {
    val responseFuture: Future[HttpResponse] =
      Source.single(HttpRequest(uri = "/monitor", method = HttpMethods.POST, entity=httpEntity))
        .via(connectionFlow)
        .runWith(Sink.head)

    responseFuture onComplete {
      case Success(response) => log.info("Communicated with Server: {}", response)
      case Failure(failure) => log.error("Communication failed with Server: {}", failure)
    }

and this worked for me

daydreamer
  • 87,243
  • 191
  • 450
  • 722
  • Is it possible to retry failed responses? – Tvaroh Sep 09 '15 at 21:05
  • you can ideally since you know it failed – daydreamer Sep 09 '15 at 22:27
  • While this works, it is also very ineffective as a new connection is created for every request. This will bring all kinds of problems. What the error message says is: hey you are creating lots of requests that will be buffered somewhere and may be stuck in a queue for a long time. This "solution" says: whatever, let's DOS the server. In the end, the requests will now be stuck somewhere else. – jrudolph Sep 27 '16 at 09:27
  • So, the real solution is basically to prevent the generation of too many requests at a time in the first place (what @khiramatsu hinted at). On the other hand, if you don't care for large queues you can also increase the limit by setting `akka.http.host-connection-pool.max-open-requests`. – jrudolph Sep 27 '16 at 09:31
3

You can also overcome this error by upping the max-open-requests property of akka which is 32 by default.

The property to change will be:

akka.http.host-connection-pool.max-open-requests = 64

The only caveat is that this will fail when the client opens more concurrent connections than what the new value of that parameter is, in this example if the open connections exceed 64, you will get the same error.

harpresing
  • 603
  • 6
  • 10
2

If you are going to be repeatedly calling your method, you might want to consider using one of the connection pool based client methods as described here: http://doc.akka.io/docs/akka-stream-and-http-experimental/1.0/scala/http/client-side/index.html

You can also set the connection pool settings in the akka-http client configuration: http://doc.akka.io/docs/akka-stream-and-http-experimental/1.0/scala/http/configuration.html#akka-http-core

Search for host-connection-pool.

Jason Martens
  • 1,305
  • 11
  • 22
2

You could use Source.queue instead of Source.single to provide buffering and overflow strategy. See more details at https://stackoverflow.com/a/35115314/1699837

Community
  • 1
  • 1
khiramatsu
  • 201
  • 2
  • 4