Emil Szostakiewicz Emil Szostakiewicz - 3 months ago 18
Scala Question

Akka http request is not consumed with runFold when it's piped to actor

My code is based on examples in Akka documentation, so it should work as charm, but problem is that I only receive headers of the response, content length, and when it comes to folding body I get:


[INFO] [08/17/2016 13:01:21.116] [default-akka.actor.default-dispatcher-9] [akka://default/user/$a] Length: 29407

[INFO] [08/17/2016 13:01:21.127] [default-akka.actor.default-dispatcher-9] [akka://default/user/$a] Got response, body: List()


Actor code:

class AkkaHttp extends Actor with ActorLogging {

import akka.pattern.pipe
import context.dispatcher

final implicit val materializer: ActorMaterializer = ActorMaterializer(ActorMaterializerSettings(context.system))

val http = Http(context.system)

override def preStart() = {
http.singleRequest(HttpRequest(uri = "http://akka.io/"))
.pipeTo(self)
}

def receive = {
case s: String => {
log.info(s)
}
case HttpResponse(StatusCodes.OK, headers, entity, _) => {
log.info("Length: " + entity.contentLengthOption.getOrElse("No content"))
log.info("Got response, body: " + entity.dataBytes.runFold(ByteString.empty) {
case (acc, b) => acc ++ b }.map(s => s.utf8String))
}
case HttpResponse(code, _, _, _) =>
log.info("Request failed, response code: " + code)
}

}


If I change preStart() method to fold response in it and send just String, the body of page is logged:

override def preStart() = {
val httpRequest: HttpRequest = HttpRequest(uri = "http://akka.io/")
val request = http.singleRequest(httpRequest)
request.flatMap { response =>
response.entity.dataBytes.runFold(ByteString.empty) {
case (acc, b) => acc ++ b }.map(f => f.utf8String)
}
.pipeTo(self)
}


What could be a reason that response entity is not folded in first version?

Answer

The result of that runFold is another Future. You then go and try and print that Future, which won't yield anything of value as it's a Future and not the underlying String that you want. If you change the case in your receive to this, then it should start working:

case HttpResponse(StatusCodes.OK, headers, entity, _) => 
  log.info("Length: " + entity.contentLengthOption.getOrElse("No content"))

  val entityFut = 
    entity.dataBytes.runFold(ByteString.empty) {
      case (acc, b) => acc ++ b 
    }.
    map(s => s.utf8String)
  entityFut pipeTo self
Comments