Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does event tagging work in Lagom?

Tags:

scala

lagom

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?

  • If it is the desired behaviour, then one should not tag a sealed trait event (and probably this need update in the documentation)
  • If is the desired behaviour, then JDBCReadSideImpl and SlickReadSideImpl cannot use a map from classname to handler.
like image 366
Edmondo1984 Avatar asked Jan 01 '26 10:01

Edmondo1984


1 Answers

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.

like image 55
Tim Moore Avatar answered Jan 03 '26 13:01

Tim Moore



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!