fix: ограничить пул Postgres и реже писать прогресс скана

- DB_MAX_OPEN_CONNS (25), DB_MAX_IDLE_CONNS (10), DB_CONN_MAX_LIFETIME_SEC (1800)

- Throttle UpdateScan прогресса в Runner (500ms), меньше одновременных запросов к БД

Устраняет FATAL too many clients при больших сканах и частом опросе GetScan

Made-with: Cursor
This commit is contained in:
PTah
2026-04-13 15:33:25 +10:00
parent 088be32ec5
commit 6ad59c9990
3 changed files with 73 additions and 10 deletions
+44 -7
View File
@@ -2,7 +2,9 @@ package config
import (
"os"
"strconv"
"strings"
"time"
)
type Config struct {
@@ -13,6 +15,10 @@ type Config struct {
SNMPEnabled bool
SNMPCommunity string
ResetDBSecret string // NETTOPO_RESET_DB_SECRET — секрет для POST /api/admin/purge-scans
// Пул соединений к PostgreSQL (см. database/sql). По умолчанию ограничен, иначе при большом скане легко исчерпать max_connections на сервере.
DBMaxOpenConns int
DBMaxIdleConns int
DBConnMaxLifetime time.Duration
}
func FromEnv() Config {
@@ -44,13 +50,44 @@ func FromEnv() Config {
snmpCommunity = "public"
}
maxOpen := intFromEnvMin("DB_MAX_OPEN_CONNS", 25, 1)
maxIdle := intFromEnvMin("DB_MAX_IDLE_CONNS", 10, 0)
if maxIdle > maxOpen {
maxIdle = maxOpen
}
connLife := 30 * time.Minute
if s := strings.TrimSpace(os.Getenv("DB_CONN_MAX_LIFETIME_SEC")); s != "" {
if sec, err := strconv.Atoi(s); err == nil {
if sec == 0 {
connLife = 0 // без ограничения времени жизни соединения
} else if sec > 0 {
connLife = time.Duration(sec) * time.Second
}
}
}
return Config{
HTTPAddr: addr,
DBDSN: dbDSN,
StoreBackend: storeBackend,
RunMigrations: runMigrations,
SNMPEnabled: snmpEnabled,
SNMPCommunity: snmpCommunity,
ResetDBSecret: strings.TrimSpace(os.Getenv("NETTOPO_RESET_DB_SECRET")),
HTTPAddr: addr,
DBDSN: dbDSN,
StoreBackend: storeBackend,
RunMigrations: runMigrations,
SNMPEnabled: snmpEnabled,
SNMPCommunity: snmpCommunity,
ResetDBSecret: strings.TrimSpace(os.Getenv("NETTOPO_RESET_DB_SECRET")),
DBMaxOpenConns: maxOpen,
DBMaxIdleConns: maxIdle,
DBConnMaxLifetime: connLife,
}
}
func intFromEnvMin(key string, def, min int) int {
s := strings.TrimSpace(os.Getenv(key))
if s == "" {
return def
}
n, err := strconv.Atoi(s)
if err != nil || n < min {
return def
}
return n
}