feat(dbmanager): report pool max size and total connections opened

Add MaxOpenConnections to provider and connection stats, exposed as the
max state of dbmanager_connection_pool_size. Count physical dials through a
counting driver connector and export dbmanager_connections_opened_total;
existing_db pools derive an approximate count from sql.DBStats.
This commit is contained in:
Hein
2026-09-30 15:46:41 +02:00
parent d3a99550d9
commit 178d40587d
11 changed files with 191 additions and 51 deletions
@@ -3,9 +3,11 @@ package providers
import (
"context"
"database/sql"
"sync/atomic"
"testing"
"time"
_ "github.com/glebarez/sqlite"
_ "github.com/mattn/go-sqlite3"
)
@@ -159,6 +161,10 @@ func TestExistingDBProvider_Stats(t *testing.T) {
t.Errorf("Expected stats.Type to be 'sql', got '%s'", stats.Type)
}
if stats.MaxOpenConnections != 10 {
t.Errorf("Expected stats.MaxOpenConnections to be 10, got %d", stats.MaxOpenConnections)
}
if !stats.Connected {
t.Error("Expected stats.Connected to be true")
}
@@ -192,3 +198,35 @@ func TestExistingDBProvider_Close_NilDB(t *testing.T) {
t.Errorf("Expected Close to succeed with nil database, got error: %v", err)
}
}
func TestOpenCountedCountsDials(t *testing.T) {
var opened atomic.Int64
db, err := openCounted("sqlite", ":memory:", &opened)
if err != nil {
t.Fatal(err)
}
defer db.Close()
db.SetMaxOpenConns(1)
if err := db.PingContext(context.Background()); err != nil {
t.Fatal(err)
}
if got := opened.Load(); got != 1 {
t.Fatalf("opened = %d after first ping, want 1", got)
}
// Reusing the pooled connection must not count as a new dial.
if err := db.PingContext(context.Background()); err != nil {
t.Fatal(err)
}
if got := opened.Load(); got != 1 {
t.Fatalf("opened = %d after reuse, want 1", got)
}
// Dropping idle connections forces a fresh dial.
db.SetMaxIdleConns(0)
if err := db.PingContext(context.Background()); err != nil {
t.Fatal(err)
}
if got := opened.Load(); got != 2 {
t.Fatalf("opened = %d after redial, want 2", got)
}
}