Search code examples
akkapersistence

akka persist function is not handled every time


I use akka's PersistentActor with sharding in a cluster to keep track of my state. I have a 'Room' which i can update via following code:

case UpdateRoom(id, room, userId) => ((ret: ActorRef) => {
  (userRegion ? GetRoleForRoom(userId, id)).mapTo[String] map { role =>
    if (role == "owner") {
      state = Some(room)
      ret ! Success(room)
      eventRegion ! RoomEventPackage(id, RoomUpdated(room))
      println("works")
      persist(RoomUpdated(room))(e => println("this doesn't always fire")
    } else {
      ret ! Failure(InsufficientRights(role, "Update Room"))
    }
  }

Problem is that persist only works every other time while the rest of the function works as expected. ("works" gets printed every time, "this doesn't always fire" every other but then two times). I always have to fire the update command two times to store my Event, but then it appears to be stored for both times i fired the command.

Am i missing an important part of akka persist?


Solution

  • I think that you are making a grave mistake in the world of Actor: accessing the actor (mutable) state from outside. In your case, this happens twice from within the callback of the Future returned by ask/?:

    • when updating state: state = Some(room)
    • when calling persist

    The only safe way to deal with asking from within your Actor and subsequently modifying the actor's state, is to send a message to the same actor from ask's callback, to that end, you can use pipeTo.

    Using a simplified version of your code to illustrate:

    case UpdateRoom(id, room, userId) => 
      val answer = (userRegion ? GetRoleForRoom(userId, id)).mapTo[String] map(role => RoleForRoom(id, room, userId, role))
      answer piepTo self
    case RoleForRoom(id, room, userId, room) => 
      if (role == "owner") {
        state = Some(room)
        eventRegion ! RoomEventPackage(id, RoomUpdated(room))
        persist(RoomUpdated(room))(e => println("this is safe"))
      }
    

    see also: https://doc.akka.io/docs/akka/2.5.6/scala/general/jmm.html#actors-and-shared-mutable-state