I want to use SAGA pattern in my Spring Boot Microservices. For example in order of customer, when the order created, an event like OrderCreatedEvent
produced and then in customer microservice the listener on OrderCreatedEvent
Update the customer credit and produce CreditUpdateEvent
and ... .
I use session transacted JmsTemplate
for event producing. In javadoc of JmsTemplate
said that the JMS transaction commited after the main transaction:
This has the effect of a local JMS transaction being managed alongside the main transaction (which might be a native JDBC transaction), with the JMS transaction committing right after the main transaction.
Now My question is how can I handle below scenario:
The main transaction committed (for example order recored committed) and system was unable to commit the JMS transaction (for any reason).
I want to use SAGA instead of two phase commit but I think just SAGA move the problem from order and customer service to order service and JMS provider.
SAGA hints the issue:
There are also the following issues to address:
...
- In order to be reliable, a service must atomically update its database and publish an event. It cannot use the traditional mechanism of a distributed transaction that spans the database and the message broker. Instead, it must use one of the patterns listed below.
...
The following patterns are ways to atomically update state and publish events:
- Event sourcing
- Application events
- Database triggers
- Transaction log tailing
Event Sourcing is special in this list as it brings radical change on how your system stores and processes data. Usually, systems store only the current state of the entities. Some systems add explicit support for historical states with validity periods and/or bitemporal data.
Systems which are based on Event Sourcing store the sequence of events instead of entity state in a way that allows it to reconstruct the state from events. There is only one transactional resource to maintain - event store - so there is no need to coordinate transactions.
Other patterns in the list avoid the issue of transaction coordination by requiring the event producer code to commit all changes - both entities state and events (as entities) - to the single data store. Then a dedicated, but separate mechanism - event publisher - is implemented to fetch the events from the data store and publish them to the event consumers.
Event publisher would need to keep the track of published / unpublished events which usually brings back the problem of coordinated transactions. That's were the idempotency of the event consumers comes to light. Event publisher will replay events from the last known position while consumers will ignore duplicates.
You may also reverse the active / passive aspects of the event producer and event consumer. Event producer stores entities state and events (as entities) to the single data store and provides an endpoint which allows event consumer to access event streams. Each event consumer keeps track of processed / unprocessed events - which it needs to do anyway for idempotency reasons - but only for event streams it is interested about. A really good explanation of this approach is given in the book REST in Practice - chapters 7 and 8.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With