Scalera tips: How NOT to change your actor’s state

A common key when working with Akka, is modifying properly our actor’s state. If we jog our memory, this framework paradigm allows us to program modeling the concurrency based on actors and message passing. From that base, we could define an actor as a computing unit that may have state and perform tasks based on messages that it will receive through its mailbox and that will be processed sequentially .

That means that, in order to avoid side effects, the actor’s state modification has to take place when processing a message. So senseful so far. However, it’s a pretty common mistake to do something similar to this:

class MyActor extends Actor {

  var state: Int = 0

  def receive = {

    case "command" => 
      Future(state = 1)

    case "someOtherCommand" => 
      state = 2

  }

}

In this case, we have no more warranty that the state change (whose only responsible of keeping it consistent and thread safe is the actor) might cause side efects given that, in the precise moment where the Future modifies the var, it’s possible that the state is being modified by the actor itself (probably as a reaction to some other received message).

This Future[Unit] might not be a block like that. It could be the result of having asked to some other actor:

class MyActor extends Actor {

  type State = Int

  var state: State = 0

  def receive = {

    case "command" => 
      (service ? "giveMeMyNewState").map{
        case newState: State => state = newState
      }

    case "someOtherCommand" => 
      state = 2
  }

}

Something that probably none of us has ever tried.

giphy

The proper way

If we want to modify the actor’s state as result of having previously asked to some other actor and without breaking the concurrency control of the actor, it could be achieved like this:

class MyActor extends Actor {

  type State = Int

  var state: State = 0

  def receive = {

    case "command" => 
      (service ? "giveMeMyNewState") pipeTo self

    case "someOtherCommand" => 
      state = 2

    case newState: State => 
      state = newState
  }

}

With pipeTo we specify to send to certain actor the result of having evaluated some future when its resolved. This way we’re indicating that, when we get the response of the other actor, it will be sent to our mailbox, so it will be processed like a normal message, sequentially.

bill_murray_gif_1

Easy peasy 🙂

Anuncios

3 thoughts on “Scalera tips: How NOT to change your actor’s state

  1. Some people have asked about why doing

    (service ? “giveMeMyNewState”) pipeTo self

    when it clearly does the same as sending a message with ‘tell’ and expects for an incoming message in the mailbox.

    Imagine this actor you’re asking sends back a message that your actor doesn’t know how to handle. With the proposed way, you could map it to anything else (adding some metadata or whatever) that fits into your actor’s behavior.

    (service ? “giveMeMyNewState”).map((msg:Any) => /* Make it fit */) pipeTo self

    Me gusta

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s