Graceful Shutdown в Node.js
Корректное завершение процесса: дослушать активные запросы, закрыть соединения с БД, сбросить буферы логов — потом
process.exit(0). Альтернатива — потеря данных и битые сессии.
Зачем нужно
В продакшене процесс рестартится десятки раз в день: deploy, OOM, kubernetes scale, systemd reload. Если просто убить процесс (SIGKILL), то:
- активные HTTP-запросы оборвутся на полпути — клиент получит ECONNRESET
- транзакция в БД может остаться незавершённой
- буфер логов не сбросится — последние события потеряются
- WebSocket-клиенты не получат сигнал disconnect
Сигналы
- SIGTERM — «вежливая» просьба завершиться (kubectl, systemctl, docker stop). Обрабатываем.
- SIGINT — Ctrl+C. Обрабатываем как SIGTERM в dev.
- SIGKILL —
kill -9, не перехватывается. Если до него дошло — что-то пошло не так. - SIGHUP — закрытие терминала, обычно «перечитай конфиг».
Пример
const http = require('http');
const server = http.createServer(handler);
server.listen(3000);
let shuttingDown = false;
async function shutdown(signal) {
if (shuttingDown) return;
shuttingDown = true;
console.log(`Received ${signal}, shutting down...`);
// 1. Перестать принимать новые соединения
server.close( => console.log('HTTP closed'));
// 2. Дать активным запросам ~30 секунд
const timeout = setTimeout(() => {
console.error('Forced shutdown');
process.exit(1);
}, 30_000);
timeout.unref;
// 3. Закрыть БД, очереди, логи
await db.close();
await logger.flush;
process.exit(0);
}
process.on('SIGTERM', () => shutdown('SIGTERM'));
process.on('SIGINT', () => shutdown('SIGINT'));
process.on('uncaughtException', (err) => {
console.error(err);
shutdown('uncaughtException');
});
Подводные камни
- Health check должен ОТВЕЧАТЬ unhealthy сразу после получения SIGTERM — иначе load balancer продолжит слать трафик
- Долгие операции (миграция, large query) могут не успеть за timeout — выбирай разумное окно
- Kubernetes даёт
terminationGracePeriodSeconds(по умолчанию 30s) — синхронизируй - PM2 в cluster mode сам шлёт SIGTERM воркерам и ждёт
wait_readyсобытия - Двойной shutdown — флаг
shuttingDownобязателен, иначе несколько одновременных сигналов вызовут гонки
🎓 Источники
- 🎓 [Graceful Shutdown в Node.js] · 2019-09-12 · YouTube · [Marp](../../../Documents/TimurShemsedinov/2019-09-12 — Graceful Shutdown в Node.js (ZstnowFeCe0).md)
- Тезисы: перехват SIGTERM/SIGINT, последовательное закрытие server/db/queue/log, таймаут на принудительное завершение, корректное завершение worker_threads и cluster воркеров