A lot of this is informed by experiences with sync and it’s use cases. There, a sync record is stored and transmitted between systems, and that sync record is a serialized representation of all of the entities that were saved together in a single transaction.
In other cases, I have found that we want to, say, update an MPI / CR any time a patient’s demographics have changed. There are a few pieces to that:
a) If we detect a change to Person, PersonName, PersonAddress, 3 Person Attributes, 2 Patient Identifiers, etc. we don’t want this to result in sending 8+ separate messages to update an external system, we just want to detect this as a single update event.
b) If we just look for changes to, say, Patient - I am not 100% convinced that our uses of Hibernate and services and cascading entities and such will actually fire a Patient UPDATED event for associated patient data changes. For example, if a PersonAttribute is changed, and this is saved via a call to PersonService.savePersonAttribute, does this result in a dirty flush to the Person object that Hibernate detects and issues a Person updated event for? This is even more true in a Debezium-fed model. This issue doesn’t really go away with the design we have in place, but by not firing events strictly based on entity type, it makes it more of a business decision for a listener to listen for all events, and determine if any of the entity changes it contains should result in some sort of action.
If this works, then great! But I would want to make 100% sure it actually does what we think it will do. I assume AFTER_COMMIT only fires if the commit was successful, and not fired on rollback?
This is still already in place in the events module. I mean, there was always a Hibernate interceptor that listened for entity changes. Prior to version 4.0.0, this just always fired these out asynchronously on a JMS queue by type, and one would subscribe to a type. That still happens today in the 4.0.0+ world - it just happens in a TransactionEventListener that listends for a TransactionCommittedEvent, and iterates over the entities that were committed and fires the exact same events out at that stage.
So within the current event module design, we would simply create a TransactionEventListener that listens for a TransactionBeforeCompletionEvent, and either writes the individual entity changes or some serialized representation (like sync does) of all entity changes in the event, to the outbox table transactionally, so that it would either succeed or fail along with the source transaction. If there are cleaner and better ways to do this, fine by me as long as it works.
We should definitely do this, regardless of which approach we take.