From d0d26c9821da5a05bffc53b90ddc172ba0590578 Mon Sep 17 00:00:00 2001 From: Alexa <53471801+Alexa-RR@users.noreply.github.com> Date: Sun, 25 Oct 2026 13:52:20 +0200 Subject: [PATCH] fix: wait for the bootstrap lock without a command timeout; safe unlock From the local CodeRabbit review: - A replica waiting for the lock used the default 30 s command timeout and failed to boot while another replica seeded a fresh database. Wait with no timeout, logging that it is waiting. - An unlock failure in the finally (e.g. the connection already broken) replaced the real bootstrap error and skipped closing the connection. Log it instead, and always close. --- DorkNet.Server/Startup/DatabaseBootstrap.cs | 36 ++++++++++++++++++--- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/DorkNet.Server/Startup/DatabaseBootstrap.cs b/DorkNet.Server/Startup/DatabaseBootstrap.cs index 13489a7..5ac885c 100644 --- a/DorkNet.Server/Startup/DatabaseBootstrap.cs +++ b/DorkNet.Server/Startup/DatabaseBootstrap.cs @@ -87,8 +87,21 @@ public static class DatabaseBootstrap // The connection stays open until the finally, so every step below // (they all share this scope's DbContext) runs on the session that - // holds the lock. - await db.Database.ExecuteSqlRawAsync("SELECT pg_advisory_lock(1146246987);"); + // holds the lock. Waiting for it has no command timeout: another + // replica may be seeding a fresh database (thumbnail downloads + // included) for well over the default 30 s. + connectLogger.LogInformation("[bootstrap] waiting for the database bootstrap lock"); + var previousTimeout = db.Database.GetCommandTimeout(); + db.Database.SetCommandTimeout(0); + try + { + await db.Database.ExecuteSqlRawAsync("SELECT pg_advisory_lock(1146246987);"); + } + finally + { + db.Database.SetCommandTimeout(previousTimeout); + } + connectLogger.LogInformation("[bootstrap] holding the database bootstrap lock"); try { // Begin the transaction through EF, not on the raw connection: @@ -106,9 +119,22 @@ public static class DatabaseBootstrap finally { // Explicit: Npgsql pools connections, so closing alone would not - // end the session that holds the lock. - await db.Database.ExecuteSqlRawAsync("SELECT pg_advisory_unlock(1146246987);"); - await conn.CloseAsync(); + // end the session that holds the lock. If the connection is + // already broken the unlock fails too; that must not replace the + // real bootstrap error, and the connection still gets closed + // (Postgres then drops the lock with the session). + try + { + await db.Database.ExecuteSqlRawAsync("SELECT pg_advisory_unlock(1146246987);"); + } + catch (Exception ex) + { + connectLogger.LogWarning(ex, "[bootstrap] releasing the database bootstrap lock failed"); + } + finally + { + await conn.CloseAsync(); + } } }