fix: UI виснет на секунды при недоступном MySQL-хосте

OfflineDetector дёргал connMgr.IsOnline() на каждый HTTP-запрос, а тот
при офлайне синхронно лез в сеть и держал дайл/пинг с таймаутом 3с под
общей блокировкой состояния — из-за этого /health и другие запросы
блокировались на секунды прямо в обработчике.

IsOnline() теперь чистое чтение кэша. Реальный сетевой опрос вынесен в
фоновый цикл (ConnectionManager.Start/Stop), а сами попытки dial/ping
сериализуются через отдельный connMu и никогда не держат блокировку
состояния во время сетевого I/O — поэтому конкурентные читатели статуса
больше не ждут таймаут MySQL.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-03 07:31:08 +03:00
parent 5067670294
commit 80eab1db93
2 changed files with 171 additions and 77 deletions
+9
View File
@@ -168,6 +168,13 @@ func main() {
// Create connection manager. Runtime stays local-first; MariaDB is used on demand by sync/setup only.
connMgr := db.NewConnectionManager(local)
// Keep the online-status cache fresh in the background so request-handling
// goroutines (health checks, middleware, etc.) never block on the MySQL
// dial/read timeout themselves.
connMgrCtx, connMgrCancel := context.WithCancel(context.Background())
defer connMgrCancel()
connMgr.Start(connMgrCtx)
dbUser := local.GetDBUser()
slog.Info("starting QuoteForge server",
@@ -272,6 +279,8 @@ func main() {
syncWorker.Stop()
workerCancel()
backupCancel()
connMgr.Stop()
connMgrCancel()
// Then shutdown HTTP server
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)