Ответ
В Go для отслеживания и обработки ошибок соединения с БД используется комбинация нескольких подходов, так как пакет database/sql
абстрагирует пул соединений.
-
Проверка при инициализации (
sql.Open
)sql.Open
не устанавливает соединение с БД, а лишь подготавливает структуру*sql.DB
. Ошибка на этом этапе означает неверные параметры (например, неправильный DSN или несуществующий драйвер).db, err := sql.Open("postgres", "user=... password=... ...") if err != nil { // Ошибка конфигурации, а не сети log.Fatalf("Invalid DB config: %v", err) }
-
Проверка реального соединения (
db.PingContext
) Это основной способ проверить, что соединение с базой данных может быть установлено. Его вызывают сразу послеsql.Open
.ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := db.PingContext(ctx); err != nil { log.Fatalf("DB connection failed: %v", err) }
-
Обработка ошибок при выполнении запросов Любой вызов (
QueryContext
,ExecContext
,BeginTx
) может вернуть ошибку, связанную с потерей соединения. Пакетdatabase/sql
пытается автоматически переподключиться при некоторых временных ошибках, но если это не удается, ошибка будет возвращена приложению.rows, err := db.QueryContext(ctx, "SELECT id FROM users") if err != nil { // Здесь может быть ошибка сети, таймаут или другая проблема с соединением log.Printf("Query failed: %v", err) // Здесь можно реализовать логику повторных попыток (retry) return }
-
Реализация логики повторных попыток (Retry) Для временных сбоев сети полезно реализовать механизм
retry
с экспоненциальной выдержкой (exponential backoff), чтобы не перегружать БД запросами на переподключение.// Псевдокод for i := 0; i < maxRetries; i++ { err = db.Ping() if err == nil { break // Успешно } // Ожидаем (1s, 2s, 4s, ...) time.Sleep(time.Second * (1 << i)) }
-
Мониторинг состояния пула соединений
*sql.DB
предоставляет статистику пула, которая помогает отслеживать его здоровье.stats := db.Stats() // stats.OpenConnections - количество открытых соединений // stats.WaitCount - сколько раз запросы ждали свободного соединения // stats.WaitDuration - общее время ожидания
Эти метрики полезно экспортировать в систему мониторинга (Prometheus, Grafana) для долгосрочного анализа.