Backup on Migrations (#898)

* Refactored how the migrations are run.

* A backup will be performed before any migrations. Added additional guards before a sub-module is loaded.
This commit is contained in:
Joseph Milazzo 2022-01-05 12:47:01 -08:00 committed by GitHub
parent 2bf1b96411
commit 027b8b78e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 62 additions and 22 deletions

View File

@ -36,7 +36,6 @@ namespace API
var isDocker = new OsInfo(Array.Empty<IOsVersionAdapter>()).IsDocker;
// TODO: Figure out a solution for this migration and logger.
var directoryService = new DirectoryService(null, new FileSystem());
MigrateConfigFiles.Migrate(isDocker, directoryService);
@ -58,7 +57,7 @@ namespace API
try
{
var context = services.GetRequiredService<DataContext>();
var roleManager = services.GetRequiredService<RoleManager<AppRole>>();
if (isDocker && new FileInfo("data/appsettings.json").Exists)
{
@ -81,28 +80,27 @@ namespace API
requiresCoverImageMigration = false;
}
// Apply all migrations on startup
// If we have pending migrations, make a backup first
var pendingMigrations = await context.Database.GetPendingMigrationsAsync();
if (pendingMigrations.Any())
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogInformation("Performing backup as migrations are needed");
// var backupService = services.GetRequiredService<BackupService>();
// await backupService.BackupDatabase();
}
await context.Database.MigrateAsync();
if (requiresCoverImageMigration)
{
await MigrateCoverImages.UpdateDatabaseWithImages(context, directoryService);
}
await Seed.SeedRoles(roleManager);
await Seed.SeedSettings(context, directoryService);
await Seed.SeedUserApiKeys(context);
// // Apply all migrations on startup
// // If we have pending migrations, make a backup first
// var pendingMigrations = await context.Database.GetPendingMigrationsAsync();
// if (pendingMigrations.Any())
// {
// var logger = services.GetRequiredService<ILogger<Program>>();
// logger.LogInformation("Performing backup as migrations are needed");
// // var backupService = services.GetRequiredService<BackupService>();
// // await backupService.BackupDatabase();
// }
//
// await context.Database.MigrateAsync();
//
// await Seed.SeedRoles(roleManager);
// await Seed.SeedSettings(context, directoryService);
// await Seed.SeedUserApiKeys(context);
}
catch (Exception ex)
{

View File

@ -6,10 +6,12 @@ using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
using API.Data;
using API.Entities;
using API.Extensions;
using API.Middleware;
using API.Services;
using API.Services.HostedServices;
using API.Services.Tasks;
using API.SignalR;
using Hangfire;
using Hangfire.MemoryStorage;
@ -19,8 +21,10 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.ResponseCompression;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
@ -130,12 +134,45 @@ namespace API
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IBackgroundJobClient backgroundJobs, IWebHostEnvironment env,
IHostApplicationLifetime applicationLifetime, IServiceProvider serviceProvider, ICacheService cacheService,
IDirectoryService directoryService, IUnitOfWork unitOfWork)
IDirectoryService directoryService, IUnitOfWork unitOfWork, IBackupService backupService)
{
// Apply Migrations
Task.Run(async () => await MigrateBookmarks.Migrate(directoryService, unitOfWork,
serviceProvider.GetRequiredService<ILogger<Program>>(), cacheService)).GetAwaiter().GetResult();
try
{
Task.Run(async () =>
{
// Apply all migrations on startup
// If we have pending migrations, make a backup first
var logger = serviceProvider.GetRequiredService<ILogger<Program>>();
var context = serviceProvider.GetRequiredService<DataContext>();
var pendingMigrations = await context.Database.GetPendingMigrationsAsync();
if (pendingMigrations.Any())
{
logger.LogInformation("Performing backup as migrations are needed");
await backupService.BackupDatabase();
}
await context.Database.MigrateAsync();
await MigrateBookmarks.Migrate(directoryService, unitOfWork,
logger, cacheService);
var roleManager = serviceProvider.GetRequiredService<RoleManager<AppRole>>();
await Seed.SeedRoles(roleManager);
await Seed.SeedSettings(context, directoryService);
await Seed.SeedUserApiKeys(context);
}).GetAwaiter()
.GetResult();
}
catch (Exception ex)
{
var logger = serviceProvider.GetRequiredService<ILogger<Program>>();
logger.LogCritical(ex, "An error occurred during migration");
}
app.UseMiddleware<ExceptionMiddleware>();

View File

@ -10,6 +10,7 @@ import { LibraryAccessGuard } from './_guards/library-access.guard';
import { OnDeckComponent } from './on-deck/on-deck.component';
import { DashboardComponent } from './dashboard/dashboard.component';
import { AllSeriesComponent } from './all-series/all-series.component';
import { AdminGuard } from './_guards/admin.guard';
// TODO: Once we modularize the components, use this and measure performance impact: https://angular.io/guide/lazy-loading-ngmodules#preloading-modules
@ -17,18 +18,22 @@ const routes: Routes = [
{path: '', component: UserLoginComponent},
{
path: 'admin',
canActivate: [AdminGuard],
loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule)
},
{
path: 'collections',
canActivate: [AuthGuard],
loadChildren: () => import('./collections/collections.module').then(m => m.CollectionsModule)
},
{
path: 'preferences',
canActivate: [AuthGuard],
loadChildren: () => import('./user-settings/user-settings.module').then(m => m.UserSettingsModule)
},
{
path: 'lists',
canActivate: [AuthGuard],
loadChildren: () => import('./reading-list/reading-list.module').then(m => m.ReadingListModule)
},
{