ChangeEventHandler no-op

I’m currently building a small project to understand how to best use an Akka Durable State entity alongside with a ChangeEventHandler so I can project journal events downstream. I wanted to add query Command that would return the latest State information back to the caller. However when I do that I am forced to handle that case in the ChangeEventHandler and persist an event for this query. That event wouldn’t really be an event about the system and would just clog up the journal.

trait Command
case class UpdateEntity(id: UUID, payload: String) extends Command
case class GetEntity(id: UUID): String extends Command

trait Event
case class EntityUpdated(payload: String) extends Event
case class EntityStateRetrieved extends Event // This seems like a wasteful event to persist in the journal

private val stateChangeEventHandler = ChangeEventHandler[Command, State, Event](
   updateHandler = {
          case (_, _, UpdateEntity(id, payload)) => EntityUpdated(payload) 

          case (_, _, GetEntity(id)) =>  EntityStateRetrieved //I'm forced to handle this and persist an event for a GET command,
   },
   deleteHanlder = { ... }
)

What is the best way to approach this? I would prefer to get the state through the entity itself but I don’t want to be forced to persist an event that doesn’t match the domain behaviour of the entity. I would have thought that it may be similar to event-sourced behaviour Effect.persist(Seq[Event]) where Seq could be empty.

Thank you

After looking through the implementation, the updateHandler should only be called if there’s an Effect.persist (vs., for instance, Effect.none) returned from the command handler.

So I think is just the Scala compiler warning about exhaustiveness of the pattern match, in which case you could satisfy the compiler with something like:

case (_, _, GetEntity(_)) => ???  // GetEntity does not update state, so this should never be hit

(or if some linting about ??? is in use, an equivalent throw: AssertionError (to indicate that this (GetEntity updating state) is a bug in the code) might be the most appropriate throwable for this).

Conceivably the implementation could change to compare the new state with the old state and only call the updateHandler if there’s a change, though that depends on equals being implemented (and there’s some recent controversy in the DDD world about whether equals/hashCode should be overridden for entities…).

That makes sense, thank you for the sanity check. I may have also just done something wrong in my implementation and misunderstood the error I was getting.

I think that it is an oversight in the new ChangeEventHandler API that you cannot signal that there is no change for a command, I’ve created an issue to track improving this: No way to signal no change with ChangeEventHandler · Issue #32310 · akka/akka · GitHub

1 Like

I might suggest it should mimic the API of Effect.persist, accepting a Seq[Event], allowing the client to persist 0 to many events.

As Patrik mentioned in the issue, that is not possible as change events sequence numbers must be in sync with the durable state revision number. It must always be a 1:1 with actual updates.

I don’t think there is a way to design our way out of that, so we will document more clearly that commands not leading to an update is never fed to the ChangeEventHandler but that the type system can’t know that and catch-throw-illegal-argument or something is reasonable.