diff --git a/internal/db/mysql.go b/internal/db/mysql.go index 36592c3..85755c0 100644 --- a/internal/db/mysql.go +++ b/internal/db/mysql.go @@ -129,19 +129,21 @@ func translateTextColumns(s string) string { // OpenMySQL opens the shared MySQL logbook, creating the database if needed, // then applies the (translated) embedded migrations. multiStatements is enabled // so multi-statement migration files run in a single Exec. -// tuneMySQLPool sizes the connection pool for a SHARED server. A multi-operator -// special event runs many OpsLog instances against ONE MySQL, whose max_connections -// is a hard global limit (often 100–151). A big per-instance pool (we used 50) let -// a handful of ops exhaust the server — "Error 1040: Too many connections" — after -// which queries (the on-air widget, award_refs, the grid) fail silently and the UI -// looks frozen. A modest cap with brisk idle reaping keeps each instance's server -// footprint small so ~10+ ops fit, while still absorbing the UI's concurrent -// logbook queries. No max lifetime: a slow first migration can run for minutes on a -// single connection and reaping it mid-migration drops the selected database. +// tuneMySQLPool sizes the connection pool for a SHARED server. Two opposing needs: +// - A big per-instance pool (we shipped 50) let a handful of ops exhaust the +// server's global max_connections — "Error 1040: Too many connections". +// - Too SMALL a pool starves this instance's OWN concurrent UI queries — the live +// multi-op sync (revision poll every 2s + a 3-query grid refresh), live_status, +// chat, stats, cluster — so the grid stops showing other operators' QSOs. (8 was +// too tight and reintroduced this "deadlock-like stall".) +// 16 is the balance: plenty for the UI's bursts, and ~15 ops still fit under a +// raised max_connections=300 (advise operators to raise it for a big multi-op). +// Brisk idle reaping returns slots to the server; no max lifetime so a slow first +// migration on one connection isn't reaped mid-run (drops the selected database). func tuneMySQLPool(conn *sql.DB) { - conn.SetMaxOpenConns(8) - conn.SetMaxIdleConns(3) - conn.SetConnMaxIdleTime(30 * time.Second) // return idle connections to the server promptly + conn.SetMaxOpenConns(16) + conn.SetMaxIdleConns(6) + conn.SetConnMaxIdleTime(30 * time.Second) conn.SetConnMaxLifetime(0) }