/// <inheritdoc /> protected override async Task ExecuteAsync(CancellationToken stoppingToken) { _logger.LogInformation("Rally simulation background service is starting."); await Task.Delay(5000, stoppingToken); while (!stoppingToken.IsCancellationRequested) { _logger.LogInformation("Rally simulation background service is doing background work."); using IServiceScope scope = _serviceProvider.CreateScope(); RallySimulatorDbContext dbContext = scope.ServiceProvider.GetRequiredService <RallySimulatorDbContext>(); Maybe <Race> maybeRace = await dbContext.Set <Race>() .SingleOrDefaultAsync(x => x.Status == RaceStatus.Running, stoppingToken); if (maybeRace.HasValue) { await SimulateOneHourPassing(maybeRace.Value, dbContext); } await Task.Delay(_backgroundTaskSettings.SleepTimeInMilliseconds, stoppingToken); } _logger.LogInformation("Rally simulation background service is stopping."); await Task.CompletedTask; }
/// <summary> /// Simulates the passing of one hour for the specified running race. /// </summary> /// <param name="race">The race that is currently running.</param> /// <param name="dbContext">The database context.</param> private async Task SimulateOneHourPassing(Race race, RallySimulatorDbContext dbContext) { List <Vehicle> vehicles = await dbContext.Set <Vehicle>() .Include(x => x.RepairmentLength) .Include(x => x.Speed) .Include(x => x.MalfunctionProbability) .Include(x => x.Malfunctions) .Where(x => x.RaceId == race.Id) .ToListAsync(); VehicleStatus[] brokenOrCompletedRace = { VehicleStatus.Broken, VehicleStatus.CompletedRace }; foreach (Vehicle vehicle in vehicles.Where(x => !brokenOrCompletedRace.Contains(x.Status))) { vehicle.SimulateOneHourPassing(); if (vehicle.Status == VehicleStatus.WaitingForRepair && !vehicle.TryRepair()) { continue; } decimal malfunctionProbability = (decimal)_random.NextDouble(); if (vehicle.MalfunctionProbability.LightMalfunctionProbability >= malfunctionProbability) { vehicle.AddLightMalfunction(); continue; } if (vehicle.MalfunctionProbability.HeavyMalfunctionProbability >= malfunctionProbability) { vehicle.AddHeavyMalfunction(); continue; } vehicle.IncrementDistance(vehicle.Speed.SpeedInKilometersPerHour * 1.0m, race.LengthInKilometers); if (vehicle.Distance == race.LengthInKilometers) { vehicle.CompleteRace(); } } race.SimulateOneHourPassing(); if (vehicles.All(x => brokenOrCompletedRace.Contains(x.Status))) { race.CompleteRace(); } await dbContext.SaveChangesAsync(); }
/// <summary> /// Ensures that the in-memory database is created. /// </summary> /// <param name="builder">The application builder.</param> /// <returns>The same application builder.</returns> internal static IApplicationBuilder EnsureDatabaseCreated(this IApplicationBuilder builder) { using IServiceScope serviceScope = builder.ApplicationServices.CreateScope(); using RallySimulatorDbContext dbContext = serviceScope.ServiceProvider.GetRequiredService <RallySimulatorDbContext>(); dbContext.Database.EnsureCreated(); dbContext.SeedDatabase(); return(builder); }
/// <summary> /// Seeds the database with initial data. /// </summary> /// <param name="dbContext">The database context.</param> public static void SeedDatabase(this RallySimulatorDbContext dbContext) { dbContext.Set <VehicleTypeRepairmentLength>().AddRange(new List <VehicleTypeRepairmentLength> { new VehicleTypeRepairmentLength(VehicleType.Truck, 7), new VehicleTypeRepairmentLength(VehicleType.Car, 5), new VehicleTypeRepairmentLength(VehicleType.Motorcycle, 3) }); dbContext.Set <VehicleSubtypeSpeed>().AddRange(new List <VehicleSubtypeSpeed> { new VehicleSubtypeSpeed(VehicleSubtype.Truck, SpeedInKilometersPerHour.Create(80).Value), new VehicleSubtypeSpeed(VehicleSubtype.TerrainCar, SpeedInKilometersPerHour.Create(100).Value), new VehicleSubtypeSpeed(VehicleSubtype.SportsCar, SpeedInKilometersPerHour.Create(140).Value), new VehicleSubtypeSpeed(VehicleSubtype.CrossMotorcycle, SpeedInKilometersPerHour.Create(85).Value), new VehicleSubtypeSpeed(VehicleSubtype.SportMotorcycle, SpeedInKilometersPerHour.Create(130).Value), }); dbContext.Set <VehicleSubtypeMalfunctionProbability>().AddRange(new List <VehicleSubtypeMalfunctionProbability> { new VehicleSubtypeMalfunctionProbability( VehicleSubtype.Truck, MalfunctionProbability.Create(0.06m).Value, MalfunctionProbability.Create(0.04m).Value), new VehicleSubtypeMalfunctionProbability( VehicleSubtype.TerrainCar, MalfunctionProbability.Create(0.03m).Value, MalfunctionProbability.Create(0.01m).Value), new VehicleSubtypeMalfunctionProbability( VehicleSubtype.SportsCar, MalfunctionProbability.Create(0.12m).Value, MalfunctionProbability.Create(0.02m).Value), new VehicleSubtypeMalfunctionProbability( VehicleSubtype.CrossMotorcycle, MalfunctionProbability.Create(0.03m).Value, MalfunctionProbability.Create(0.02m).Value), new VehicleSubtypeMalfunctionProbability( VehicleSubtype.SportMotorcycle, MalfunctionProbability.Create(0.18m).Value, MalfunctionProbability.Create(0.10m).Value) }); dbContext.SaveChanges(); }