Health check и SIGTERM: как подготовить API к обновлениям
Зачем различать живой процесс и готовое приложение, как завершать HTTP-запросы при SIGTERM и что проверять после релиза в Inquir Compute.
Зелёный статус контейнера ещё не означает, что пользователь может оформить заказ. HTTP-сервер может отвечать, пока приложение не загрузило конфигурацию или потеряло доступ к обязательной базе. Обратная проблема возникает при обновлении: работающий процесс завершают, а текущие запросы не успевают закончиться.
Эти две границы — начало и конец жизни процесса — стоит проектировать вместе. Разберём небольшой API на Node.js, а затем настроим проверку здоровья и время завершения в Inquir Compute. Пример не обещает обновлений без единой потерянной связи: длинные соединения, нехватка ресурсов и состояние базы требуют отдельных решений.
Разделите «жив» и «готов»
Простая проверка процесса отвечает на вопрос: способен ли сервер обработать HTTP-запрос? Проверка готовности отвечает на другой: может ли эта версия сейчас обслуживать полезный трафик? Не делайте готовность успешной раньше завершения обязательной инициализации.
Не включайте в каждую проверку все внешние сервисы. Если недоступен необязательный сервис рекомендаций, отключение всего API может усилить сбой. Для обязательных зависимостей используйте ограниченные таймауты и учитывайте нагрузку от самих проверок. Общие понятия health checks и graceful shutdown разобраны в документации Express; конкретные проверки платформы нужно настраивать отдельно.
Минимальный сервер с завершением запросов
Сохраните код в server.mjs. Он использует стандартную библиотеку Node.js и не требует npm-зависимостей:
import http from 'node:http';
let stopping = false;
const server = http.createServer((req, res) => {
if (req.url === '/readyz') {
res.writeHead(stopping ? 503 : 200);
return res.end(stopping ? 'stopping' : 'ready');
}
if (stopping) {
res.writeHead(503, { Connection: 'close' });
return res.end('retry later');
}
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ version: 'v1' }));
});
server.listen(3000, '0.0.0.0');
process.on('SIGTERM', () => {
if (stopping) return;
stopping = true;
const deadline = setTimeout(() => process.exit(1), 25_000);
deadline.unref();
server.close(() => {
clearTimeout(deadline);
process.exit(0);
});
});
У этого примера нет базы, поэтому готовность означает готовность HTTP-процесса. В реальном API добавьте инициализацию до начала приёма трафика, а при завершении закройте пул подключений после окончания запросов. Не копируйте process.exit(0) перед закрытием своих ресурсов: незавершённые операции потеряют шанс закончиться.
Здесь внутренний дедлайн — 25 секунд. Это выбранная настройка примера, не лимит HTTP-запроса платформы. Если операция может работать несколько минут, лучше вынести её в устойчивую фоновую задачу, а клиенту вернуть идентификатор. Для WebSocket нужны собственная процедура закрытия и повторное подключение клиента: server.close() не решает жизненный цикл всех upgraded-соединений.
Упакуйте сервер и настройте Inquir
FROM node:22-bookworm-slim
WORKDIR /app
COPY --chown=node:node server.mjs ./
USER node
EXPOSE 3000
CMD ["node", "server.mjs"]
После авторизации CLI создайте отдельное тестовое приложение:
inquir apps create readiness-demo --ingress public --port 3000 --health-path /readyz --drain-grace 30
inquir apps deploy readiness-demo --promote
inquir apps status readiness-demo
В примере процессу даётся 30 секунд после SIGTERM, а его собственный дедлайн короче на 5 секунд. Запас позволяет закончить самостоятельно. Поддерживаемый диапазон --drain-grace в CLI — от 0 до 3600 целых секунд. Это время завершения старого контейнера; оно не гарантирует доступность дополнительной реплики во время обновления.
Проверьте переход между версиями
Сначала запросите /readyz и / на адресе из status. Затем измените version на v2, выполните новый deploy и убедитесь, что публичный ответ изменился. Во время теста посылайте несколько запросов в секунду и записывайте HTTP-статусы, задержки и ошибки соединения. Не делайте вывод по единственному удачному запросу.
Отдельно в тестовом окружении проверьте нездоровый релиз: временно возвращайте 503 из /readyz. Цель проверки — увидеть, что нездоровая версия не становится нормально обслуживающим production. Сохраните идентификатор предыдущего релиза и проверьте текущее состояние; не повторяйте promote вслепую после таймаута CLI.
Для диагностики используйте inquir apps logs readiness-demo --no-follow --tail 100. Руководство по приложениям описывает релизы, а разбор ошибок деплоя помогает отделить проблемы порта, запуска и маршрутизации. Откат приложения не отменяет миграцию базы и не восстанавливает удалённые файлы — эти изменения требуют собственного плана.