Sending Akka HttpEntity between actors

207 views Asked by At

In akka-http, HttpRequest and HttpResponse are mostly immutable objects, except for their HttpEntity bodies (which have a Source).

Is it safe to send a request, response, or solo entity to another actor (especially a remote actor) or is some precaution needed?

1

There are 1 answers

0
Ramón J Romero y Vigil On

As stated in the comments: sending an HttpEntity to a remote Actor is unlikely to work due to the socket limitation. Further evidence can be found in the documentation (emphasis theirs):

IMPORTANT: Messages can be any kind of object but have to be immutable. Scala can’t enforce immutability (yet) so this has to be by convention.

However, the ByteString values coming from the Source do not have the same limitations as the Source itself since ByteString is immutable. You could simply drain the Source on the local akka-http ActorSystem and dispatch ByteString values to your remote Actor.

As an example, say you want to use an Actor to uppercase all of the characters in a utf-8 based HttpEntity. You can setup your Actor:

class UpperActor extends Actor {
  override def receive : Receive = {
    case b : ByteString => sender() ! b.toString.toUpperCase
  }
}

Then your akka-http could look like:

val actorRef = ??? //setup the ref to remote UpperActor

/**Query the Actor*/
val dispatchByteString : (ByteString) => Future[String] = 
  (byteString : ByteString) => (actorRef ? byteString).mapTo[String]

val parallelism = 10 // should match your Actor's mailbox size

/**Construct the Response Source.*/
val requestToSrc : (HttpRequest) => Source[ChunkStreamPart,_] = 
  (_ : HttpRequest).entity
                   .dataBytes
                   .mapAsync(parallelism)(dispatchByteString)
                   .map(ChunkStreamPart.apply)

val contentType = ContentTypes.`text/plain(UTF-8)`

val route = extractRequest { request =>
  complete(HttpResponse(entity = Chunked(contentType, requestToSrc(request))))
}