Handling Failures with Compensating Transactions in Sagas

Provide an example of handling failures in a saga in JavaScript with compensating transactions for a booking system where a failure in booking a hotel leads to canceling the flight reservation.
class BookingSaga {
  constructor(bookingService, flightService) {
    this.bookingService = bookingService;
    this.flightService = flightService;

  async bookTrip(userId, tripDetails) {
    try {
      // Step 1: Reserve a flight
      const flight = await this.flightService.reserveFlight(tripDetails.flight);
      console.log('Flight reserved', flight);

      // Step 2: Book a hotel - If fails, compensate previous steps
      const hotel = await this.bookingService.bookHotel(tripDetails.hotel);
      console.log('Hotel booked', hotel);

      // If both steps are successful, return booking details
      return { flight, hotel };
    } catch (error) {
      console.error('Booking failed', error);
      // Compensating transaction for flight reservation
      await this.flightService.cancelFlight(tripDetails.flight);
      console.log('Flight reservation canceled');
      throw error; // rethrow the error after compensation
This JavaScript class 'BookingSaga' handles a travel booking process as a saga. It tries to reserve a flight and book a hotel sequentially. If the hotel booking fails, it compensates by canceling the already reserved flight, ensuring system consistency despite the partial failure.