15
votes

I'm just starting to learn Akka Actors in Scala. My understanding is that messages received by an Actor are queued in an Actor's mailbox, and processed one at a time. By processing messages one at a time, concurrency issues (race conditions, deadlocks) are mitigated.

But what happens if the Actor creates a future to do the work associated with a message? Since the future is async, the Actor could begin processing the next several messages while the future associated with the prior message is still running. Wouldn't this potentially create race conditions? How can one safely use futures within an Actor's receive() method to do long running tasks?

3
do you mean action associated with the future operates on the variables internal to the actor? then yes, it is a race condition.Alexei Kaigorodov

3 Answers

27
votes

The safest way to use futures within an actor is to only ever use pipeTo on the future and send its result as a message to an actor (possibly the same actor).

import akka.pattern.pipe

object MyActor {

  def doItAsynchronously(implicit ec: ExecutionContext): Future[DoItResult] = { 
  /* ... */ 
  }

}

class MyActor extends Actor {

  import MyActor._    
  import context.dispatcher  

  def receive = {
    case DoIt =>
      doItAsynchronously.pipeTo(self)
    case DoItResult =>
       // Got a result from doing it
  }

}

This ensures that you won't mutate any state within the actor.

0
votes

If you need to mutate state in futures without blocking incoming messages you might want to reconsider redesigning your actor model. I would introduce separate actors for each task you would use those futures on. After all, an actor's main task is to maintain its state without letting it escape thus providing safe concurrency. Define an actor for those long running task whose responsibility is only to take care of that.

Instead of taking care of the state manually you might want to consider using akka's FSM so you get a much cleaner picture of what changes when. I presonally prefer this approach to ugly variables when I'm dealing with more complex systems.

0
votes

Remember two things

  1. The notion behind the term Future(a special actor) is that we can create an actor for any result while it(the result) is still being computed, started or finished but we can't have an address for that special actor or future.

  2. Suppose I want to buy something (my result is buying something, and the process it to initiate steps to start buying procedure) we can create an actor for the result (buy) but if there is any problem and we can't buy the thing we will have an exception instead of the result.

Now how the above two things fit is explained below-

Say we need to compute the factorial of 1 billion we may think that it will take a lot of time to compute but we get the Future immediately it will not take time to produce the Future (" Since the future is async, the Actor could begin processing the next several messages while the future associated with the prior message is still running."). Next, we can pass this future, store it and assign it.

Hope so you understand what I'm trying to say.

Src : https://www.brianstorti.com/the-actor-model/