Ваши шаги по расследованию и устранению ошибки 500 (Internal Server Error)?

Ответ

Ошибка 500 (Internal Server Error) — это общий код ответа, означающий, что на сервере произошла непредвиденная ошибка. Мой план действий для её диагностики будет следующим:

Шаг 1: Сбор информации (не трогая прод)

  1. Проверить логи приложения: Это первое и самое важное место. Искать записи об ошибках (ERROR, FATAL), паниках (panic) и их стектрейсы, которые произошли в момент получения 500-й ошибки.
  2. Проверить логи веб-сервера (Nginx, Apache): Если приложение работает за прокси-сервером, ошибка может быть на его уровне (например, upstream sent invalid header).
  3. Системы мониторинга и алертинга (Prometheus, Grafana, Sentry): Проанализировать дашборды. Возможно, есть всплеск нагрузки на CPU/RAM, нехватка дискового пространства, или ошибка уже была автоматически зафиксирована и сгруппирована в Sentry.

Шаг 2: Воспроизведение и локализация

  1. Попытаться воспроизвести ошибку: Если возможно, воспроизвести ошибку в тестовом или staging-окружении с теми же входными данными. Это самый безопасный способ для отладки.
  2. Проанализировать запрос: Какой именно эндпоинт, с какими параметрами, заголовками и телом запроса вызывает ошибку?
  3. Проверить внешние зависимости: Убедиться, что базы данных, кэши (Redis), брокеры сообщений (RabbitMQ, Kafka) и другие внешние API, к которым обращается сервис, доступны и работают корректно.

Шаг 3: Анализ кода и исправление

  1. Анализ стектрейса: Если есть panic, стектрейс точно укажет на место в коде, где произошла проблема. В Go для перехвата паник в HTTP-обработчиках используется recover.
    func recoveryMiddleware(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            defer func() {
                if err := recover(); err != nil {
                    log.Printf("recovered from panic: %vn%s", err, debug.Stack())
                    http.Error(w, "Internal Server Error", http.StatusInternalServerError)
                }
            }()
            next.ServeHTTP(w, r)
        })
    }
  2. Анализ недавних изменений: Проверить последние коммиты и деплои. Очень часто причина кроется в недавно добавленном коде.
  3. Логирование запросов/ответов: Если причина неясна, можно временно добавить middleware для детального логирования входящих запросов и ответов, чтобы поймать проблемный случай.
    func loggingMiddleware(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            log.Printf("Request: %s %s", r.Method, r.URL.Path)
            next.ServeHTTP(w, r)
        })
    }

Шаг 4: Внедрение исправления

  1. Написать исправление и тесты: Устранить причину ошибки и написать регрессионный тест, который бы падал без этого исправления, чтобы предотвратить повторение ошибки в будущем.
  2. Выкатить исправление: Развернуть исправленную версию приложения.