Search code examples
nservicebusnservicebus-sagas

nservicebus calling a Saga from within another Saga


I'm new to NServiceBus and trying to find the best way to model a scenario which uses compensating transactions.

For example, say I have a typical BookHotel scenario:

In the happy case, the messaging flow would proceed as follows:

  1. BookHotelCommand --> BookHotelSaga
  2. BookFlightCommand --> Reply IFlightBookedMessage
  3. BookRentalCommand --> Reply IRentalBookedMessage
  4. ReplyToOriginator --> HotelBookedMessage

How would I model compensating transactions in the above flow? I was initially thinking of calling a "UnbookHotelSaga" in one of the replies above, based on some business conditions. However, I seem to be running into some challenges with getting this working. Can someone with Saga experience comment if this is the right approach.

Here is the scenario I was thinking would work by calling another Saga:

  1. BookHotelCommand --> BookHotelSaga
  2. BookFlightCommand --> Reply IFlightBookedMessage
  3. BookRentalCommand --> (condition satisfied) --> UnbookHotelCommand --> UnbookHotelSaga
  4. UnbookRentalCommand --> Reply IUnbookRentalMessage
  5. UnbookFlightCommand --> Reply IUnbookFlightMessage
  6. UnbookHotelCommand --> ReplyToOriginator --> UnbookedHotelMessage

Can someone please advise on the best-practices approach to implementing compensating transactions?


Solution

  • I'm not really sure I understand the long running process and what it should do. Some more information on functionality would probably help.

    One of the first things I noticed was mentioning of IUnbookRentalMessage. First of all, don't use I at the start of messages. The fact that they can be interfaces, has to do with polymorphism and multiple inheritance features of .NET. Messages themselves have no technical meaning on the wire and you should therefore not include the I.

    Also, commands are in imperative tense and events in past tense. So BookFlight for a command and FlightBooked for an event.

    You could theoretically create multiple sagas that all take part in a single long running business process. A saga called BookingPolicy or BookingProcess or BookingSaga to orchestrate the entire process. And FlightBookingPolicy for the flight and HotelBookingPolicy for the hotel.

    If you start out with a BookFlight command, the FlightBookingPolicy could publish an event called FlightBooked. The BookingPolicy could use that event to start its own instance of the saga. So for example, the (ASP.NET) website that sends all the commands, would not have to know about the BookingPolicy. It just sends the appropriate commands with the appropriate data. The same goes for hotel, car, etc.

    Then at some point, the website sends a CommitBooking or FinishUpMyVacation command, which does arrive at the BookingPolicy saga and that finalizes the entire booking. It sends an event BookingFinishingUp or something. Based on that event, some handler might deduct money from a creditcard. Another handler does integration with 3rd parties to actually submit the vacation. Another handler sends out emails. Etcetera.

    Finally when the BookingPolicy (or even another saga) is finished, the BookingPolicy saga will publish an event called BookingFinished and the appropriate FlightBookingPolicy and HotelBookingPolicy and CarBookingPolicy also wrap up and end their work. Whatever that may be.

    Does that make sense? If you want, you can also continue the conversation on https://discuss.particular.net/ or [email protected].