Lagom reference documentation shows how to tag events:
object BlogEvent {
val BlogEventTag = AggregateEventTag[BlogEvent]
}
sealed trait BlogEvent extends AggregateEvent[BlogEvent] {
override def aggregateTag: AggregateEventTag[BlogEvent] =
BlogEvent.BlogEventTag
}
The sealed trait suggest one can tag a parent Event to get all children been processed in order:
All events with a particular tag can be consumed as a sequential, ordered stream of events.
So we went this way, we tagged our parent event and we implemented one ReadSideProcessor using slick and it didn't worked. Increasing the logging level we saw an "unhandled message" and we found out the following in SlickReadSideImpl
:
override def handle(): Flow[EventStreamElement[Event], Done, NotUsed] =
Flow[EventStreamElement[Event]]
.mapAsync(parallelism = 1) { element =>
val dbAction = eventHandlers.get(element.event.getClass)
.map { handler =>
// apply handler if found
handler(element)
}
.getOrElse {
// fallback to empty action if no handler is found
if (log.isDebugEnabled) log.debug("Unhandled event [{}]", element.event.getClass.getName)
DBIO.successful(())
}
.flatMap { _ =>
// whatever it happens we save the offset
offsetDao.updateOffsetQuery(element.offset)
}
.map(_ => Done)
slick.db.run(dbAction.transactionally)
}
The eventHandlers.get(element.event.getClass)
above fails to find any handler if the class doesn't exactly match the class for which the handler was registered, for example it is a subclass (our case).
This is somehow confusing: is this the desired behaviour or is it a bug in the implementation of the JDBCReadSideImpl
and SlickReadSideImpl
?
This is working as intended. The expectation is that you will want to handle concrete event types in different ways, so you will register a handler for each concrete type.
The point of tagging all of the event subtypes with the same tag is to ensure ordering between different types of events on the same entity. For example, if you have a BlogCreatedEvent
and a BlogPublishedEvent
then you would want to be sure that your processor receives the created event before the published event, even if it handles them differently.