mirror of
https://github.com/aliasvault/aliasvault.git
synced 2026-03-26 18:44:10 -04:00
Add safe central db migration to prevent race condition false-positive errors on startup (#1758)
This commit is contained in:
committed by
Leendert de Borst
parent
888214e7d0
commit
0077552713
@@ -163,8 +163,11 @@ app.MapRazorComponents<App>()
|
||||
using (var scope = app.Services.CreateScope())
|
||||
{
|
||||
var container = scope.ServiceProvider;
|
||||
var logger = container.GetRequiredService<ILogger<Program>>();
|
||||
await using var db = await container.GetRequiredService<IAliasServerDbContextFactory>().CreateDbContextAsync();
|
||||
await db.Database.MigrateAsync();
|
||||
|
||||
// Wait for migrations to be applied (API project runs them centrally)
|
||||
await db.WaitForDatabaseReadyAsync(logger);
|
||||
|
||||
await StartupTasks.CreateRolesIfNotExist(scope.ServiceProvider);
|
||||
await StartupTasks.SetAdminUser(scope.ServiceProvider);
|
||||
|
||||
@@ -7,8 +7,11 @@
|
||||
|
||||
namespace AliasServerDb.Configuration;
|
||||
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Npgsql;
|
||||
|
||||
/// <summary>
|
||||
/// Database configuration class.
|
||||
@@ -67,4 +70,53 @@ public static class DatabaseConfiguration
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Waits for the database to be ready by checking if all migrations have been applied.
|
||||
/// This is useful for services that should not run migrations themselves but need to wait
|
||||
/// for another service (typically the API) to complete migrations first.
|
||||
/// </summary>
|
||||
/// <param name="context">The database context to check.</param>
|
||||
/// <param name="logger">Optional logger for diagnostics.</param>
|
||||
/// <param name="timeoutSeconds">Maximum time to wait in seconds (default: 60).</param>
|
||||
/// <param name="checkIntervalMs">Interval between checks in milliseconds (default: 2000).</param>
|
||||
/// <returns>A task representing the asynchronous operation.</returns>
|
||||
public static async Task WaitForDatabaseReadyAsync(this DbContext context, ILogger? logger = null, int timeoutSeconds = 60, int checkIntervalMs = 2000)
|
||||
{
|
||||
var timeout = DateTime.UtcNow.AddSeconds(timeoutSeconds);
|
||||
var attempt = 0;
|
||||
|
||||
while (DateTime.UtcNow < timeout)
|
||||
{
|
||||
attempt++;
|
||||
|
||||
try
|
||||
{
|
||||
// Check if database is accessible and all migrations are applied
|
||||
var pendingMigrations = await context.Database.GetPendingMigrationsAsync();
|
||||
if (!pendingMigrations.Any())
|
||||
{
|
||||
logger?.LogInformation("Database is ready. All migrations have been applied.");
|
||||
return;
|
||||
}
|
||||
|
||||
logger?.LogInformation(
|
||||
"Waiting for database migrations to complete. {PendingCount} migrations pending. Attempt {Attempt}.",
|
||||
pendingMigrations.Count(),
|
||||
attempt);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger?.LogWarning(
|
||||
ex,
|
||||
"Database not yet accessible. Attempt {Attempt}. Waiting {Interval}ms before retry...",
|
||||
attempt,
|
||||
checkIntervalMs);
|
||||
}
|
||||
|
||||
await Task.Delay(checkIntervalMs);
|
||||
}
|
||||
|
||||
throw new TimeoutException($"Database did not become ready within {timeoutSeconds} seconds. Migrations may not have completed.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,8 +168,11 @@ using (var scope = host.Services.CreateScope())
|
||||
{
|
||||
var container = scope.ServiceProvider;
|
||||
var factory = container.GetRequiredService<IAliasServerDbContextFactory>();
|
||||
var logger = container.GetRequiredService<ILogger<Program>>();
|
||||
await using var context = await factory.CreateDbContextAsync();
|
||||
await context.Database.MigrateAsync();
|
||||
|
||||
// Wait for migrations to be applied (API project runs them centrally)
|
||||
await context.WaitForDatabaseReadyAsync(logger);
|
||||
}
|
||||
|
||||
await host.RunAsync();
|
||||
|
||||
@@ -42,8 +42,11 @@ using (var scope = host.Services.CreateScope())
|
||||
{
|
||||
var container = scope.ServiceProvider;
|
||||
var factory = container.GetRequiredService<IAliasServerDbContextFactory>();
|
||||
var logger = container.GetRequiredService<ILogger<Program>>();
|
||||
await using var context = await factory.CreateDbContextAsync();
|
||||
await context.Database.MigrateAsync();
|
||||
|
||||
// Wait for migrations to be applied (API project runs them centrally)
|
||||
await context.WaitForDatabaseReadyAsync(logger);
|
||||
}
|
||||
|
||||
await host.RunAsync();
|
||||
|
||||
Reference in New Issue
Block a user