Hi,
I have a use-case where the sender of an event shall be able to specify
whether the event shall be processed in the background or an answer is
expected. I wanted to express these semantics by specifying a 'replyTo:
Option[ActorRef]' in the message rather than adding a flag to the message.
The constraint here is that it shall work from outside the actor system as
well (ie. I would need something like the ask pattern, which basically
returns a future, if the event isn't sent from within an actor).
I thought about these approaches, none of which seemed quite right:
- Send the event with the ask pattern: This would mean I don't have a
replyTo in the message, but a flag (eg. 'responseWanted'). If the flag is
set to true, the processing actor would respond -- otherwise not. The
problem here is that the ask pattern always expects a response within the
specified timeout or throws an exception if no response is received. Also,
I'd rather have an explicit replyTo attribute in the event instead of the
flag.
- Send the event with tell: This would mean the sender needs to be an actor
as well or somehow else obtain an ActorRef to be sent along for the
response. This would mean I'd have to create an ActorRef on the fly to
handle the response.
Eventually I ended up implementing a bit of boilerplate code that combines
the two approaches (heavily inspired by the ask pattern's impl): If the
sender is not interested in a response, it can just fire the event with a
regular tell and set the replyTo to None. If the sender wants a response,
however, it would invoke a function with this signature: *def
askOpt(msgFactory: ActorRef => Any, target: ActorRef): Future[Any]* This
creates an actor on the fly, creates the event with the newly created
actor's ref and then sends that to the target from inside the new actor. It
then races against a scheduled task, just like the ask pattern.
So my questions are:
- Is this a good approach? I feel like I am re-implementing lots of things
that already exist in the ask pattern, however all of that is inacessible
from the outside
- Specifying the replyTo in the message will become much more prominent
with akka-typed (as far as I understand). How would ask work in that
scenario? (seems somewhat similar)
Thanks a lot!
- Reto
Boilerplate Code:
def ask(msgFactory: ActorRef => Any, target: ActorRef)(implicit system:
ActorSystem, timeout: Timeout): Future[Any] = {
val result = Promise[Any]()
val actor = system.actorOf(PromiseActor.props(result, msgFactory,
target))
import system.dispatcher
val f = system.scheduler.scheduleOnce(timeout.duration) {
result tryComplete Failure(new AskTimeoutException(s"Ask timed out on
[$target] after [${timeout.duration.toMillis} ms]"))
}
result.future onComplete { _ =>
try actor ! PoisonPill finally f.cancel()
}
result.future
}
private class PromiseActor(p: Promise[Any], evtFactory: ActorRef => Any,
target: ActorRef) extends Actor {
override def preStart: Unit = {
target ! evtFactory(self)
}
override def receive: Receive = {
case res: Any =>
p.success(res)
context.stop(self)
}
}
--
>>>>>>>>>> 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 [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/akka-user.
For more options, visit https://groups.google.com/d/optout.