Implementing Lagom Readside Persistence Using Slick

Persistent Entities in Lagom hold state of individual entities. In other words, they cannot be used to serve queries that span more than single entity. This requires us to create another view of the data that is tailored to serve rather optimized queries that span over multiple entities, which brings us to the most talked about separation of the write-side and the read-side of the persistent data, also known as CQRS (Command Query Responsibility Segregation) pattern.

In this blog post I would like to demonstrate how read side persistence is implemented in Lagom using Slick which is a modern database query and access library for Scala that allows us to write database queries in Scala thus profiting from static checks, compile-time safety and compositionality of Scala.

Dependencies

Lagom's Slick support is build on top of it’s support for storing persistent entities in a relational database. This requires us to add lagomScaladslPersistenceJdbc as our dependency. We would also require to add a JDBC database connector driver of our choice. We will be using mysql connector for this demo.


Notice that we don't require Slick dependency, for it being natively supported by the framework itself.

Configurations

Lagom uses Play’s JDBC support to configure and create a connection pool, which requires us to provide details, such as, JDBC driver, database URL, etc in the application.conf to help Lagom with the same. We also need to configure a correct Slick profile, which is slick.jdbc.MySQLProfile$ in our case. These profiles abstract relevant SQL dialect, data type encodings, or other idiosyncracies.

Application Loader

Next we need our application loader to load relevant read-side persistence components which includes ReadSideSlickPersistenceComponents and HikariCPComponents.


Note: Please be informed that the order in which the traits ReadSideJdbcPersistenceComponents and WriteSideCassandraPersistenceComponents are extended to create EmployeeApplication is of grave importance due to a bug in Lagom which requires trait ReadSideJdbcPersistenceComponents to be mixed in before the trait WriteSideCassandraPersistenceComponents.

Model Entities

Let's now model our employee entity as Slick table definition as shown below.

Query Readside

Lagom makes use of the database configurations from our application.conf to create and inject an instance of Slick Database required as a dependency in our repository.


Unlike get queries, createTable, addEmployee and updateEmployee queries return Slick DBIOAction as required by ReadSideProcessor.ReadSideHandler that handles events generated by Persistent Entities, which I'll introduce later. It is the Slick’s Database which facilitates the execution of these DBIOAction.

Slick’s Database also manages the execution of blocking JDBC calls in a thread pool designed to handle them, which is why db.run() API returns a Future.

Update Readside

Every state change in a Persistent Entity is persisted in Cassandra as logs of historical events, which is how Lagom implements what's called as Event Sourcing. It is in response of the persistence of these events that the read-side is required to update the read-side data model. Lagom has a built in support for populating the read-side view out of the box. This is achieved by implementing a ReadSideProcessor with assistance from the SlickReadSide support component.


The ReadSideProcessor implementation must implement a buildHandler that returns a ReadSideHandler, which is used by Lagom to prepare read-side processing and eventually handle the events returned by aggregateTags method definition. All events with a particular tag are consumed as a sequential, ordered stream of events. You can refer Lagom documentation to learn how tags are implemented.

Now the Lagom's built in support comes into play when you extend ReadSideSlickPersistenceComponents trait in your application loader.


As you can see, besides bringing in Slick Database and JdbcProfile right from our application.conf as we discussed above, the ReadSideSlickPersistenceComponents trait also brings in an implementation of SlickReadSide.


It is this SlickReadSide implementation that implements a ReadSideHandler builder out of the box for us. We can now implement our ReadSideProcessor as shown below.


The event handlers processEmployeeAdded and processEmployeeUpdated eventually ask our repository implementations to return DBIOAction in response to respective events that these handlers are registered against.

And this is how we implement read-side persistence in Lagom using Slick. You can find the complete working implementation here on github.

Show Comments