Akka actors/scala - single onSuccess for multiple asks - scala

I have a chain of akka actors like
A --> B --> C
Actor A 'asks' actor B which in turn 'asks' actor C.
Actor A needs to wait till actor C has finished processing.
B is a thin layer and does nothing more than passing(asking) the message to C and returns a Future back to A. Basically B just do
{ case msgFromA => sender ! C ? msgFromA }
Hence what A is getting is a Future[Any].
The way A is handling the request is using nested maps
actorRefFactory.actorOf(Props[A]) ? msgA map {
resp =>
// Type cast Any to Future and use another map to complete processing.
resp.asInstanceOf[Future[_]] map {
case Success =>
// Complete processing
case Failure(exc) =>
// Log error
This works(i.e The final processing happens only when the actor C has finished processing ) but needless to say it looks horrible. I tried using flatmaps but could not make it work. Any ideas to make it look good :)
Thanks

A more proper way:
In A:
val f: Future[MyType] = (B ? msg).mapTo[MyType]
f onComplete {
case Success(res) => // do something
case Failure(t) => // do something
}
In B, use forward:
{ case msgFromA => C forward msgFromA }
In C:
// call database
// update cache
sender() ! res // actually sends to A

Related

Model multiple function calls with a stream (in a safe, FP way)

Given a function A => IO[B] (aka Kleisli[IO, A, B]) that is meant to be called multiple times, and has side effects, like updating a DB, how to delegate such multiple calls of it into a stream (I guess Pipe[IO, A, B]) (fs2, monix observable/iterant)? Reason for this is to be able to accumulate state, batch calls together over a time window etc.
More concretely, http4s server requires a Request => IO[Response], so I am looking how to operate on streams (for the above benefits), but ultimately provide such a function to http4s.
I suspect it will need some correlation ID behind the scenes and I am fine with that, I am more interested in how to do it safely and properly from an FP perspective.
Ultimately, the signature I expect is probably something like:
Pipe[IO, A, B] => (A => IO[B]), such that calls to Kleisli are piped through the pipe.
As an afterthought, would it be at all possible to backpressure?
One idea is to model it with MPSC (Multiple Publisher Single Consumer). I'll give an example with Monix since I'm more familiar with it, but the idea stays the same even if you use FS2.
object MPSC extends App {
sealed trait Event
object Event {
// You'll need a promise in order to send the response back to user
case class SaveItem(num: Int, promise: Deferred[Task, Int]) extends Event
}
// For backpressure, take a look at `PublishSubject`.
val cs = ConcurrentSubject[Event](MulticastStrategy.Publish)
def pushEvent(num: Int) = {
for {
promise <- Deferred[Task, Int]
_ <- Task.delay(cs.onNext(SaveItem(num, promise)))
} yield promise
}
// You get a list of events now since it is buffered
// Monix has a lot of buffer strategies, check the docs for more details
def processEvents(items: Seq[Event]): Task[Unit] = {
Task.delay(println(s"Items: $items")) >>
Task.traverse(items) {
case SaveItem(_, promise) => promise.complete(Random.nextInt(100))
}.void
}
val app = for {
// Start the stream in the background
_ <- cs
.bufferTimed(3.seconds) // Buffer all events within 3 seconds
.filter(_.nonEmpty)
.mapEval(processEvents)
.completedL
.startAndForget
_ <- Task.sleep(1.second)
p1 <- pushEvent(10)
p2 <- pushEvent(20)
p3 <- pushEvent(30)
// Wait for the promise to complete, you'll do this for each request
x <- p1.get
y <- p2.get
z <- p3.get
_ <- Task.delay(println(s"Completed promise: [$x, $y, $z]"))
} yield ()
app.runSyncUnsafe()
}

akka unstashAll not working

I am implementing an actor with multiple states and using Stash not to lose any messages. My states are initializing (get something from DB), running (handling requests) and updating (updating my state).
My problem is that I lose the messages when i try to unstashAll() in future resolving.
def initializing: Receive = {
case Initialize =>
log.info("initializing")
(for {
items1 <- db.getItems("1")
items2 <- db.getItems("2")
} yield items1 ::: items2) map {items =>
unstashAll()
context.become(running(items))
}
case r =>
log.debug(s"actor received message: $r while initializing and stashed it for further processing")
stash()}
i fixed it by changing my implementation to this
def initializing: Receive = {
case Initialize =>
log.info("initializing")
(for {
items1 <- db.getItems("1")
items2 <- db.getItems("2")
} yield items1 ::: items2) pipeTo self
context.become({
case items: List[Item] =>
unstashAll()
context.become(running(items))
case r =>
log.debug(s"actor received message: $r while initializing and stashed it for further processing")
stash()
})
case r =>
log.debug(s"actor received message: $r while initializing and stashed it for further processing")
stash()}
can anyone explain why the first didn't work ?
I think the unstashAll part works fine. The problem is that you were running it - together with your context.become - as part of a future callback.
This means that the code inside your map block escapes the predictability of your actor sequential processing. In other words, this could happen:
you call unstashAll
your messages are put back in the actor's mailbox
the actor picks up your messages one by one. The context still hasn't changed, so they are stashed again
your context finally becomes running (but it's too late)
The solution is - as you found out - the pipeTo pattern, which essentially sends a Futures result to the actor as a message. This makes it all sequential and predictable.

Akka: The order of responses

My demo app is simple. Here is an actor:
class CounterActor extends Actor {
#volatile private[this] var counter = 0
def receive: PartialFunction[Any, Unit] = {
case Count(id) ⇒ sender ! self ? Increment(id)
case Increment(id) ⇒ sender ! {
counter += 1
println(s"req_id=$id, counter=$counter")
counter
}
}
}
The main app:
sealed trait ActorMessage
case class Count(id: Int = 0) extends ActorMessage
case class Increment(id: Int) extends ActorMessage
object CountingApp extends App {
// Get incremented counter
val future0 = counter ? Count(1)
val future1 = counter ? Count(2)
val future2 = counter ? Count(3)
val future3 = counter ? Count(4)
val future4 = counter ? Count(5)
// Handle response
handleResponse(future0)
handleResponse(future1)
handleResponse(future2)
handleResponse(future3)
handleResponse(future4)
// Bye!
exit()
}
My handler:
def handleResponse(future: Future[Any]): Unit = {
future.onComplete {
case Success(f) => f.asInstanceOf[Future[Any]].onComplete {
case x => x match {
case Success(n) => println(s" -> $n")
case Failure(t) => println(s" -> ${t.getMessage}")
}
}
case Failure(t) => println(t.getMessage)
}
}
If I run the app I'll see the next output:
req_id=1, counter=1
req_id=2, counter=2
req_id=3, counter=3
req_id=4, counter=4
req_id=5, counter=5
-> 4
-> 1
-> 5
-> 3
-> 2
The order of handled responses is random. Is it normal behaviour? If no, how can I make it ordered?
PS
Do I need volatile var in the actor?
PS2
Also, I'm looking for some more convenient logic for handleResponse, because matching here is very ambiguous...
normal behavior?
Yes, this is absolutely normal behavior.
Your Actor is receiving the Count increments in the order you sent them but the Futures are being completed via submission to an underlying thread pool. It is that indeterminate ordering of Future-thread binding that is resulting in the out of order println executions.
how can I make it ordered?
If you want ordered execution of Futures then that is synonymous with synchronous programming, i.e. no concurrency at all.
do I need volatile?
The state of an Actor is only accessible within an Actor itself. That is why users of the Actor never get an actual Actor object, they only get an ActorRef, e.g. val actorRef = actorSystem actorOf Props[Actor] . This is partially to ensure that users of Actors never have the ability to change an Actor's state except through messaging. From the docs:
The good news is that Akka actors conceptually each have their own
light-weight thread, which is completely shielded from the rest of the
system. This means that instead of having to synchronize access using
locks you can just write your actor code without worrying about
concurrency at all.
Therefore, you don't need volatile.
more convenient logic
For more convenient logic I would recommend Agents, which are a kind of typed Actor with a simpler message framework. From the docs:
import scala.concurrent.ExecutionContext.Implicits.global
import akka.agent.Agent
val agent = Agent(5)
val result = agent()
val result = agent.get
agent send 7
agent send (_ + 1)
Reads are synchronous but instantaneous. Writes are asynch. This means any time you do a read you don't have to worry about Futures because the internal value returns immediately. But definitely read the docs because there are more complicated tricks you can play with the queueing logic.
Real trouble in your approach is not asynchronous nature but overcomplicated logic.
And despite pretty answer from Ramon which I +1d, yes there is way to ensure order in some parts of akka. As we can read from the doc there is message ordering per sender–receiver pair guarantee.
It means that for each one-way channel of two actors there is guarantee, that messages will be delivered in order they been sent.
But there is no such guarantee for Future task accomplishment order which you are using to handle answers. And sending Future from ask as message to original sender is way strange.
Thing you can do:
redefine your Increment as
case class Increment(id: Int, requester: ActorRef) extends ActorMessage
so handler could know original requester
modify CounterActor's receive as
def receive: Receive = {
case Count(id) ⇒ self ! Increment(id, sender)
case Increment(id, snd) ⇒ snd ! {
counter += 1
println(s"req_id=$id, counter=$counter")
counter
}
}
simplify your handleResponse to
def handleResponse(future: Future[Any]): Unit = {
future.onComplete {
case Success(n: Int) => println(s" -> $n")
case Failure(t) => println(t.getMessage)
}
}
Now you can probably see that messages are received back in the same order.
I said probably because handling still occures in Future.onComplete so we need another actor to ensure the order.
Lets define additional message
case object StartCounting
And actor itself:
class SenderActor extends Actor {
val counter = system.actorOf(Props[CounterActor])
def receive: Actor.Receive = {
case n: Int => println(s" -> $n")
case StartCounting =>
counter ! Count(1)
counter ! Count(2)
counter ! Count(3)
counter ! Count(4)
counter ! Count(5)
}
}
In your main you can now just write
val sender = system.actorOf(Props[SenderActor])
sender ! StartCounting
And throw away that handleResponse method.
Now you definitely should see your message handling in the right order.
We've implemented whole logic without single ask, and that's good.
So magic rule is: leave handling responses to actors, get only final results from them via ask.
Note there is also forward method but this creates proxy actor so message ordering will be broken again.

Sequence of actions clean code

I have an actor based application (using akka) written in scala. Now I have an actor that should configure a device in the network by sending it various HTTP-requests in a predefined order.
I encapsulated all the HTTP stuff in a seperate class for my actors to access.
Each of the configuration steps can of course fail so I used Try[Int] as a return type of the methods that handle the communication with the device (returning the HTTP-responsecode as content of the Try).
Now my problem is that every configuration step depends on all steps before to have completed successfully and my code therefore becomes difficult to read (in my oppinion).
I have it implemented basically like this
action1 match {
case Failure(err) => //report error
case Success(retCode) if retCode < 400 =>
nextStep match {
...
}
}
After a few actions this just becomes a massive statement where you cannont see at first glance what is going on.
So how would I go about writing this in a clean-code-ish fashion?
You could implement your sequence of actions as ... sequence of actions:
Blocking version:
def seq: Seq[() => Try[Int]] = ???
// find first failure
def failed: Option[Try[Int]] = seq.view.map{ _() }.find {
case Failure(err) =>
//report error
true
case Success(retCode) => retCode > 400
}
For nonblocking version you should use Future instead of Try:
val seq: List[() => Future[Int]] = ???
def isSuccess(actions: List[() => Future[Int]]): Future[Boolean] = actions match {
case h :: tail => h().flatMap { c =>
if (c > 400) Future(false)
else isSuccess(tail)
}
case Nil => Future(true)
}

How can Scala actors return a value in response to a message?

There are plenty of examples of actors replying with another message back to the sender, but whilst browsing the API docs I noticed the !! and !? operators which are part of the CanReply trait (which seems to be new to 2.8: http://www.scala-lang.org/archives/rc-api/scala/actors/CanReply.html). I was therefore wondering whether it was just a case of having the receive/react block return a value, i.e. make the PartialFunction return type something other than Unit?
I'll start digging through the source to try to work out how they're meant to be used, but if anyone has any insight or knows of any more in-depth documentation or examples then I'd be most grateful.
Cheers,
Paul.
Replies can be sent with the method reply, as shown here:
import scala.actors._
class Reverser extends Actor {
def act() { Actor.loop { react {
case s: String => Thread.sleep(1000); reply(s.reverse)
case _ => exit()
}}}
}
There are three ways to explicitly accept the reply.
Use !!, which returns a Future, which is a container class that promises to give you the contents when you need them. It returns immediately, but if you actually ask for the contents, you have to wait until the other thread is done and fills the request.
Use !? without a timeout. Your code will pause for as long as it takes for the other thread to reply.
Use !? with a timeout. Your code will pause until it gets a reply or until the timeout expires, whichever comes first.
Here's an example of all three:
val r = new Reverser
r.start
val a = (r !! "Hi")
a() match {
case s: String => println(s)
case _ => println("Error A")
}
val b = r !? "Hello"
b match {
case s: String => println(s)
case _ => println("Error B")
}
val c = (r !? (500,"Howdy"))
c match {
case Some(s: String) => println(s)
case Some(_) => println("Error C")
case None => println("Too slow!")
}
r ! None // None isn't a string, so r will stop running
And if you run this you get
iH
elloH
Too slow!