Any ideas on how to make transaction with reactor/webflux

Viewed 43

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

0 Answers
Related