Futures vs. per-request actors in akka-http

1,555 views
Skip to first unread message

Nicolau Werneck

unread,
Jun 14, 2015, 11:50:54 PM6/14/15
to akka...@googlegroups.com
From what I gathered from the documentation and examples, the usual way to answer to a request asynchronously in Spray and akka-http is to `complete` with a `Future`, which may be produced from asking an actor. But in Spray there was also the so-called "actor per-request" pattern, documented in http://techblog.net-a-porter.com/2013/12/ask-tell-and-per-request-actors/

Is that still possible to do with akka-http? And is it discouraged in general? Should we really stick to using Futures to integrate akka-http to the rest of our applications?

    ++nic

Richard Bradley

unread,
Jun 15, 2015, 2:51:27 PM6/15/15
to akka...@googlegroups.com
The situation is very much the same in Akka HTTP as it was in Spray 1.3.
You should be able to translate the actor-per-request pattern into Akka with only superficial changes. 
If you didn't deal with large (streamed / chunked) requests, everything is very much the same from Routing on down.

As to which is recommended -- I think that is much the same as well:

Actor-per-request needs more book-keeping (to avoid leaks) but allows greater control in complex scenarios.

Future calls (which can include "asks" on Actors) are simpler and usually more type-safe and easier to work with IMO. You need to be very careful around mutable state though.

HTH,


Rich

Nicolau Werneck

unread,
Jun 15, 2015, 11:41:54 PM6/15/15
to akka...@googlegroups.com
All right then, except I'm under the impression that to use that pattern we need to create an application using the `spray.routing.HttpService` class, and I could not find it in akka-http. Is it available under a different name?

Thanks,
    ++nic

Richard Bradley

unread,
Jun 16, 2015, 4:40:55 AM6/16/15
to akka...@googlegroups.com
You can see the source code to the net-a-porter Spray example here:

The startup looks like:
  IO(Http) ! Http.Bind(serviceActor, "localhost", port = 38080)

where "serviceActor" is an actor that mixes in spray.routing.HttpService, as you say. The actor uses that trait to call "runRoute" to bind its Route to the HTTP layer.


In Akka HTTP, you instead need to wrap a Route with "akka.http.scaladsl.server.Route.handlerFlow" to turn it into a Flow[HttpRequest, HttpResponse, Unit] and then pass that into "Http().bindAndHandle(...)".

That part has changed quite a bit, but from the Routing layer on down, everything is very much the same, in my opinion.

Nicolau Werneck

unread,
Jun 16, 2015, 10:00:13 PM6/16/15
to akka...@googlegroups.com
Great, thanks for the reply!    ++nic

Richard Rodseth

unread,
Sep 7, 2015, 1:24:00 PM9/7/15
to akka...@googlegroups.com
I've run into the same problem. How to do per-request actors rather than ask pattern with Akka Http, and I'm afraid I don't understand how handlerFlow helps. I've started a separate thread, but if either of you can elaborate that would be great. The Spray migration page is still marked TODO.

Thanks.

--
>>>>>>>>>> Read the docs: http://akka.io/docs/
>>>>>>>>>> Check the FAQ: http://doc.akka.io/docs/akka/current/additional/faq.html
>>>>>>>>>> Search the archives: https://groups.google.com/group/akka-user
---
You received this message because you are subscribed to the Google Groups "Akka User List" group.
To unsubscribe from this group and stop receiving emails from it, send an email to akka-user+...@googlegroups.com.
To post to this group, send email to akka...@googlegroups.com.
Visit this group at http://groups.google.com/group/akka-user.
For more options, visit https://groups.google.com/d/optout.

Akka Team

unread,
Sep 9, 2015, 5:18:30 AM9/9/15
to Akka User List
Hi Richard,

There is no easy way currently to do per-request actors (except that everything in your handler Flow is kind of a per-request actor), this is something we need to improve. I created an issue: https://github.com/akka/akka/issues/18431

-Endre
--
Akka Team
Typesafe - Reactive apps on the JVM
Blog: letitcrash.com
Twitter: @akkateam

Patrik Nordwall

unread,
Sep 9, 2015, 5:59:41 AM9/9/15
to akka...@googlegroups.com
On Wed, Sep 9, 2015 at 11:17 AM, Akka Team <akka.o...@gmail.com> wrote:
Hi Richard,

There is no easy way currently to do per-request actors (except that everything in your handler Flow is kind of a per-request actor), this is something we need to improve. I created an issue: https://github.com/akka/akka/issues/18431

It's possible to create an actor from the mapAsync function and return the Future of an ask request to that new actor. What am I missing?
/Patrik



--

Patrik Nordwall

Typesafe Reactive apps on the JVM

Twitter: @patriknw

Akka Team

unread,
Sep 9, 2015, 6:05:41 AM9/9/15
to Akka User List
On Wed, Sep 9, 2015 at 11:59 AM, Patrik Nordwall <patrik....@gmail.com> wrote:


On Wed, Sep 9, 2015 at 11:17 AM, Akka Team <akka.o...@gmail.com> wrote:
Hi Richard,

There is no easy way currently to do per-request actors (except that everything in your handler Flow is kind of a per-request actor), this is something we need to improve. I created an issue: https://github.com/akka/akka/issues/18431

It's possible to create an actor from the mapAsync function and return the Future of an ask request to that new actor. What am I missing?
/Patrik

Where would you create the actor? You need an ActorRefFactory for that, and the only legal way from inside a stage would be then to create a top-level actor, which is far from optimal.

-Endre

Patrik Nordwall

unread,
Sep 9, 2015, 6:27:30 AM9/9/15
to akka...@googlegroups.com
On Wed, Sep 9, 2015 at 12:05 PM, Akka Team <akka.o...@gmail.com> wrote:


On Wed, Sep 9, 2015 at 11:59 AM, Patrik Nordwall <patrik....@gmail.com> wrote:


On Wed, Sep 9, 2015 at 11:17 AM, Akka Team <akka.o...@gmail.com> wrote:
Hi Richard,

There is no easy way currently to do per-request actors (except that everything in your handler Flow is kind of a per-request actor), this is something we need to improve. I created an issue: https://github.com/akka/akka/issues/18431

It's possible to create an actor from the mapAsync function and return the Future of an ask request to that new actor. What am I missing?
/Patrik

Where would you create the actor? You need an ActorRefFactory for that, and the only legal way from inside a stage would be then to create a top-level actor, which is far from optimal.

I could have created a top level actor up front and let that one create child actors on demand. The ask would go to the top level actor that forwards to a child. It could be a router if a single top level actor becomes a bottleneck.

I agree that this is a nice feature to have built-in, but I think there are ways that are rather alright already.

Akka Team

unread,
Sep 9, 2015, 6:34:57 AM9/9/15
to Akka User List
On Wed, Sep 9, 2015 at 12:27 PM, Patrik Nordwall <patrik....@gmail.com> wrote:


On Wed, Sep 9, 2015 at 12:05 PM, Akka Team <akka.o...@gmail.com> wrote:


On Wed, Sep 9, 2015 at 11:59 AM, Patrik Nordwall <patrik....@gmail.com> wrote:


On Wed, Sep 9, 2015 at 11:17 AM, Akka Team <akka.o...@gmail.com> wrote:
Hi Richard,

There is no easy way currently to do per-request actors (except that everything in your handler Flow is kind of a per-request actor), this is something we need to improve. I created an issue: https://github.com/akka/akka/issues/18431

It's possible to create an actor from the mapAsync function and return the Future of an ask request to that new actor. What am I missing?
/Patrik

Where would you create the actor? You need an ActorRefFactory for that, and the only legal way from inside a stage would be then to create a top-level actor, which is far from optimal.

I could have created a top level actor up front and let that one create child actors on demand. The ask would go to the top level actor that forwards to a child. It could be a router if a single top level actor becomes a bottleneck.

That can work, even if not trivial. Also ties the Flow to a certain top-level actor, making it less reusable -- but it might not matter in an Http handler anyway. I just still don't like that single bottleneck point, router or not.
 

I agree that this is a nice feature to have built-in, but I think there are ways that are rather alright already.

If nothing else, we should make this a cookbook pattern. Btw there is no HTTP cookbook yet.

-Endre

Richard Rodseth

unread,
Sep 10, 2015, 11:02:32 AM9/10/15
to akka...@googlegroups.com
Thanks for the response. This is somewhat encouraging. +1 to cookbook and migration docs.

I'm not up to speed on Flows, so I don't know what the proposed solution would look like in a route definition.
In the meantime (this is just for a new proof of concept app) I embraced the Ask in the route definition and create one-offs in response. I didn't use forwarding as Patrik mentioned. Instead the one-off has a "requester" property and after doing a bunch of tells and receives, completes the ask future by sending a response to the requester. I hope this is OK - it seems to work as a bridge between AskWorld and TellDon'tAskWorld. 

Heiko Seeberger

unread,
Sep 10, 2015, 12:22:13 PM9/10/15
to akka...@googlegroups.com
That should work, but as long as there’s no aggregation or something but just a linear flow of messages, I think forwarding is the simplest solution.

Cheers
Heiko

--

Heiko Seeberger
Twitter: @hseeberger

Richard Rodseth

unread,
Sep 10, 2015, 2:03:39 PM9/10/15
to akka...@googlegroups.com
It seemed to me that forwarding implied chained asks. Not sure what you mean by aggregation vs linear flow. The goal for me is to have no asks, other than the one in the route definition, and that means that the one-off actor can't reply from within its "DoIt" message handler.

Patrik Nordwall

unread,
Sep 10, 2015, 2:09:47 PM9/10/15
to akka...@googlegroups.com
By forward I mean forward (not chained ask). ;-)

Richard Rodseth

unread,
Sep 10, 2015, 2:30:02 PM9/10/15
to akka...@googlegroups.com
Well I must be missing something. Here's what I'm doing:

    case SimulatorServiceRequestHandler.AskForStatus => {

      val requester = sender

      // Create a per-request actor whose result will go to my sender

      val getStatusActor = context.actorOf(GetStatusActor.props(requester, service))

      getStatusActor ! GetStatusActor.DoIt // Reply goes to requester

    }


I thought you were proposing

        case msg @ SimulatorServiceRequestHandler.AskForStatus => {

      // Create a per-request actor and forward the message

      val getStatusActor = context.actorOf(GetStatusActor.props(service))

      getStatusActor forward msg

    }

But then does GetStatusActor have to reply from within it's own AskForStatus handler? If so, and other actors are involved, how does it do that without doing another ask with pipeToSender ?

Patrik Nordwall

unread,
Sep 10, 2015, 3:14:10 PM9/10/15
to akka...@googlegroups.com
On Thu, Sep 10, 2015 at 8:29 PM, Richard Rodseth <rrod...@gmail.com> wrote:
Well I must be missing something. Here's what I'm doing:

    case SimulatorServiceRequestHandler.AskForStatus => {

      val requester = sender

      // Create a per-request actor whose result will go to my sender

      val getStatusActor = context.actorOf(GetStatusActor.props(requester, service))

      getStatusActor ! GetStatusActor.DoIt // Reply goes to requester


Ok, that is good.

    }


I thought you were proposing

        case msg @ SimulatorServiceRequestHandler.AskForStatus => {

      // Create a per-request actor and forward the message

      val getStatusActor = context.actorOf(GetStatusActor.props(service))

      getStatusActor forward msg

    }

But then does GetStatusActor have to reply from within it's own AskForStatus handler? If so, and other actors are involved, how does it do that without doing another ask with pipeToSender ?


It would have replied to the sender(), which points to the original ask future (PromiseActorRef).

I like your approach of passing in the requester ActorRef in the constructor.

Richard Rodseth

unread,
Sep 10, 2015, 3:17:12 PM9/10/15
to akka...@googlegroups.com
Oh good. Thanks.

Heiko Seeberger

unread,
Sep 11, 2015, 12:01:13 PM9/11/15
to akka...@googlegroups.com
The whole purpose of forwarding is that the receiving actor sees the sender of the original message when using `sender()` (please use the parens).

So, if A sends a message to B via `!` or `tell` and B forwards that message or some other one via `forward` to C, C can simply respond to A by using `sender() ! "response“`.

A ~> B ~> C
A     <~     C

Makes sense?

Heiko

--

Heiko Seeberger
Twitter: @hseeberger

Richard Rodseth

unread,
Sep 11, 2015, 4:52:12 PM9/11/15
to akka...@googlegroups.com
But if C is telling D something and receiving the reply in a separate message D -> C, sender() is no longer any use.
Maybe that's what you meant by aggregation.

I like to include a replyTo in messages. The combination of that and the requestor property in my one-off actors seems to be working out fine.
There's rather a lot of boiler plate compared to the net-a-porter approach, but I could probably address that down the line with some type parameters.

So:

A sends AskStatus to B 
B creates new StatusOneOff with requester property = sender()
B sends DoIt to StatusOneOff 
StatusOneOff sends GetStatus(replyTo = self) to D
D or one of its minions sends GetStatusReply(value) to StatusOneOff
StatusOneOff sends value to requester ref

Voila! No asks anywhere except at the boundary where required by Akka HTTP.

I do still agree with Endre that a way to avoid the per-request factory bottleneck (B in this case) would be good.

PS. I added the parens :)


Heiko Seeberger

unread,
Sep 12, 2015, 1:48:08 AM9/12/15
to akka...@googlegroups.com


> On 11 Sep 2015, at 22:52, Richard Rodseth <rrod...@gmail.com> wrote:
>
> But if C is telling D something and receiving the reply in a separate message D -> C, sender() is no longer any use.
> Maybe that's what you meant by aggregation.

Yep, that’s a non-linear message flow.

> I like to include a replyTo in messages.

Sure, that’s a good idea, because it makes the message protocol very explicit. It’s also a good step towards Akka Typed ;-)

Heiko

Reply all
Reply to author
Forward
0 new messages