Guard deploys against a broken migration
CI / build-and-push (push) Successful in 46s
CI / deploy (push) Successful in 9s

Program.cs: wrap the boot-time MigrateAsync in try/catch (was an unhandled
exception into a restart:unless-stopped crash-loop), log critical and exit(1)
on failure, and add a --migrate-only flag that applies migrations then exits
0 without starting the web host.

deploy.sh: run migrations as a preflight via the new --migrate-only image
against the live novelly-data volume, before the running (old-image) stack
is touched. A failing migration now aborts the deploy with the old
containers still serving traffic, instead of swapping to a crash-looping
new container first and finding out from the health-check timeout.
This commit is contained in:
James Wampler
2026-08-19 14:23:34 -07:00
parent 7a1c726af8
commit 8f93dce065
3 changed files with 42 additions and 1 deletions
+19 -1
View File
@@ -41,12 +41,30 @@ builder.Services.AddCors(options => options.AddDefaultPolicy(policy => policy
.AllowAnyMethod()
.AllowCredentials()));
var migrateOnly = args.Contains("--migrate-only");
var app = builder.Build();
using (var scope = app.Services.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService<NovelDbContext>();
await db.Database.MigrateAsync();
try
{
await db.Database.MigrateAsync();
}
catch (Exception ex)
{
app.Logger.LogCritical(ex, "Database migration failed on startup");
Environment.Exit(1);
}
if (migrateOnly)
{
app.Logger.LogInformation("Migration complete, exiting ({MigrateOnlyFlag})", "--migrate-only");
Environment.Exit(0);
}
await ServiceUser.EnsureSeededAsync(db, builder.Configuration[ServiceApiKeyAuthenticationHandler.ConfigurationKey], app.Logger);
}