You might wonder why don't I use @Transaction which spring already provided. I wanted too, but I'm doing event-sourcing anything that happened can't be changed or rollback. So I need to manually publish another compensation event which solve the previous one that already happened. More over I'm using project reactor so I'm kinda stuck on how should I design to make it works.
Let's say in case of hotel reservation I would have these process. So when the makePayment is failed I should rollback transaction by publish compensation events like this.
// pb stands for publish
Mono.just("start_transaction")
.flatMap { reserveHotelRoom(roomId) } pb RoomReservedEvent v ^ pb RoomUnreservedEvent
.flatMap { applyDiscount(coupon) } pb CouponRedeemedEvent v ^ pb CouponUnredeemedEvent
.flatMap { makePayment(bankAccount) } pb paymentHasbeenMadeEvent v -> oops error happens xD ^
This is what I have tried so far, but it doesn't work. once error has been thrown it still execute the next process so I have to continue working on it, but hope you get an idea of what I'm trying to do so.
class ReactiveTransaction() {
private var aggregators = Mono.just("_start_transaction_")
private var compensationAction = Mono.just("_start_rollback_")
fun addExecution(execution: Mono<String>, onError: Mono<String>): ReactiveTransaction {
// i don't know how to clone mono object so this is the current solution
val temp = compensationAction.flatMap { onError }
compensationAction = temp
aggregators = aggregators.flatMap { execution }
.onErrorResume { temp }
.checkpoint()
return this;
}
fun execute(): Mono<String> {
return aggregators
}
}
fun main() {
ReactiveTransaction().addExecution(reserveHotel, unreserveHotel)
.addExecution(applyDiscount, unapplyDiscount)
.addExecution(makePayment, cancelPayment)
.execute()
}
Is this design valid what should I concern ? or any library that can handle this problem recommend?
update: I use mongodb as my event store with reactive repository