Перейти к содержимому
ГоМастер

Поиск по урокам

Найдите урок, курс, термин или раздел

Чек-лист продакшена для Go-сервиса

Локально сервис работает, а в бою выясняется, что запрос без таймаута висит вечно, деплой рвёт пользовательские соединения, а при падении базы нельзя понять, где искать причину. Проблемы из этого списка не относятся к одному коммиту, поэтому на код-ревью их обычно не видно — их и собирают в отдельный чек-лист.

9 групп, 34 пунктовотметки хранятся в браузере

Что стоит за каждым пунктом

Список разбит на девять групп: таймауты и отмена, graceful shutdown, health-check, лимиты, логирование, метрики, конфигурация, безопасность и тесты. Порядок групп не случаен — он совпадает с порядком, в котором проблемы проявляются в жизни: сначала сервис зависает, потом не выключается, потом о нём невозможно понять, что происходит.

Каждый пункт — это не «хорошая практика вообще», а конкретная проверка с объяснением: почему пункт важен, что произойдёт без него и как это выглядит в коде. Там, где есть типовое решение, приведён пример.

Отметки сохраняются в localStorage, поэтому чек-лист можно проходить по частям и возвращаться к нему перед каждым релизом. Кнопка «Скопировать списком» превращает результат в текст, который можно вставить в задачу или в обсуждение с командой.

Кому это полезнее всего: автору первого сервиса, который уходит в продакшен, и ревьюеру, который хочет задать правильные вопросы на ревью архитектуры. Перечитывать чек-лист полезно и опытному разработчику: часть пунктов со временем меняет смысл. Например, лимит на размер тела запроса становится обязательным, как только за сервисом появляется публичный API, а health-check для готовности — после первого деплоя с несколькими репликами.

Прогресс

Отметки сохраняются в вашем браузере: можно пройти чек-лист частями и вернуться позже.

Отмечено
0 / 34
Готовность
0%
Группы закрыты
0
из 9

Таймауты и отмена

0 из 4

Запрос без таймаута — это зависший воркер, съеденный connection pool и падение.

  • client := &http.Client{
        Timeout: 10 * time.Second,
    }
  • ctx, cancel := context.WithTimeout(r.Context(), 2*time.Second)
    defer cancel()
    
    if err := repo.Save(ctx, order); err != nil {
        return err
    }
  • pool, err := pgxpool.New(ctx, dsn)
    pool.Config().MaxConnLifetime = 30 * time.Minute

Graceful shutdown

0 из 4

Сервис должен уметь завершиться, не оборвав запросы на полуслове.

  • ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
    defer stop()
  • ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
    defer cancel()
    
    if err := srv.Shutdown(ctx); err != nil {
        log.Error("shutdown", "err", err)
    }

Health-check

0 из 3

Оркестратор должен понимать, жив ли процесс и готов ли он принимать трафик.

Лимиты и защита

0 из 4

Ограничение тела запроса, числа соединений и частоты — базовая гигиена сервиса.

  • r.Body = http.MaxBytesReader(w, r.Body, 1<<20) // 1 МБ
  • srv := &http.Server{
        ReadHeaderTimeout: 5 * time.Second,
        WriteTimeout:      30 * time.Second,
    }

Логирование

0 из 4

Логи должны быть пригодны для чтения человеком и для агрегации машиной.

  • slog.Info("order created",
        "order_id", id,
        "amount", amount,
    )

Метрики

0 из 4

Метрики отвечают на вопрос «что сломалось» до того, как об этом узнал пользователь.

Конфигурация

0 из 3

Конфигурация проверяется при старте, а не в середине рабочего дня.

  • if cfg.Addr == "" {
        return errors.New("ADDR is required")
    }

Безопасность

0 из 4

Секреты, TLS, ввод пользователя и заголовки ответов.

Тесты и CI

0 из 4

Проверки, которые ловят проблемы до релиза, а не после.

Чек-лист можно проходить по одному пункту: отметьте то, что уже сделано, и вернитесь позже. Пункты из группы «Таймауты и отмена» обычно дают самую большую пользу в первый же день.

Частые вопросы о готовности сервиса к продакшену

Зачем нужен чек-лист, если есть код-ревью?

Ревью смотрит на конкретное изменение, а чек-лист — на сервис целиком: есть ли в нём таймауты, health-check, лимиты и остановка. Проблемы из этого списка обычно не относятся к одному коммиту, поэтому на ревью их не видно. Чек-лист проходят один раз при выводе сервиса в бой, а потом — по пунктам при изменении архитектуры.

Как правильно настроить health-check в Kubernetes?

Разделяйте liveness и readiness. Liveness отвечает «процесс жив» и не должен ходить во внешние зависимости: иначе при кратковременной недоступности базы Kubernetes перезапустит здоровый под. Readiness отвечает «можно принимать трафик» и проверяет критичные зависимости: во время миграции или прогрева кэша readiness должен возвращать отказ, и новые поды не получат трафик. Оба эндпоинта — на отдельном порту, недоступном извне.

Нужен ли лимит на размер тела запроса, если за прокси стоит nginx?

Прокси обычно ограничивает размер тела, и это уже спасает от самых крупных запросов. Но nginx можно настроить неправильно или вовсе не ставить перед Go-сервисом. Лимит в самом приложении — последний рубеж: http.MaxBytesReader обрывает чтение тела и не даёт процессу съесть память на мусорном запросе.

Где хранить отметки и можно ли ими поделиться?

Отметки лежат в localStorage вашего браузера и никуда не отправляются. Чтобы поделиться результатом, нажмите «Скопировать списком» — получите текст с отметками, который можно вставить в задачу или обсуждение.

Где разобрать эксплуатацию подробнее