Are there any drawbacks, sending (a lot of) multiple commands in saga

I made a module for handling transaction in saga. As far as I understand there’s no rollback strategy in saga (ACID) so if there’s an exception thrown we have to rollback state by manually publish commands/events in saga and it makes the code a bit hard to read and understand (maybe just for me). So my module would look like this.

public void on(event: BookHotelRoomRequestedEvent) {
     // if exception raises execute compensation action in reverse order.
     Transaction.create()
                .addExecution(::sendReserveHotelCmd.withCompensation(::sendUnreserveHotelCmd)) 
                .addExecution(::sendApplyCouponCmd.withCompensation(::sendUnapplyCouponCmd))
                .addExecution(::sendMakePaymentCmd)
                .start();
}

one thing that I notice is that it would take a lot of time to handle just 1 event if I use this approach because I send a lot of commands in one place. Are there any drawbacks that I should concern using this approach.

The most evident drawback I can think of is the point you raise about “event handling takes longer.”
Axon Framework’s Streaming Event Processors, which I anticipate you’re using, use a so-called token to:

  1. Track the progress through the event store
  2. Share the work between different threads

Point one is covered by the token containing the globalIndex, thus the position within the event stream.
Pointe two is covered by a Streaming Processor’s threads claiming a token.

Now, it’s this claim that, if left unchecked, could block other processes from performing any work.
To battle this, Axon Framework puts a timeout on these claims.
If this timeout is met, other threads (either on that JVM or on other JVM’s) are allowed to steal the token.

This timeout is more easily met if event handling takes to long.
Henceforth, you’ve two roads to take:

  1. Extending the claimTimeout of the TokenStore. This will impact all Event Processors using that TokenStore, which may be undesirable.
  2. Split the Saga’s processes into separate steps instead of one major task.

In all honesty, I’d prefer to move to option two.
This will mean a single command is executed, with a single compensating action if it fails.
The subsequent commands can then be taken care of as a reaction to handling the event originating from the previous task.
Whether that’s feasible within your application is another story, of course.

I hope this provides you with some guidance, @Lincoln_Burrows!