In this post I’d like to talk about some aspects of Akka persistence (being still experimental at the moment of writing). The official documentation does a good job explaining the concept behind the Akka persistence and how to make an actor to be persistent. However I noticed one thing to be confusing to many people when dealing with akka-persistence at the beginning. Persistent View. Before we talk about it let’s start off with the pattern that will help to understand persistent views better.
CQRS (Command Query Responsibility Segregation)
The idea of CQRS pattern is to use a different model to update data and the model to read data instead of more classical way doing CRUD (create, read, update, delete) operations at the same time and place. In terms of CRUD, create, update and delete are Commands and read is Query. One of the architectural patterns CRQS fits with is Event Sourcing (you can read how Akka persistence implements this idea in the official documentation). Before looking at persistent views let’s take a look at non persistent actor first.
CQRS with Non Persistent Actors
Let’s imagine that there is an actor which keeps transactions in its internal state. We can use the same actor for storing new transactions and reading them. One of the issues with such a design is need of having absolutely different representations to display. For instance we would like to show all invalid transactions on the administration panel and the current balance for particular account. The main issue with this is not the code becoming more complex. If the actor is in the middle of updating the state it cannot be queried what makes the system less responsive. To separate commands and queries most likely we will end up with more than one actor (each with its own state reflecting changes from the main actor). It will work pretty well until the main actor (with all the transactions) goes down. When this happens the state is lost forever. The other actors can still function but the data will stay out of sync.
Persistent Views and CQRS
To make it clear the Persistent View is a Query part of CQRS. The persistent actor is used for managing state (persisting events, deleting messages, restoring from the journal, saving the snapshots, etc.). The persistent views are polling message from a persistent actor’s journal directly (instead of being coupled with the persistent actor itself). All they have to know is identifier of the persistent actor. If the persistent actor dies it does not affect the persistent views as they still can serve data from the journal. When the persistent actor is recovered the persistent views will become consistent eventually. Moreover the persistent view can use another sources to optimize data presentation. Basically it’s as simple as that. Use persistent actors for handling commands and persistent views for queries.
Persistent Views in Action
The working demo project can be found here. The source code consists of 3 files where one of them is the persistent actor and another two are the persistent views.
TransactionActor is a persistent actor that persists transactions. All the machinery in the source code is about maintaining and recovering state.
InvalidTransactionsView is a persistent view that shows all invalid transactions. You can see how it’s decoupled from the
TransactionActor. Another persistent view is
BalanceView. Instead of keeping the list of transactions it keeps a map where stores the current amount per account. In traditional approach both persistent views would be the methods of the same object. In case of separate views even if the persistent actor and one of the views die the remaining view will be able to process the queries.
I think Persistent Views play an important role when using event sourcing. They help to follow CQRS pattern more easily than ordinary actors. I would even say that they are as important as the persistent actors. I hope the official documentation will be more verbose about them and that this analogy with CQRS can help to develop intuition.