fix: SQLite connection leak causing unbounded memory growth
SaveStats returned tx.Create().Error directly without assigning to the local err variable, so the deferred closure always saw err==nil and called Commit() on a failed transaction. This left the underlying go-sqlite3 connection unreturned to the pool. With StatsJob firing every 10s, leaked connections accumulated ~150 KB each, reaching 400+ MB after ~33 hours. Fixes: - stats.go: assign Create result to err so defer can Rollback on failure - backup.go: defer-close backupDb to prevent pool leak on early return - migration/main.go: defer-close migration db - db.go: add ConnMaxIdleTime(5m), lower MaxIdleConns to 2, set _cache_size=-200 to reduce per-connection memory from ~2 MB to ~200 KB Measured: RSS dropped from 419 MB to 66 MB, db file descriptors from 4484 to 6, with zero growth over 3-minute observation window.
This commit is contained in:
+8
-1
@@ -42,6 +42,11 @@ func GetDb(exclude string) ([]byte, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
if sqlDB, e := backupDb.DB(); e == nil {
|
||||
_ = sqlDB.Close()
|
||||
}
|
||||
}()
|
||||
defer os.Remove(dbPath)
|
||||
|
||||
err = backupDb.AutoMigrate(
|
||||
@@ -218,7 +223,9 @@ func ImportDB(file multipart.File) error {
|
||||
return common.NewErrorf("Error checking db: %v", err)
|
||||
}
|
||||
newDb_db, _ := newDb.DB()
|
||||
newDb_db.Close()
|
||||
if newDb_db != nil {
|
||||
newDb_db.Close()
|
||||
}
|
||||
|
||||
// Backup the current database for fallback
|
||||
fallbackPath := fmt.Sprintf("%s.backup", config.GetDBPath())
|
||||
|
||||
+6
-2
@@ -55,7 +55,10 @@ func OpenDB(dbPath string) error {
|
||||
if strings.Contains(dbPath, "?") {
|
||||
sep = "&"
|
||||
}
|
||||
dsn := dbPath + sep + "_busy_timeout=10000&_journal_mode=WAL"
|
||||
// _cache_size=-200 caps each connection's page cache at ~200 KiB
|
||||
// (default is ~2 MiB), reducing memory amplification if a connection
|
||||
// escapes the pool.
|
||||
dsn := dbPath + sep + "_busy_timeout=10000&_journal_mode=WAL&_cache_size=-200"
|
||||
db, err = gorm.Open(sqlite.Open(dsn), c)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -66,8 +69,9 @@ func OpenDB(dbPath string) error {
|
||||
return err
|
||||
}
|
||||
sqlDB.SetMaxOpenConns(25)
|
||||
sqlDB.SetMaxIdleConns(5)
|
||||
sqlDB.SetMaxIdleConns(2)
|
||||
sqlDB.SetConnMaxLifetime(time.Hour)
|
||||
sqlDB.SetConnMaxIdleTime(5 * time.Minute)
|
||||
|
||||
if config.IsDebug() {
|
||||
db = db.Debug()
|
||||
|
||||
Reference in New Issue
Block a user