PurpleSchool — курсы программирования онлайн
  • Пути
    • Frontend React разработчик
    • Frontend Vue разработчик
    • Backend разработчик Node.js
    • Fullstack разработчик React / Node.js
    • Mobile разработчик React Native
    • Backend разработчик Golang
    • Devops инженер
    • Backend разработчик Python
  • AI для кодаНовое
  • О нас
    • Отзывы
    • Реферальная программа
    • О компании
    • Контакты
  • Иконка открытия меню
    • Сообщество
    • PurpleПлюс
    • AI Собеседование
    • AI тренажёр
    • Проекты
PurpleSchool — платформа бесплатных roadmap и курсов для разработчиков
ютуб иконка
Telegram иконка
VK иконка
VK иконка
Курсы
ГлавнаяКаталог курсовFrontendBackendFullstack
Практика
КарьераПроектыPurpleПлюс
Материалы
БлогБаза знаний
Документы
Договор офертаПолитика конфиденциальностиПроверка сертификатаМиграция курсовРеферальная программа
Реквизиты
ИП Ларичев Антон АндреевичИНН 773373765379contact@purpleschool.ru

PurpleSchool © 2020 -2026 Все права защищены

  • Курсы
    • FrontendИконка стрелки
    • AI разработкаИконка стрелки
    • BackendИконка стрелки
    • DevOpsИконка стрелки
    • MobileИконка стрелки
    • ТестированиеИконка стрелки
    • Soft-skillsИконка стрелки
    • ДизайнИконка стрелки
    Иконка слояПерейти в каталог курсов
  • Бесплатно
    • Курсы
    • JavaScript Основы разработкиPython Основы PythonCSS CSS FlexboxКарта развитияВопросы для собеседований
    • База знанийИконка стрелки
    • Новостные рассылкиИконка стрелки
  • PurpleSchool — курсы программирования онлайн
    • AI для кодаНовое
    • Сообщество
    • PurpleПлюс
    • AI Собеседование
    • AI тренажёр
    • Проекты
    Главная
    Сообщество
    Graceful shutdown, health checks и zero-downtime deploy: чек-лист для продакшна

    Graceful shutdown, health checks и zero-downtime deploy: чек-лист для продакшна

    Аватар автора Graceful shutdown, health checks и zero-downtime deploy: чек-лист для продакшна

    Антон Ларичев

    Иконка календаря03 апреля 2026
    devopsnode.jsdockerseniorИконка уровня senior
    Картинка поста Graceful shutdown, health checks и zero-downtime deploy: чек-лист для продакшна

    Введение

    Graceful shutdown в Node.js — это механизм корректного завершения приложения, при котором ни один пользовательский запрос не теряется. В продакшне, где каждый потерянный запрос — это потенциально потерянный клиент, правильная реализация graceful shutdown критически важна. В сочетании с health checks и стратегией zero-downtime deploy вы получаете систему, которая обновляется без простоя.

    В этой статье разберём практический чек-лист: от обработки сигналов завершения до настройки readiness probe в Kubernetes. Все примеры — на Node.js с Docker и Kubernetes.

    Как реализовать graceful shutdown в Node.js

    При получении сигнала SIGTERM (который отправляет Docker или Kubernetes при остановке контейнера) приложение должно выполнить три действия: прекратить приём новых соединений, дождаться завершения текущих запросов и закрыть внешние подключения.

    import { createServer } from 'http';
    
    const server = createServer((req, res) => {
      // Обработка запроса
      res.writeHead(200);
      res.end('OK');
    });
    
    let isShuttingDown = false;
    
    // Обработчик graceful shutdown
    function shutdown(signal: string) {
      console.log(`Получен сигнал ${signal}, начинаем завершение...`);
      isShuttingDown = true;
    
      // Прекращаем приём новых соединений
      server.close(() => {
        console.log('Все соединения закрыты, завершаем процесс');
        process.exit(0);
      });
    
      // Принудительное завершение через таймаут
      setTimeout(() => {
        console.error('Таймаут graceful shutdown, принудительное завершение');
        process.exit(1);
      }, 10000);
    }
    
    process.on('SIGTERM', () => shutdown('SIGTERM'));
    process.on('SIGINT', () => shutdown('SIGINT'));
    
    server.listen(3000);
    

    Как закрыть соединения с базой данных и Redis при завершении

    Одного server.close() недостаточно. Нужно закрыть все внешние ресурсы — пулы соединений с базой данных, Redis-клиенты, очереди сообщений:

    import { Pool } from 'pg';
    import { createClient } from 'redis';
    
    const pgPool = new Pool({ connectionString: process.env.DATABASE_URL });
    const redis = createClient({ url: process.env.REDIS_URL });
    
    async function shutdown(signal: string) {
      console.log(`Получен ${signal}, начинаем drain...`);
      isShuttingDown = true;
    
      server.close(async () => {
        try {
          // Закрываем пул PostgreSQL
          await pgPool.end();
          console.log('PostgreSQL пул закрыт');
    
          // Закрываем Redis
          await redis.quit();
          console.log('Redis соединение закрыто');
    
          process.exit(0);
        } catch (err) {
          console.error('Ошибка при закрытии ресурсов:', err);
          process.exit(1);
        }
      });
    
      setTimeout(() => process.exit(1), 15000);
    }
    

    Настройка health checks для Docker и Kubernetes

    Health checks — это механизм, который сообщает оркестратору о состоянии приложения. В Kubernetes используются три типа проб: liveness probe, readiness probe и startup probe.

    Эндпоинт health check в приложении

    import express from 'express';
    
    const app = express();
    let isShuttingDown = false;
    let isReady = false;
    
    // Liveness — приложение живо
    app.get('/health/live', (req, res) => {
      res.status(200).json({ status: 'alive' });
    });
    
    // Readiness — приложение готово принимать трафик
    app.get('/health/ready', (req, res) => {
      if (isShuttingDown || !isReady) {
        return res.status(503).json({ status: 'not ready' });
      }
      res.status(200).json({ status: 'ready' });
    });
    
    // Отмечаем готовность после инициализации
    async function bootstrap() {
      await pgPool.connect(); // Проверяем соединение с БД
      await redis.connect();
      isReady = true;
      console.log('Приложение готово к приёму трафика');
    }
    

    Readiness probe в Kubernetes: как настроить правильно

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: api-server
    spec:
      replicas: 3
      template:
        spec:
          containers:
            - name: api
              image: myapp:latest
              ports:
                - containerPort: 3000
              livenessProbe:
                httpGet:
                  path: /health/live
                  port: 3000
                initialDelaySeconds: 5
                periodSeconds: 10
                failureThreshold: 3
              readinessProbe:
                httpGet:
                  path: /health/ready
                  port: 3000
                initialDelaySeconds: 3
                periodSeconds: 5
                failureThreshold: 2
              startupProbe:
                httpGet:
                  path: /health/live
                  port: 3000
                failureThreshold: 30
                periodSeconds: 2
          terminationGracePeriodSeconds: 30
    

    Ключевые параметры: readinessProbe с failureThreshold: 2 быстро выводит под из балансировки, а terminationGracePeriodSeconds задаёт максимальное время для graceful shutdown.

    Чек-лист zero-downtime deploy для продакшна

    Zero-downtime deploy — это стратегия обновления, при которой пользователи не замечают процесс деплоя. Вот полный чек-лист:

    Приложение

    1. Обрабатывает SIGTERM и выполняет graceful shutdown
    2. Отдаёт 503 на readiness probe при завершении
    3. Закрывает все соединения (БД, Redis, очереди)
    4. Имеет таймаут принудительного завершения
    5. Эндпоинты /health/live и /health/ready реализованы

    Docker

    FROM node:20-alpine
    
    WORKDIR /app
    COPY package*.json ./
    RUN npm ci --only=production
    COPY dist/ ./dist/
    
    # Используем tini для корректной передачи сигналов
    RUN apk add --no-cache tini
    ENTRYPOINT ["/sbin/tini", "--"]
    
    HEALTHCHECK --interval=10s --timeout=3s --retries=3 \
      CMD wget -qO- http://localhost:3000/health/live || exit 1
    
    CMD ["node", "dist/main.js"]
    

    Важный момент: без init-процесса (tini или --init в docker run) Node.js не получит SIGTERM, и контейнер будет убит через SIGKILL после таймаута.

    Kubernetes

    spec:
      strategy:
        type: RollingUpdate
        rollingUpdate:
          maxUnavailable: 0
          maxSurge: 1
      template:
        spec:
          containers:
            - name: api
              lifecycle:
                preStop:
                  exec:
                    command: ["sh", "-c", "sleep 5"]
    

    Параметр maxUnavailable: 0 гарантирует, что ни один под не будет удалён, пока новый не пройдёт readiness probe. А preStop hook с задержкой даёт время на распространение изменений в endpoint-ах кластера.

    Частые ошибки при настройке безостановочного деплоя

    Нет обработки SIGTERM. Приложение не слушает сигналы — контейнер убивается через SIGKILL через 30 секунд, все текущие запросы теряются.

    Liveness вместо readiness. Если использовать только liveness probe без readiness, Kubernetes не знает, готов ли под к трафику. Новый под начинает получать запросы до полной инициализации.

    Слишком короткий terminationGracePeriodSeconds. Если у вас есть длительные запросы (загрузка файлов, генерация отчётов), 30 секунд по умолчанию может не хватить. Увеличьте до 60-120 секунд.

    Отсутствие preStop hook. Без задержки перед завершением Kubernetes может отправлять трафик на под, который уже начал завершаться. Добавьте sleep 5 в preStop.

    Node.js как PID 1 в Docker. Без tini или --init Node.js запускается как PID 1 и не обрабатывает сигналы стандартным образом.

    Заключение

    Graceful shutdown, health checks и zero-downtime deploy — это три столпа надёжного продакшна. Реализация graceful shutdown в Node.js требует обработки SIGTERM, закрытия соединений и таймаута. Health checks через liveness и readiness probe дают оркестратору полную картину состояния приложения. А правильная стратегия rolling update с maxUnavailable: 0 и preStop hook обеспечивает безостановочный деплой.

    Используйте чек-лист из этой статьи перед каждым выводом сервиса в продакшн — это сэкономит часы отладки и предотвратит потерю пользовательских запросов.

    Иконка глаза715

    Комментарии

    0

    Постройте личный план изучения Основы разработки до уровня Middle — бесплатно!

    Основы разработки — часть карты развития Frontend, Backend, Mobile

    • step100+ шагов развития
    • lessons30 бесплатных лекций
    • lessons300 бонусных рублей на счет

    Бесплатные лекции

    Лучшие курсы по теме

    изображение курса

    Основы Git

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.9
    3 999 ₽ 6 990 ₽
    Подробнее
    изображение курса

    HTML и CSS

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.9
    3 999 ₽ 6 990 ₽
    Подробнее
    изображение курса

    CSS Flexbox

    Антон Ларичев
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.9
    бесплатно
    Подробнее

    Похожие статьи

    Картинка поста Git флоу для команды разработчиков: гайд по веткам и релизам
    Иконка аватараАнтон
    Иконка календаря30 сентября 2026
    gitgit-flowкомандная работа+ 2middleИконка уровня middle

    Git флоу для команды разработчиков: гайд по веткам и релизам

    Git флоу для команды разработчиков: разбираем Git Flow, GitHub Flow и trunk-based development — как выбрать модель веток и избежать конфликтов при совместной работе.

    Иконка чипа0
    Иконка глаза346
    Иконка комментариев0
    Картинка поста Микросервисная архитектура для начинающих: гайд с примерами
    Иконка аватараАнтон
    Иконка календаря23 сентября 2026
    микросервисыархитектураbackend+ 2juniorИконка уровня junior

    Микросервисная архитектура для начинающих: гайд с примерами

    Микросервисная архитектура простыми словами: чем она отличается от монолита, какие есть плюсы и минусы, и как спроектировать первую систему на микросервисах — с примерами кода.

    Иконка чипа0
    Иконка глаза247
    Иконка комментариев0
    Картинка поста CLAUDE.md: как написать инструкции для Claude Code
    Иконка аватараАнтон
    Иконка календаря11 октября 2026
    AI-инструментыClaude CodeDevOps+ 1middleИконка уровня middle

    CLAUDE.md: как написать инструкции для Claude Code

    CLAUDE.md — это файл с инструкциями по проекту, который Claude Code читает в начале каждой сессии. Положите его в корень репозитория и опишите внутри, чем проект собирается, чем запускаются тесты и каких соглашений держаться в коде. После этого агент перестанет спрашивать одно и то же в каждом новом диалоге и предлагать решения, которые в вашей кодовой базе не приняты. Формат предельно простой: обычный Markdown, обязательных полей нет, заголовки любые. Дальше — где именно создавать файл и как Claude Code собирает инструкции сразу из нескольких мест, что писать внутрь, как подключать к файлу другие документы и чем CLAUDE.md отличается от AGENTS.md. Одна оговорка перед началом: Claude Code обновляется часто, набор команд и поддерживаемых файлов пополняется. Если какая-то деталь ниже ведёт себя у вас иначе, сверяйтесь с документацией той версии, которая стоит у вас.

    Иконка чипа0
    Иконка глаза141
    Иконка комментариев0
    Иконка чипа0