public GeoliteManagerTest(WebAppTestFactory factory) { geoliteManager = factory.Services.GetService <IGeoliteManager>(); hostEnvironment = factory.Services.GetService <IWebHostEnvironment>(); this.factory = factory; }
protected override async Task ExecuteAsync(CancellationToken stoppingToken) { using (var scope = provider.CreateScope()) { dbContext = scope.ServiceProvider.GetRequiredService <ApplicationContext>(); geoliteManager = scope.ServiceProvider.GetRequiredService <IGeoliteManager>(); hostEnvironment = scope.ServiceProvider.GetRequiredService <IWebHostEnvironment>(); connectionManager = scope.ServiceProvider.GetRequiredService <IConnectionStringManager>(); // update every 7 days int updateIntervalInMilliseconds = TimeSpan.FromDays(7).Milliseconds; dbContext.Database.EnsureCreated(); if (!dbContext.GeoObjects.Any()) { FillDatabase(); // install timer to UpdateDatabase every 7 days timer = new Timer(async(obj) => await UpdateDatabaseAsync(), null, updateIntervalInMilliseconds, updateIntervalInMilliseconds); } else { GeoObject geoObject = await dbContext.GeoObjects.FirstOrDefaultAsync(); DateTime lastUpdateTime = geoObject.UpdateTime; DateTime currentTime = DateTime.UtcNow; DateTime nextUpdateTime = CalculateNextUpdateTime(currentTime); TimeSpan dayPassed = currentTime - lastUpdateTime; DateTime dateToUpdate = nextUpdateTime - dayPassed; TimeSpan daysLeft = dateToUpdate - currentTime; if (daysLeft.Days > 0) { // install timer to UpdateDatabase when left days will pass and set interval to repeat this action every 7 days // so we update our DB every week (Wednesday) timer = new Timer(async(obj) => await UpdateDatabaseAsync(), null, daysLeft.Milliseconds, updateIntervalInMilliseconds); } else { // install timer to UpdateDatabase now and set interval to repeat this action every 7 days // so we update our DB every week (Wednesday) timer = new Timer(async(obj) => await UpdateDatabaseAsync(), null, 0, updateIntervalInMilliseconds); } } } DateTime CalculateNextUpdateTime(DateTime currentTime) => currentTime.DayOfWeek switch { DayOfWeek.Sunday => currentTime + TimeSpan.FromDays(3), DayOfWeek.Monday => currentTime + TimeSpan.FromDays(2), DayOfWeek.Tuesday => currentTime + TimeSpan.FromDays(1), DayOfWeek.Wednesday => currentTime, DayOfWeek.Thursday => currentTime + TimeSpan.FromDays(6), DayOfWeek.Friday => currentTime + TimeSpan.FromDays(5), DayOfWeek.Saturday => currentTime + TimeSpan.FromDays(4), _ => currentTime }; // since we have no data in DB we should not call this method in async mode // because we first should migrate data to our DB and don't let any controller to be able to access DB before we // so this is why it's better to do it in sync // because we don't want our API work when DB is empty void FillDatabase() { var root = hostEnvironment.ContentRootPath; var directory = Path.Combine(root, "Geolite"); Directory.CreateDirectory(directory); string geoliteDb = geoliteManager.DownloadDbFileAsync(directory).Result; geoliteManager.MigrateToDbContext(geoliteDb, dbContext).Wait(); } async Task UpdateDatabaseAsync() { var root = hostEnvironment.ContentRootPath; var directory = Path.Combine(root, "Geolite"); Directory.CreateDirectory(directory); string geoliteDb = await geoliteManager.DownloadDbFileAsync(directory); #region Migrate geoliteDb to new Database string newDatabaseConnection = connectionManager.GenerateNewConnectionString(); var newDbConnectionBuilder = new DbContextOptionsBuilder <ApplicationContext>(); newDbConnectionBuilder.UseNpgsql(newDatabaseConnection); using (var context = new ApplicationContext(newDbConnectionBuilder.Options)) { await context.Database.EnsureCreatedAsync(); await geoliteManager.MigrateToDbContext(geoliteDb, context); } #endregion // get currentDbConnection so that to delete // because we already created new DB string outdatedConnectionString = connectionManager.ConnectionString; // set CurrentConnectionString to our new DB connectionManager.ConnectionString = newDatabaseConnection; #region Delete outdated Database var outdatedDbBuilder = new DbContextOptionsBuilder <ApplicationContext>(); outdatedDbBuilder.UseNpgsql(outdatedConnectionString); using (var outdatedContext = new ApplicationContext(outdatedDbBuilder.Options)) { await outdatedContext.Database.EnsureDeletedAsync(); } #endregion } } }