Ответ
Таймаут от БД — это ожидаемая ошибка в распределенных системах. Если ее не обработать, приложение вернет клиенту общую ошибку 500 Internal Server Error
, что неинформативно. Правильная обработка включает несколько уровней защиты.
1. Использование context
с таймаутом (Основное решение)
Для каждого входящего запроса создавайте context
с дедлайном и передавайте его во все вызовы, взаимодействующие с внешними системами (БД, другие сервисы).
func handleRequest(w http.ResponseWriter, r *http.Request) {
// Устанавливаем таймаут на операцию с БД, например, 3 секунды
ctx, cancel := context.WithTimeout(r.Context(), 3*time.Second)
defer cancel()
var user User
// Передаем контекст в вызов к БД
err := db.QueryRowContext(ctx, "SELECT name FROM users WHERE id = $1", 1).Scan(&user.Name)
if err != nil {
// Проверяем, была ли ошибка вызвана именно таймаутом контекста
if errors.Is(err, context.DeadlineExceeded) {
// Возвращаем клиенту корректный код ошибки
http.Error(w, "Database operation timed out", http.StatusGatewayTimeout) // 504
return
}
// Обрабатываем другие возможные ошибки БД
http.Error(w, "Internal Server Error", http.StatusInternalServerError) // 500
return
}
// ... успешный ответ
}
2. Дополнительные защитные меры
- Правильный HTTP-статус: Вместо
500 Internal Server Error
лучше использовать504 Gateway Timeout
или503 Service Unavailable
. Это точнее описывает проблему для клиента и систем мониторинга. - Настройка пула соединений: Ограничьте максимальное количество открытых соединений (
SetMaxOpenConns
) и время жизни соединения (SetConnMaxLifetime
), чтобы предотвратить исчерпание ресурсов и использование "зависших" соединений. - Логика повторных запросов (Retry): Для временных ошибок можно реализовать механизм повторных запросов, желательно с экспоненциальной задержкой (
exponential backoff
), чтобы не "завалить" запросами и без того нагруженную БД. - Паттерн Circuit Breaker (Предохранитель): Если БД стабильно не отвечает, Circuit Breaker временно прекращает отправку новых запросов, давая ей время на восстановление и предотвращая каскадные сбои в вашем сервисе.