Reading the Scala doc I am having difficulty understanding the difference between ask and tell.
http://doc.akka.io/docs/akka/snapshot/scala/actors.html states :
! means “fire-and-forget”, e.g. send a message asynchronously and
return immediately. Also known as tell.
? sends a message asynchronously and returns a Future representing a
possible reply. Also known as ask.
If the actor I'm using spawns a web request then what is the difference between ask and tell ? In both cases the request will be spawned asynchronously and must wait for a response, in other words how can "tell" return immediately if the actor is invoking a web service and awaiting a response ?
The difference between ask and tell is from the point of view of the message sender (which is not necessarily an actor). ask will send the message and return a future, which can be awaited until timeout or a reply is received, tell will send the message and return immediately.
In the case of ask, the actor that receives the message should reply to the sender when the operation is completed.
It sounds like you already know the basic difference between ask and tell, but don't understand how tell could be used to involve other actors in handling HTTP requests.
In order for it to make sense to use tell in your HTTP request handlers, you have to use an HTTP server that does not require that request handlers return their responses. Spray is such an HTTP server.
In Spray a request handler does not return its response; it is given a RequestContext object, and responding to the request involves invoking some method on it. You can simply send that RequestContext to another actor, which can then respond to the request:
path("foo") {
rc => rc complete "foo" // respond here
} ~
path("bar") {
rc => barActor ! DoBar(rc) // send it to bar; NO RESPONSE HERE
}
Then the actor referred to by barActor could say
case DoBar(rc) =>
rc complete "bar" // respond here, in another actor
The fact that Spray packages up the request context into an object that can be passed around and completed from any actor is a great fit for the actor model. If, on the other hand, your web framework requires that the invoked handler return the response, then if you want to involve another actor your only choice is to use ask.
Typesafe announced that Play will soon use Spray underneath. I hope that means that Play will then allow requests to be sent along to other actors for processing.
Related
I'm currently porting an Akka Classic app to Akka Typed. I have the following components:
HttpService - Not an Actor
JobDispatcher - An Actor
JobWorker - Child actor of JobDispatcher
The JobDispatcher is a singleton actor that orchestrates jobs. Each JobWorker is responsible for one "job" and knows the job's status.
The HTTP service will make an Ask to JobDispatcher, called GetJobStatuses.
The JobDispatcher will then Ask each of the JobWorkers what their status is, aggregate the results into a list, and reply to HttpService.
The way I did this in Akka Classic was to have JobDispatcher do all the Asks, put the Futures into a list of Futures, and then transform that into a Future of Lists, and when that aggregate Future completed, I would send the results to HttpService. It looked something like this:
val statusFutures: Seq[Future[JobStatus]] = jobWorkers map (jobWorker => (jobWorker ? GetJobStatus).mapTo[JobStatus])
val aggregateFuture: Future[Seq[SearchStatus]] = Future.sequence(statusFutures)
val theSender = context.sender()
aggregateFuture onComplete {
case Success(jobStatuses: Seq[JobStatus]) => {
theSender ! jobStatuses
}
case Failure(exception) => {
theSender ! exception
}
}
So, now that we're moving to Akka Typed, we're not supposed to use Futures / onComplete, but instead turn the Ask response into a message back ourself (JobDispatcher in this case). This is fairly straightforward for simple situations where I'm Asking one other actor for one reply. But in this case, I have a whole list of child actors from which I need to compile their responses.
The only thing I can think of is to make JobDispatcher hold a "state" of a list of JobWorker responses that I'm waiting for, track of which ones have been received, and when I've received them all, send a response message back to the HTTP service. This is further complicated by the fact that I may have multiple simultaneous Asks coming in from the HTTP service, and I'd have to track multiple copies of this "state", and somehow identify which HTTP request each one is for.
This is all WAY more complicated than the the aggregate Future solution above.
What is the simple/correct way to handle situations like this in Akka Typed?
The docs suggest using a per-session child actor for this situation. The child actor, being only associated with a single HTTP request is implicitly tracking exactly one copy of that state and is also able to manage the state of the process of scatter/gathering jobs (e.g. around timeouts and retries).
It's also worth noting that the example classic code has a massive bug: never call sender in code involving futures. Mixing futures and actors is superficially easy but also easy to turn into something that only works by coincidence (with tests often exhibiting that coincidental behavior).
I have an HTTP API endpoint that I need constantly check for new values. Luckily, it's supports long polling. So the idea is that I need to implement 'an infinite loop' where I do a request, wait for a response (at most 10mins), get some value from response and produce a side-effect by storing them somewhere, make another request.
Given that I have some function the call to which will start this 'infinite loop' I also need to return a Closable to satisfy Finagle API I'm integrating with so the process can be interrupted. If HTTP request fails I need to re-try immediately.
Now I need to figure out how to implement this with Futures in Finagle. I wonder whether I can user a recursion by applying transform to response Future?.. Or am I missing something and there is a more straightforward way to do it in Finagle?
Thanks!
I am not sure I can imagine how it (what you described) can be made any more straightforward than recursive:
def keepCalling: Future[Unit] = makeRequest
.flatMap { response =>
processResponse(response)
if(cancelled) Future.Unit else keepCalling
}
Note, that this is actually not recursive in the traditional sense, as we should normally expect (with some reservations) only one instance of keepCalling to be on stack at any given time, since the "recursive" invocation happens on a different thread.
I'm implementing a REST endpoint in Spray.
Here is the flow along with the name of the actors that are responsible for each of the step below.
Invoke the REST API and pass the required parameters (ActorSupervisor)
Validate the parameters (ValidateActor)
Call an external datastore to get data based on the parameter values (DataStoreActor)
3a. The external datastore API returns a Future
Pass the Future in step 3a. to an actor that can process the data (ProcessingActor)
Returned the processing results back to the client (as Future[ HTTP Response])
The most expensive step is #4 (which may take anywhere from a 400ms to 5 minutes depending on the size of the input dataset.
My question is how can I return a HTTP response back from #5?
There are multiple ways to handle that which you can use which gels well with your architecture. Using any method, you will have to use ctx's (spray's RequestContext) complete method to complete the HTTP request. You can use:-
Pass "ctx" (spray's RequestContext) encapsulated in the Actor's message and utilize ctx in the Step #5 to complete the request.
For example:-
If currently, you pass message from ActorStep1 to ActorStep2 then you will need to pass message(ctx)
in this method. The benefit in this method is that you can complete the request from any step but an extra attribute will be added to each message.
Instead of telling you can use ask pattern. In the step 5, you will respond back to Actor in step 4 with Future[ HTTP Response]. Similarly, Actor in step 4 will respond to Actor in step 3 and so on. This works for me because I have only one chain, may not work for you.
You can use forward pattern. For example - Actor in step 1 will pass a message to Actor in Step 2. The Actor in Step 2 will forward the message to Actor in Step 3 after processing and so on till Actor in Step 5. The actor in Step 5 will respond back using sender ! Future[HTTPResponse] which will actually send the message to Actor in Step 1 where you can complete the request.
Spray is just a thin layer on top of Akka, treat this as a case of passing a message back to parent Actor from child actor.
Say I have an IO Actor connection capable of sending and receiving messages over TCP. In my actor, I ask the other side of the connection for a response:
connection.ask(ByteString("stuff")).collect {
case Received(response) => log.debug(response.utf8String)
}
It appears that with this code the ask future times out, and instead the containing actor receives the raw message outside of the ask pattern.
Can you use the ask pattern with Akka IO actors? If not, why not?
I don't know the architecture in detail, but here's how I would explain it to myself:
The problem with Akka IO connector actors here is that they don't work in a request-response manner. And if you think about it - that makes sense, because TCP is not a request-response protocol. TCP doesn't even have a notion of message. From programmer's perspective TCP connection is just a pair of continuous byte streams - one in each direction. That's it.
Akka IO is a minimal actor layer on top of network protocols, so it's not surprising that it mimics this behaviour. When TCP actor receives some data from the network, it only knows one thing - that it should send a Received message to the actor that originally sent the Connect message. That's all. It has no idea that the data it received from the network is somehow related to the data that you sent earlier.
Adding to all of that, ask pattern works only under assumption that when you send message A to some actor, it will respond with the message B by sending it exactly to the sender of message A. As we already know, TCP actor doesn't do that - it simply sends everything to the sender of original Connect message.
The reason why this assumption is required is that ask pattern actually creates some sort of a "phantom" actor that is set as the sender of the message sent using ask. This "phantom" actor will then receive the response and invoke all the callbacks registered on the Future. As a side note - be aware that those callbacks are invoked completely independently of the sending actor, i.e. they may run concurrently to it!
So, I would finally conclude that the ask pattern used like this will not work with Akka IO, because it's simply too low level for such an abstraction. If you still want it, you need to create you own layer of abstraction on top of Akka IO, e.g. some simple intermediate actor that covers TCP connector actor and implements the request-response behaviour.
As an additional reference to #ghik's answer, here's roughly how I created an intermediate actor to enable the ask pattern for IO on the rest of my actors.
class IOAskHandlerActor(address: InetSocketAddress) extends Actor {
override def receive = {
// Connection setup code omitted
case Connected(remote, local) =>
// other code omitted
context become latch(sender())
}
def latch(connection: ActorRef): Receive = {
case outgoing =>
context become receiving(connection, sender())
connection ! MySerializer.write(outgoing)
}
def receiving(connection: ActorRef, asker: ActorRef): Receive = {
case Received(incoming) =>
context become latch(connection)
asker ! MySerializer.read(incoming)
}
}
Instances of this class can be asked for responses. Note that I have only tested this with one simultaneous asker (which is my use case) and this probably doesn't work for multiple askers.
I'm using the Play Framework with scala. I'm new to scala, akka, and play.
This is my actor system. I'm not sure I'm doing this right, but I have 2 routers. 1 for Actor A, and 1 for Actor B:
val system = ActorSystem("ActionSystem")
val actorARouter = system.actorOf(Props[ActionParser].withRouter(
SmallestMailboxRouter(Runtime.getRuntime.availableProcessors())), name = "actorARouter")
val actorBRouter = system.actorOf(Props[ActionDispatcher].withRouter(
SmallestMailboxRouter(Runtime.getRuntime.availableProcessors())), name = "actorBRouter")
This is the current setup that I have:
The play framework provides a Controller for me that receives a http rest call with some json. Whenever the Controller receives a rest call, I do an ask sends the json to a router for Actor A. Here is what that looks like:
(actorARouter ? request.body.asJson.get).map {
case m: controllers.HttpMessages.OK => Ok(m.body)
case m: controllers.HttpMessages.HttpResponse => Status(m.status)(m.body)
}
Actor A then parses the json into a Seq of objects and then sends them via an ask to Actor B. Actor B is supposed to eventually process those by sending them to other actors, but for now is just returning generic responses.
The generic responses are being received back by ActorA via the future, then being parsed to JSON and then returned to the Controller via an OK response... or at least that's what is supposed to happen.
What's happening:
So what's happening is the controller sends to ActorA, ActorA sends to ActorB. ActorB sends generic responses to ActorA. ActorA parses generic responses into JSON and tries to do sender ! OK(json) but I get a message in the console saying it wasn't delivered as it's a "dead letter". when I debug into it when I look at sender, sender is a reference to the actor akka://ActionSystem/deadLetters
My questions:
Obviously I'm doing something wrong. Maybe I shouldn't be chaining these actors responses together like this. Again, I mentioned I only had plans to further this by having ActorB send out requests to other actors.
When I do an ask in an actor, that doesn't hog that thread and stop it from processing other messages while it's waiting for a response does it?
EDIT:
I found out I can save a reference to the sender for later use, and then send to that, and that seems to fix the dead letter problem. But I'm still very uncertain if this is the right way to be doing things. It feels like every time I'm adding another layer of actors 10's of milliseconds are being added onto my response time. Perhaps that's due to other factors though.
Without looking at your code, I cannot really comment on what caused the dead letter, from your edit I guess you closed over sender() instead of assigning it to a variable and closing over that.
To respond to your questions:
It is much easier to construct message flows with actors if you only use fire-and-forget messages. The ask Pattern is useful in some cases, but most of the time you should try to avoid it. What you can do instead is to pass the original sender along through your actors by using forward instead of tell. This way a response can be generated by the last actor in your message flow. The first actor only needs the code to handle the response, and does not need to care about generating the response. Nice separation of concerns right there. If you need to aggregate several responses in order to send out a single response afterwards, you can also use a temporary actor that all other actors will send their response to, and that knows the orignal sender. Temporary actors need to be stopped after doing their work.
As far as I know the ask pattern is asynchronous and uses temporary actors internally. However, if you wait for the result of the future in your actor, that will block that actor, and it will not be able to process further messages. A nice method to use the ask pattern is in combination with the pipeTo Pattern, which you can use to send the result of ask to an actor (usally self)