Ответ
Ошибка 500 (Internal Server Error) — это общий код ответа, означающий, что на сервере произошла непредвиденная ошибка. Мой план действий для её диагностики будет следующим:
Шаг 1: Сбор информации (не трогая прод)
- Проверить логи приложения: Это первое и самое важное место. Искать записи об ошибках (
ERROR
,FATAL
), паниках (panic
) и их стектрейсы, которые произошли в момент получения 500-й ошибки. - Проверить логи веб-сервера (Nginx, Apache): Если приложение работает за прокси-сервером, ошибка может быть на его уровне (например,
upstream sent invalid header
). - Системы мониторинга и алертинга (Prometheus, Grafana, Sentry): Проанализировать дашборды. Возможно, есть всплеск нагрузки на CPU/RAM, нехватка дискового пространства, или ошибка уже была автоматически зафиксирована и сгруппирована в Sentry.
Шаг 2: Воспроизведение и локализация
- Попытаться воспроизвести ошибку: Если возможно, воспроизвести ошибку в тестовом или staging-окружении с теми же входными данными. Это самый безопасный способ для отладки.
- Проанализировать запрос: Какой именно эндпоинт, с какими параметрами, заголовками и телом запроса вызывает ошибку?
- Проверить внешние зависимости: Убедиться, что базы данных, кэши (Redis), брокеры сообщений (RabbitMQ, Kafka) и другие внешние API, к которым обращается сервис, доступны и работают корректно.
Шаг 3: Анализ кода и исправление
- Анализ стектрейса: Если есть
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) }) }
- Анализ недавних изменений: Проверить последние коммиты и деплои. Очень часто причина кроется в недавно добавленном коде.
- Логирование запросов/ответов: Если причина неясна, можно временно добавить 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: Внедрение исправления
- Написать исправление и тесты: Устранить причину ошибки и написать регрессионный тест, который бы падал без этого исправления, чтобы предотвратить повторение ошибки в будущем.
- Выкатить исправление: Развернуть исправленную версию приложения.