public Task StartNewFlight(FlightPlan flightPlan) { FlightPlan.Validate(flightPlan, includeFlightPath: false); try { return(ErrorHandlingPolicy.ExecuteRequestAsync(async() => { var flyingAirplaneCallSigns = await TableStorageOperationAsync( () => flyingAirplanesTable_.GetFlyingAirplaneCallSignsAsync(shutdownTokenSource_.Token), null, nameof(FlyingAirplanesTable.GetFlyingAirplaneCallSignsAsync)); if (flyingAirplaneCallSigns.Contains(flightPlan.CallSign, StringComparer.OrdinalIgnoreCase)) { // In real life airplanes can have multiple flight plans filed, just for different times. But here we assume there can be only one flight plan per airplane throw new InvalidOperationException($"The airplane {flightPlan.CallSign} is already flying"); // CONSIDER forcing execution of the new flight plan here, instead of throwing an error. } flightPlan.FlightPath = Dispatcher.ComputeFlightPath(flightPlan.DeparturePoint, flightPlan.Destination); // The actual creation of the flight will be queued and handled by the time passage routine to ensure that there are no races // during new world state calculation newFlightQueue_.Enqueue(flightPlan); if (logger_.IsEnabled(LogLevel.Information)) { flightPlan.AddUniverseInfo(); logger_.LogInformation( LoggingEvents.NewFlightCreated, "New flight created from {DeparturePoint} to {Destination} for {CallSign}. Clearance is {FlightPath}", flightPlan.DeparturePoint.Name, flightPlan.Destination.Name, flightPlan.CallSign, flightPlan.FlightPath.Select(fix => fix.Name).Aggregate(string.Empty, (current, fixName) => current + " " + fixName)); } })); } catch (Exception ex) { logger_.LogError(LoggingEvents.StartingNewFlightFailed, ex, "Unexpected error occurred when starting new flight"); throw; } }