여기서는 멈추세요
- 정확한 PM2 소유 사용자·PM2_HOME·애플리케이션 이름을 확인하지 못했다면 restart·save를 실행하지 않습니다.
- DB migration·queue consumer·cron job의 중복 실행 영향을 확인하지 못했다면 cluster reload나 instance 증감을 하지 않습니다.
- 로그·dump.pm2·unit environment에 비밀이 나타나면 수집을 중단하고 접근 통제와 마스킹을 먼저 적용합니다.
PROCESS RESTART
SAFE OPERATING BOUNDARY
0600으로 보관한 ecosystem과 이전 정상 artifact·Node version을 같은 묶음으로 복원하고 startOrReload로 한 번만 전환합니다. Node upgrade 뒤라면 startup unit의 절대 PATH도 이전 version으로 다시 생성하고 안정화 후 process list를 저장합니다. 이미 처리 중이던 HTTP·queue·cron 업무는 PM2 rollback이 복원하지 않으므로 idempotency·재처리 기준을 적용합니다.
BEFORE YOU START
CHECK THE BRANCH
첫 실패의 stderr·stack trace와 종료 코드를 기준으로 config·module·port·의존 서비스 원인을 해결합니다. restart 횟수 초기화로 증거를 숨기지 않습니다.
배포·로그·temp 파일이 watch path에 포함됐는지, RSS가 max_memory_restart를 넘는지 확인합니다. threshold만 크게 올리기 전에 메모리 추세를 조사합니다.
nvm은 shell 함수이고 PM2 startup unit은 생성 당시의 절대 Node 경로를 사용할 수 있습니다. unit PATH와 서비스 계정의 실제 Node·PM2를 비교합니다.
DB·queue·외부 API를 계속 압박하지 않도록 exponential backoff와 제한된 max_restarts를 적용하고 근본 의존성부터 복구합니다.
FOLLOW THE FLOW
반드시 PM2를 소유한 Unix 계정으로 조회합니다. 다른 계정의 PM2 daemon을 새로 띄우면 장애 상태를 잘못 판단할 수 있습니다.
sudo -iu <APP_USER> bash -lc '. "$HOME/.nvm/nvm.sh"; nvm use <APPROVED_NODE_24_VERSION> >/dev/null; pm2 list; pm2 ping'sudo -iu <APP_USER> bash -lc '. "$HOME/.nvm/nvm.sh"; nvm use <APPROVED_NODE_24_VERSION> >/dev/null; pm2 describe <APP_NAME>'출력에 내부 경로·environment 차이가 포함될 수 있어 외부 공유 전 마스킹합니다.systemctl status pm2-<APP_USER>.service --no-pager -l
systemctl cat pm2-<APP_USER>.serviceps -eo pid,ppid,user,%cpu,%mem,rss,etime,stat,comm --sort=-rss | head -30
sudo ss -lntp | grep -E ':<APP_PORT>\b'PM2 status, restart count, uptime와 systemd NRestarts를 구분합니다. 서로 다른 사용자·PM2_HOME·process manager가 같은 app을 관리하는지 확인합니다.
첫 실패 로그와 exit code를 제한된 범위로 수집합니다.
실시간 tail 대신 고정 줄 수와 장애 시각을 확인합니다. PM2 report·jlist·환경 전체는 secret을 포함할 수 있어 외부 공유용으로 실행하지 않습니다.
sudo -iu <APP_USER> bash -lc '. "$HOME/.nvm/nvm.sh"; nvm use <APPROVED_NODE_24_VERSION> >/dev/null; pm2 logs <APP_NAME> --lines 200 --nostream --timestamp'sudo -iu <APP_USER> bash -lc '. "$HOME/.nvm/nvm.sh"; nvm use <APPROVED_NODE_24_VERSION> >/dev/null; tail -n 200 "$HOME/.pm2/pm2.log"'journalctl -u pm2-<APP_USER>.service --since '<INCIDENT_START>' --until '<INCIDENT_END>' --no-pagersudo -iu <APP_USER> bash -lc '. "$HOME/.nvm/nvm.sh"; nvm use <APPROVED_NODE_24_VERSION> >/dev/null; command -v node; node --version; command -v pm2; pm2 --version'MODULE_NOT_FOUND·EADDRINUSE·permission·config parse·dependency timeout·signal·memory restart를 첫 exit와 연결합니다. 반복 로그의 마지막 문장만 보지 않습니다.
artifact·cwd·config·dependency를 PM2 밖에서 안전하게 검증합니다.
현재 process를 건드리지 않고 ecosystem 문법, script 존재·권한, port 소유자와 dependency endpoint를 확인합니다. 실제 secret 값은 출력하지 않습니다.
sudo -iu <APP_USER> bash -lc '. "$HOME/.nvm/nvm.sh"; nvm use <APPROVED_NODE_24_VERSION> >/dev/null; node --check <ECOSYSTEM_FILE>'namei -l <APP_CWD>/<APP_SCRIPT>
sudo -u <APP_USER> test -r <APP_CWD>/<APP_SCRIPT> && echo readablesudo ss -lntp | grep -E ':<APP_PORT>\b'curl -fsS --connect-timeout 3 <APPROVED_DEPENDENCY_HEALTH_URL>인증정보를 URL에 넣지 않고 사설 health endpoint만 조회합니다.같은 artifact가 foreground에서도 즉시 종료하면 PM2 문제가 아니라 애플리케이션·환경 문제입니다. port owner·권한·Node ABI를 함께 봅니다.
watch·restart·memory·startup PATH와 이전 정상 ecosystem 차이를 검토합니다.
이전 정상 revision과 현재 ecosystem을 source control에서 비교합니다. watch, autorestart, min_uptime, max_restarts, backoff, max_memory_restart와 startup unit Node 경로를 확인합니다.
git -C <APP_REPOSITORY> diff <LAST_GOOD_REVISION> -- <ECOSYSTEM_RELATIVE_PATH>systemctl show pm2-<APP_USER>.service -p ExecStart -p ExecStop -p User -p FragmentPath환경 변수 원문은 비밀을 포함할 수 있으므로 조회하지 않고 Node·PM2 실행 경로만 확인합니다.sudo -iu <APP_USER> bash -lc '. "$HOME/.nvm/nvm.sh"; nvm use <APPROVED_NODE_24_VERSION> >/dev/null; pm2 monit'대화형 조회입니다. 장애 중 장시간 열어두지 않고 RSS·restart 시각만 기록합니다.sudo -iu <APP_USER> bash -lc '. "$HOME/.nvm/nvm.sh"; nvm use <APPROVED_NODE_24_VERSION> >/dev/null; node -p "process.version + \" modules=\" + process.versions.modules"'짧은 uptime을 failure로 제한하는 max_restarts와 backoff가 없으면 외부 의존성을 압박합니다. nvm Node 변경 뒤 unit PATH가 이전 version이면 startup만 실패할 수 있습니다.
근본 원인 수정안과 정상 revision·backup을 승인합니다.
변경 전 ecosystem과 PM2 process 목록을 0600으로 보관하고 코드·의존성·restart 전략 중 확인한 원인만 수정합니다. 즉시 pm2 save하지 않습니다.
sudo install -d -o root -g root -m 0700 <APPROVED_BACKUP_DIR>
if sudo test -f <ECOSYSTEM_FILE>; then sudo cp --archive --no-clobber <ECOSYSTEM_FILE> <APPROVED_BACKUP_DIR>/ecosystem.before.cjs; fi
if sudo test -f /home/<APP_USER>/.pm2/dump.pm2; then sudo cp --archive --no-clobber /home/<APP_USER>/.pm2/dump.pm2 <APPROVED_BACKUP_DIR>/dump.before.pm2; fi
if sudo test -f <APPROVED_BACKUP_DIR>/ecosystem.before.cjs; then sudo chmod 0600 <APPROVED_BACKUP_DIR>/ecosystem.before.cjs; fi
if sudo test -f <APPROVED_BACKUP_DIR>/dump.before.pm2; then sudo chmod 0600 <APPROVED_BACKUP_DIR>/dump.before.pm2; fi존재하는 ecosystem·dump만 변경 전에 no-clobber로 복사합니다. dump에는 환경값이 포함될 수 있으므로 0700/0600 경로에서만 보관하고 외부 공유 전에 비밀·개인정보를 마스킹합니다.sudo -iu <APP_USER> bash -lc '. "$HOME/.nvm/nvm.sh"; nvm use <APPROVED_NODE_24_VERSION> >/dev/null; node --check <REVIEWED_ECOSYSTEM_FILE>; pm2 startOrReload <REVIEWED_ECOSYSTEM_FILE> --only <APP_NAME>'sudo -iu <APP_USER> bash -lc '. "$HOME/.nvm/nvm.sh"; nvm use <APPROVED_NODE_24_VERSION> >/dev/null; pm2 describe <APP_NAME>; pm2 logs <APP_NAME> --lines 100 --nostream --timestamp'
curl -fsS http://127.0.0.1:<APP_PORT>/<HEALTH_PATH>sudo -iu <APP_USER> bash -lc '. "$HOME/.nvm/nvm.sh"; nvm use <APPROVED_NODE_24_VERSION> >/dev/null; pm2 save'승인한 관찰 시간 동안 restart count가 증가하지 않고 업무 smoke test가 성공한 뒤에만 실행합니다.online·health뿐 아니라 restart count가 증가하지 않고 오류율·dependency 부하가 회복돼야 합니다. backoff만으로 원인이 해결된 것은 아닙니다.
악화되면 백업 ecosystem과 이전 artifact를 복원해 startOrReload하고, Node version이 바뀌었다면 PM2 공식 절차에 따라 startup unit을 이전 절대 경로로 재생성합니다. DB migration·queue 처리는 별도 보정합니다.
PRIMARY REFERENCES
배포판과 버전에 따라 옵션·로그 위치가 다를 수 있습니다. 실행 전 서버의 --help와 로컬 매뉴얼을 함께 확인하세요.