Skip to content

Commit

Permalink
Merge pull request #7 from Tech-Fabric/refactor-purchase-workflow
Browse files Browse the repository at this point in the history
Refactor purchase workflow
  • Loading branch information
Vlandrik authored Feb 9, 2024
2 parents 122f1e2 + e11b981 commit fe325f3
Show file tree
Hide file tree
Showing 22 changed files with 264 additions and 210 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -363,3 +363,4 @@ FodyWeavers.xsd
/Monolith/.idea
/temporal-server/db_data
/.idea
/temporal-server/temporal_db_data
8 changes: 4 additions & 4 deletions TemporalAirlinesConcept.Api/Controllers/FlightsController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public FlightsController(IFlightService flightService)
[HttpGet]
public async Task<ActionResult<IEnumerable<DAL.Entities.Flight>>> GetFlights()
{
var flights = await _flightService.GetFlightsAsync();
var flights = await _flightService.GetFlights();

return Ok(flights);
}
Expand All @@ -28,7 +28,7 @@ public FlightsController(IFlightService flightService)
[HttpGet("{id}")]
public async Task<ActionResult<DAL.Entities.Flight>> GetFlight(string id)
{
var flight = await _flightService.GetFlightAsync(id);
var flight = await _flightService.GetFlight(id);

return Ok(flight);
}
Expand All @@ -37,7 +37,7 @@ public FlightsController(IFlightService flightService)
[HttpPost]
public async Task<ActionResult<DAL.Entities.Flight>> CreateFlight(FlightInputModel model)
{
var createdFlight = await _flightService.CreateFlightAsync(model);
var createdFlight = await _flightService.CreateFlight(model);

return CreatedAtAction(nameof(GetFlight), new { id = createdFlight.Id }, createdFlight);
}
Expand All @@ -46,7 +46,7 @@ public FlightsController(IFlightService flightService)
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteFlight(string id)
{
await _flightService.RemoveFlightAsync(id);
await _flightService.RemoveFlight(id);

return NoContent();
}
Expand Down
18 changes: 9 additions & 9 deletions TemporalAirlinesConcept.Api/Controllers/TicketsController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,29 +17,29 @@ public TicketsController(ITicketService ticketService)
}

[HttpPost("purchase")]
public async Task<ActionResult<string>> PurchaseTicketAsync(PurchaseModel purchaseModel)
public async Task<ActionResult<string>> PurchaseTicket(PurchaseModel purchaseModel)
{
return Ok(await _ticketService.RequestTicketPurchaseAsync(purchaseModel));
return Ok(await _ticketService.RequestTicketPurchase(purchaseModel));
}

[HttpGet("by-user/{userId}")]
public async Task<ActionResult<string>> GetTicketsAsync([FromRoute] string userId)
public async Task<ActionResult<string>> GetTickets([FromRoute] string userId)
{
var tickets = await _ticketService.GetTickets(userId);

return Ok(tickets);
}

[HttpGet("{userId}/{flightId}")]
public async Task<ActionResult<string>> GetTicketAsync([FromRoute] string userId, [FromRoute] string flightId)
public async Task<ActionResult<string>> GetTicket([FromRoute] string userId, [FromRoute] string flightId)
{
var tickets = await _ticketService.GetTickets(userId, flightId);

return Ok(tickets);
}

[HttpGet("{ticketId}")]
public async Task<ActionResult<Ticket>> GetTicketAsync([FromRoute] string ticketId)
public async Task<ActionResult<Ticket>> GetTicket([FromRoute] string ticketId)
{
var ticket = await _ticketService.GetTicket(ticketId);

Expand All @@ -55,14 +55,14 @@ public async Task<ActionResult<Ticket>> MarkAsPaid([FromRoute] string purchaseWo
}

[HttpPost("check-in")]
public async Task<ActionResult<bool>> ReserveSeatAsync(SeatReservationInputModel seatReservationInputModel)
public async Task<ActionResult<bool>> ReserveSeat(SeatReservationInputModel seatReservationInputModel)
{
return Ok(await _ticketService.RequestSeatReservationAsync(seatReservationInputModel));
return Ok(await _ticketService.RequestSeatReservation(seatReservationInputModel));
}

[HttpPost("board")]
public async Task<ActionResult<bool>> BoardPassengerAsync(BoardingInputModel boardingInputModel)
public async Task<ActionResult<bool>> BoardPassenger(BoardingInputModel boardingInputModel)
{
return Ok(await _ticketService.BoardPassengerAsync(boardingInputModel));
return Ok(await _ticketService.BoardPassenger(boardingInputModel));
}
}
6 changes: 3 additions & 3 deletions TemporalAirlinesConcept.Api/Controllers/UsersController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public UsersController(IUserService userService, IUserRegistrationService userRe
[HttpGet]
public async Task<ActionResult<IEnumerable<DAL.Entities.User>>> GetUsers()
{
var users = await _userService.GetUsersAsync();
var users = await _userService.GetUsers();

return Ok(users);
}
Expand All @@ -31,7 +31,7 @@ public UsersController(IUserService userService, IUserRegistrationService userRe
[HttpGet("{id}")]
public async Task<ActionResult<DAL.Entities.User>> GetUser(string id)
{
var user = await _userService.GetUserAsync(id);
var user = await _userService.GetUser(id);

return Ok(user);
}
Expand Down Expand Up @@ -67,7 +67,7 @@ public async Task<IActionResult> RegisterUser(UserRegistrationModel model)
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteUser(string id)
{
await _userService.RemoveUserAsync(id);
await _userService.RemoveUser(id);

return NoContent();
}
Expand Down
2 changes: 1 addition & 1 deletion TemporalAirlinesConcept.Common/Helpers/Saga.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public void AddCompensation(Func<Task> compensation)
_compensations.Push(compensation);
}

public async Task CompensateAsync()
public async Task Compensate()
{
var i = 0;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace TemporalAirlinesConcept.Common.Helpers;

public class WorkflowHandleHelper
{
public static async Task<bool> IsWorkflowExists<T>(ITemporalClient client, string workflowId)
public static async Task<bool> IsWorkflowRunning<T>(ITemporalClient client, string workflowId)
{
var handle = client.GetWorkflowHandle<T>(workflowId);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,34 +17,34 @@ public FlightActivities(IUnitOfWork unitOfWork, IMapper mapper)
}

[Activity]
public async Task<FlightDetailsModel> MapFlightModelAsync(DAL.Entities.Flight flight)
public Task<FlightDetailsModel> MapFlightModel(DAL.Entities.Flight flight)
{
return _mapper.Map<FlightDetailsModel>(flight);
return Task.FromResult(_mapper.Map<FlightDetailsModel>(flight));
}

[Activity]
public async Task<FlightDetailsModel> AssignSeatsAsync(FlightDetailsModel flight)
public Task<FlightDetailsModel> AssignSeats(FlightDetailsModel flight)
{
foreach (var ticket in flight.Registered)
{
if (ticket.Seat is not null)
continue;

var seat = flight.Seats.FirstOrDefault(s => s.TicketId is null);

ticket.Seat = seat;

seat.TicketId = ticket.Id;
}

return flight;
return Task.FromResult(flight);
}

[Activity]
public async Task<bool> SaveFlightDetailsAsync(FlightDetailsModel flightDetailsModel)
public async Task<bool> SaveFlightDetails(FlightDetailsModel flightDetailsModel)
{
var flight = _mapper.Map<DAL.Entities.Flight>(flightDetailsModel);

await _flightRepository.UpdateFlightAsync(flight);

return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,32 @@ public FlightService(IMapper mapper, ITemporalClient temporalClient, IFlightRepo
_flightRepository = flightRepository;
}

public async Task<List<DAL.Entities.Flight>> GetFlightsAsync()
public async Task<List<DAL.Entities.Flight>> GetFlights()
{
var flights = await _flightRepository.GetFlightsAsync();

var flightDetails = await Task.WhenAll(flights.Select(flight => GetFlightAsync(flight.Id)));
var flightDetails = await Task.WhenAll(flights.Select(FetchFlightDetailFromWorkflow));

flights = flightDetails.ToList();

return flights;
}

public async Task<DAL.Entities.Flight> GetFlightAsync(string id)
public async Task<DAL.Entities.Flight> GetFlight(string id)
{
var flight = await _flightRepository.GetFlightAsync(id);

var fetchedFlight = await FetchFlightDetailFromWorkflow(flight);

return fetchedFlight;
}

public async Task<DAL.Entities.Flight> FetchFlightDetailFromWorkflow(DAL.Entities.Flight flight)
{
if (flight is null)
throw new EntityNotFoundException("Flight was not found.");

if (!await WorkflowHandleHelper.IsWorkflowExists<FlightWorkflow>(_temporalClient, flight.Id))
if (!await WorkflowHandleHelper.IsWorkflowRunning<FlightWorkflow>(_temporalClient, flight.Id))
return flight;

var handle = _temporalClient.GetWorkflowHandle<FlightWorkflow>(flight.Id);
Expand All @@ -49,7 +56,7 @@ public FlightService(IMapper mapper, ITemporalClient temporalClient, IFlightRepo
return _mapper.Map<DAL.Entities.Flight>(flightDetails);
}

public async Task<DAL.Entities.Flight> CreateFlightAsync(FlightInputModel model)
public async Task<DAL.Entities.Flight> CreateFlight(FlightInputModel model)
{
var flight = _mapper.Map<DAL.Entities.Flight>(model);

Expand All @@ -58,7 +65,7 @@ public FlightService(IMapper mapper, ITemporalClient temporalClient, IFlightRepo
return flight;
}

public async Task RemoveFlightAsync(string id)
public async Task RemoveFlight(string id)
{
var flight = await _flightRepository.GetFlightAsync(id);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,29 @@ public class FlightWorkflow
private FlightDetailsModel _flight;

[WorkflowRun]
public async Task RunAsync(DAL.Entities.Flight flight)
public async Task Run(DAL.Entities.Flight flight)
{
_flight = await Workflow.ExecuteActivityAsync((FlightActivities act) => act.MapFlightModelAsync(flight),
_flight = await Workflow.ExecuteActivityAsync((FlightActivities act) => act.MapFlightModel(flight),
_activityOptions);

await ChangeStatusAtTimeAsync(FlightStatus.CheckIn, _flight.Depart.Subtract(TimeSpan.FromDays(1)));
await ChangeStatusAtTime(FlightStatus.CheckIn, _flight.Depart.Subtract(TimeSpan.FromDays(1)));

_flight = await Workflow.ExecuteActivityAsync((FlightActivities act) =>
act.AssignSeatsAsync(_flight), _activityOptions);
act.AssignSeats(_flight), _activityOptions);

await ChangeStatusAtTimeAsync(FlightStatus.Boarding, _flight.Depart.Subtract(TimeSpan.FromHours(2)));
await ChangeStatusAtTime(FlightStatus.Boarding, _flight.Depart.Subtract(TimeSpan.FromHours(2)));

await ChangeStatusAtTimeAsync(FlightStatus.Closed, _flight.Depart.Subtract(TimeSpan.FromMinutes(5)));
await ChangeStatusAtTime(FlightStatus.Closed, _flight.Depart.Subtract(TimeSpan.FromMinutes(5)));

await ChangeStatusAtTimeAsync(FlightStatus.Departed, _flight.Depart);
await ChangeStatusAtTime(FlightStatus.Departed, _flight.Depart);

await ChangeStatusAtTimeAsync(FlightStatus.Arrived, _flight.Arrival);
await ChangeStatusAtTime(FlightStatus.Arrived, _flight.Arrival);

await Workflow.ExecuteActivityAsync((FlightActivities act) => act.SaveFlightDetailsAsync(_flight),
await Workflow.ExecuteActivityAsync((FlightActivities act) => act.SaveFlightDetails(_flight),
_activityOptions);
}

private async Task ChangeStatusAtTimeAsync(FlightStatus status, DateTime time)
private async Task ChangeStatusAtTime(FlightStatus status, DateTime time)
{
var delay = time.Subtract(Workflow.UtcNow);

Expand All @@ -55,54 +55,64 @@ private async Task ChangeStatusAtTimeAsync(FlightStatus status, DateTime time)
/// </summary>
/// <param name="bookingSignalModel">The booking request model.</param>
[WorkflowSignal]
public async Task BookAsync(BookingSignalModel bookingSignalModel)
public Task Book(BookingSignalModel bookingSignalModel)
{
_flight.Registered.Add(bookingSignalModel.Ticket);

return Task.CompletedTask;
}

/// <summary>
/// Removes a ticket booking.
/// </summary>
/// <param name="bookingSignalModel">The model containing the booking request information.</param>
[WorkflowSignal]
public async Task BookCompensationAsync(BookingSignalModel bookingSignalModel)
public Task BookCompensation(BookingSignalModel bookingSignalModel)
{
var index = _flight.Registered.FindIndex(s => s.Id == bookingSignalModel.Ticket.Id);

_flight.Registered.RemoveAt(index);
var bookedTicket = _flight.Registered.FirstOrDefault(s => s.Id == bookingSignalModel.Ticket.Id);

if (bookedTicket is not null)
_flight.Registered.Remove(bookedTicket);

return Task.CompletedTask;
}

/// <summary>
/// Marks a ticket as paid.
/// </summary>
/// <param name="markTicketPaidSignalModel">The request model containing the ticket to be marked as paid.</param>
[WorkflowSignal]
public async Task MarkTicketPaidAsync(MarkTicketPaidSignalModel markTicketPaidSignalModel)
public Task MarkTicketPaid(MarkTicketPaidSignalModel markTicketPaidSignalModel)
{
var ticket = _flight.Registered.Find(s => s.Id == markTicketPaidSignalModel.Ticket.Id);
var ticket = _flight.Registered.FirstOrDefault(s => s.Id == markTicketPaidSignalModel.Ticket.Id);

if (ticket is not null)
ticket.PaymentStatus = PaymentStatus.Paid;

ticket.PaymentStatus = PaymentStatus.Paid;
return Task.CompletedTask;
}

/// <summary>
/// Marks a ticket as cancelled.
/// </summary>
/// <param name="markTicketPaidSignalModel">The model containing information about the ticket to mark as paid.</param>
[WorkflowSignal]
public async Task MarkTicketPaidCompensationAsync(MarkTicketPaidSignalModel markTicketPaidSignalModel)
public Task MarkTicketPaidCompensation(MarkTicketPaidSignalModel markTicketPaidSignalModel)
{
var ticket = _flight.Registered.Find(s => s.Id == markTicketPaidSignalModel.Ticket.Id);
var ticket = _flight.Registered.FirstOrDefault(s => s.Id == markTicketPaidSignalModel.Ticket.Id);

if (ticket is not null)
ticket.PaymentStatus = PaymentStatus.Cancelled;

return Task.CompletedTask;
}

/// <summary>
/// Reserves a seat for a ticket in the flight.
/// </summary>
/// <param name="seatReservationSignalModel">The model containing the seat and ticket information.</param>
[WorkflowSignal]
public async Task ReserveSeatAsync(SeatReservationSignalModel seatReservationSignalModel)
public Task ReserveSeat(SeatReservationSignalModel seatReservationSignalModel)
{
var seat = _flight.Seats.FirstOrDefault(f => f.Name == seatReservationSignalModel.Seat);

Expand All @@ -111,14 +121,16 @@ public async Task ReserveSeatAsync(SeatReservationSignalModel seatReservationSig
var ticket = _flight.Registered.FirstOrDefault(t => t.Id == seatReservationSignalModel.Ticket.Id);

ticket.Seat = seat;

return Task.CompletedTask;
}

/// <summary>
/// Removes seat reservation.
/// </summary>
/// <param name="seatReservationSignalModel">The seat reservation request model that contains the seat information.</param>
[WorkflowSignal]
public async Task ReserveSeatCompensationAsync(SeatReservationSignalModel seatReservationSignalModel)
public Task ReserveSeatCompensation(SeatReservationSignalModel seatReservationSignalModel)
{
var ticket = _flight.Registered.FirstOrDefault(t => t.Id == seatReservationSignalModel.Ticket.Id);

Expand All @@ -127,16 +139,20 @@ public async Task ReserveSeatCompensationAsync(SeatReservationSignalModel seatRe
var seat = _flight.Seats.FirstOrDefault(f => f.Name == seatReservationSignalModel.Seat);

seat.TicketId = null;

return Task.CompletedTask;
}

/// <summary>
/// Adds a passenger's ticket to the boarded list of a flight.
/// </summary>
/// <param name="boardingSignalModel">The model containing the information of the passenger's boarding request.</param>
[WorkflowSignal]
public async Task BoardPassengerAsync(BoardingSignalModel boardingSignalModel)
public Task BoardPassenger(BoardingSignalModel boardingSignalModel)
{
_flight.Boarded.Add(boardingSignalModel.Ticket);

return Task.CompletedTask;
}

/// <summary>
Expand Down
Loading

0 comments on commit fe325f3

Please sign in to comment.