Skip to content

Commit 8246f57

Browse files
committed
fix(deploy): retry MigrateAsync up to 12x to tolerate Docker DNS warmup race
1 parent 7136114 commit 8246f57

1 file changed

Lines changed: 28 additions & 2 deletions

File tree

server/src/Coiny.Api/Program.cs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,12 +68,38 @@ static void ApplyJsonDefaults(System.Text.Json.JsonSerializerOptions opts)
6868
// usually want to control migrations manually) stays unchanged. Coolify deploys set this to
6969
// `true` in prod env so a fresh Postgres container gets the full schema on its first boot.
7070
// Idempotent on every later boot: EF checks __EFMigrationsHistory and no-ops if up-to-date.
71-
// On migration failure the container exits non-zero → Coolify keeps the previous image running.
71+
//
72+
// Retry loop: on first deploy Coolify spins up Postgres and the API container nearly
73+
// simultaneously, so Npgsql's first DNS resolve can fail with `EAI_AGAIN` (Docker's embedded DNS
74+
// hasn't propagated the alias yet) or `Connection refused` (Postgres still initializing). We back
75+
// off up to a minute total — long enough for Postgres init, short enough that a genuinely broken
76+
// connection string still surfaces as a deploy failure for Coolify to roll back.
7277
if (builder.Configuration.GetValue<bool>("MIGRATE_ON_STARTUP"))
7378
{
7479
using IServiceScope migrationScope = app.Services.CreateScope();
7580
var db = migrationScope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
76-
await db.Database.MigrateAsync();
81+
var migrationLogger = migrationScope.ServiceProvider
82+
.GetRequiredService<ILoggerFactory>()
83+
.CreateLogger("Coiny.Migration");
84+
85+
const int maxAttempts = 12;
86+
TimeSpan delay = TimeSpan.FromSeconds(5);
87+
for (int attempt = 1; ; attempt++)
88+
{
89+
try
90+
{
91+
await db.Database.MigrateAsync();
92+
migrationLogger.LogInformation("EF migrations applied on attempt {Attempt}", attempt);
93+
break;
94+
}
95+
catch (Exception ex) when (attempt < maxAttempts)
96+
{
97+
migrationLogger.LogWarning(ex,
98+
"EF migration attempt {Attempt} failed ({Error}); retrying in {Delay}s",
99+
attempt, ex.Message, delay.TotalSeconds);
100+
await Task.Delay(delay);
101+
}
102+
}
77103
}
78104

79105
app.UseExceptionHandler();

0 commit comments

Comments
 (0)