~/home

Обновление Node под pm2 без сюрпризов

· node, pm2

TL;DR: При обновлении Node.js через nvm под pm2: привяжите nvm alias default к мажорной версии, поправьте сохранённый PATH в ~/.pm2/dump.pm2 для приложений в fork mode, перегенерируйте systemd-юнит pm2 с новым бинарником node и проверьте readlink /proc/PID/exe, прежде чем удалять старую версию.

Вышел security-релиз, и я перевёл несколько pm2-приложений на свежую версию Node через nvm. Сам nvm install занял минуту. А вот найти все места, где пряталась старая версия, вышло заметно дольше. Ниже порядок, который сработал с одним рестартом на каждое приложение.

1. Привяжите default в nvm к мажорной версии

Если default у вас указывает на lts/*, nvm переписывает этот алиас при каждом запросе списка версий. Как только новая ветка становится LTS, default начинает указывать на версию, которую вы не ставили, и новые шеллы стартуют вообще без node.

nvm install 24 --reinstall-packages-from=22
nvm alias default 24

--reinstall-packages-from ставит ту же версию pm2, что была, а не последнюю. Здесь это ровно то, что нужно.

2. Приложения в fork mode помнят старый PATH

pm2 сохраняет окружение каждого приложения в ~/.pm2/dump.pm2. Приложения в fork mode запускают node через сохранённый PATH, поэтому после рестарта демона они тихо продолжают работать на старом бинарнике. Приложения в cluster mode используют node самого демона.

Сделайте бэкап дампа и замените старую версию в PATH, NVM_BIN, NVM_INC и _. pm2 restart --update-env тоже подойдёт, но если запускать его неинтерактивной командой по SSH, он подхватит урезанный PATH этого шелла.

3. Перегенерируйте systemd-юнит

В юните, который создаёт pm2 startup, путь к node зашит намертво. Сгенерируйте его заново с новым бинарником:

NEW=$HOME/.nvm/versions/node/v24.x.y
sudo env PATH=$NEW/bin:$PATH $NEW/bin/node $NEW/lib/node_modules/pm2/bin/pm2 \
  startup systemd -u $USER --hp $HOME
sudo systemctl daemon-reload
sudo systemctl restart pm2-$USER

pm2 update по SSH для этого не подходит: он перезапустит демон внутри scope вашей SSH-сессии, а не под systemd.

4. Проверьте и только потом удаляйте

for p in $(pgrep -f node); do readlink /proc/$p/exe; done | sort | uniq -c
pm2 save

nvm uninstall — только когда на старую версию больше ничего не ссылается.