Graceful shutdown и жизненный цикл приложения

↑ 3.5 Инфраструктура приложения: ошибки, health checks, фоновые задачи · ← Предыдущая · → Следующая

Обязательно~3 мин чтенияУровень: middle

Зачем это на собесе

Как не терять запросы при деплое в Kubernetes.

Объяснение

Последовательность при остановке: сигнал SIGTERM → IHostApplicationLifetime.ApplicationStopping → сервер перестаёт принимать новые соединения и ждёт текущие → остановка IHostedService (в обратном порядке) → ApplicationStopped.

builder.Services.Configure<HostOptions>(o => o.ShutdownTimeout = TimeSpan.FromSeconds(30));
 
lifetime.ApplicationStopping.Register(() => log.LogInformation("Stopping..."));

В Kubernetes:

  1. Под получает Terminating, его убирают из endpoints (readiness).
  2. Параллельно отправляется SIGTERM.
  3. По истечении terminationGracePeriodSeconds — SIGKILL.

Из-за гонки между удалением из балансировки и SIGTERM короткая задержка в preStop (sleep 5) предотвращает потерю запросов.

Что делать при остановке

  • Завершить in-flight запросы, не принимать новые.
  • Остановить консюмеры: перестать читать, закончить текущее, закоммитить offset.
  • Сбросить буферы (логи, метрики, outbox).
  • Освободить блокировки и соединения.

Нюансы и подводные камни

  • ShutdownTimeout по умолчанию 30 секунд (в .NET 6+); должен быть меньше terminationGracePeriodSeconds.
  • PID 1 в контейнере: используйте exec в entrypoint, чтобы сигнал дошёл до процесса.
  • Долгие запросы должны реагировать на RequestAborted/ApplicationStopping.
  • Данные в памяти, не сохранённые до остановки, теряются: используйте очереди и транзакции.

Практика

  1. Отправьте SIGTERM во время запроса и убедитесь, что он завершился.
  2. Добавьте preStop и проверьте отсутствие 502 при rolling update.
  3. Корректно остановите Kafka consumer.

Вопросы с ответами

Связанные темы