Hi Sebastian, Validation should be done before persist, and your code is correct. Exceptions from validation should not be thrown, your conclusion is correct.
Regarding unforeseen bugs, NPE, it can be better in a production system to survive also that by restarting (perhaps it was just a corner case). What would the alternative be? Exit the JVM? The bug should of course be fixed, but that can be done on Monday if the exception was thrown during the weekend. /Patrick > On Sep 5, 2017, at 16:09, Sebastian Oliveri <[email protected]> wrote: > > > I am going to describe a concrete scenario I have: "an item can be removed > from the menu" > > class MenuActor extends PersistentActor { > > var state: Option[Menu] = None > > override def receiveCommand: Receive = { > > case remove: RemoveItem => > persist(MenuItemRemoved(remove.itemId)) { > event => > state = state.map(_.remove(event.itemId)) > sender ! state.get > } > // ... other handlers > } > } > > The Menu aggregate root raises a BusinessException("$itemId does not exist") > if obviously the item identified by the given ID does not exist in the Menu. > > In the concrete case of an HTTP client this error would be map to a 400 > status code containing the descriptive message as any other "breaking > aggregate invariant" scenario. > > What I am doing right now is this: > > class MenuActor extends PersistentActor { > > var state: Option[Menu] = None > > override def receiveCommand: Receive = { > case remove: RemoveItem => > try { > val newState = state.map(_.remove(remove.itemId)) // -> 1 > persist(MenuItemRemoved(remove.categoryId)) { > event => > state = newState // -> 2 > sender ! state.get > } > } catch { > case businessException: BusinessException => sender() ! > Failure(businessException) // -> 3 > } > // ... other handlers > } > } > > 1 -> I mutate the actor state before persisting the event since that is the > aggregate mutating behaviour that raise an exception when an invariant is > violated. > All the samples I saw mutates the internal actor state in the event handler > closure after persisting the event but if the aggregate consistency is > violated and it throws a business exception then we would have an > inconsistent state of the journal containing an event that should not be > there. > > 2 -> In order to prevent what I mentioned in the previous point I just assign > the actor state to be the new state (aggregate mutation before persist) > > 3 -> If the aggregate raises an exception we don´t save the event in the > journal, instead we send back a Failure message that maps to a Future.failed > in the client who asked this actor and so we can give feedback to any client > source about this business exception. > > > A )Is this OK? If not... how is handled? > > I´ve seen in the docs that after sending back the Failure message, the > exception is re-thrown so supervision takes place: > > } catch { > case businessException: BusinessException => { > sender() ! Failure(businessException) > throw businessException // supervision take places > } > } > Why to do that? The default supervision strategy will Restart the actor, but > I don´t need the actor to be restarted, resumed would be OK, however... I > just leave the actor as it is since the code above prevented the state to be > mutated and the client who asked this actor is notified about the business > exception. > > B) Should I throw the businessException after sending back the Failure to the > sender? Why? Why to restart the actor? > > C) Last question, I´ve seen examples of supervision expecting > NullPointerException, arithmeticException and so on... those sound bugs to > me, unexpected exceptions other than network failures and so shouldn't´t be > supervised but fixed. I understand the situation where a Backoff supervisor > sounds reasonable to deal with network failures but I don´t see why to > supervise exceptions that are caused because of bugs like the ones mentioned > before (matching doc examples) > > > Thanks, > Sebastian > > > > > -- > >>>>>>>>>> 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. -- >>>>>>>>>> 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.
