← 전체 글로 돌아가기

웹 개발

systemd 서비스가 재시작만 반복할 때 확인한 종료 신호 처리

프로세스가 실행 직후 재시작되던 VPS에서 상태와 애플리케이션 종료 처리를 확인한 기록입니다

재시작 횟수만 늘어나는 서비스

Node 서버를 systemd로 올린 뒤 배포 직후 auto-restart가 반복됐습니다. 브라우저에서는 502만 보였고 상태 요약만 보면 포트 문제로 오해하기 쉬웠습니다. 로그를 시간순으로 맞춰 보니 SIGTERM 뒤 HTTP 서버가 연결을 정리하지 못하고 있었습니다.

journalctl에서 원인을 분리하기

sudo systemctl status myapp.service --no-pager
sudo journalctl -u myapp.service -n 100 --no-pager
sudo systemctl show myapp.service -p Result -p ExecMainStatus -p MainPID

상태는 요약이고 journalctl은 원인에 가깝습니다. 배포 시각, 기존 프로세스 종료 시각, 새 PID가 생긴 시각을 함께 기록하니 문제가 선명해졌습니다.

서비스 파일보다 먼저 앱을 고치기

종료 정책을 바꿔 증상을 숨기지 않고 애플리케이션이 새 요청을 받지 않은 뒤 기존 요청을 마치도록 했습니다.

const server = app.listen(process.env.PORT || 3000);
process.once('SIGTERM', () => {
  server.close(() => process.exit(0));
  setTimeout(() => process.exit(1), 10000).unref();
});

서비스에는 실행 사용자와 작업 디렉터리도 명시했습니다.

[Service]
User=myapp
WorkingDirectory=/srv/myapp
ExecStart=/usr/bin/node /srv/myapp/server.js
Restart=on-failure
RestartSec=5

배포 전 종료 테스트

로그를 보면서 서비스를 재기동하고 정상 종료 한 번 뒤 새 PID가 생기는지 확인했습니다. 10초 이상 걸리는 요청이 있을 때 강제 종료되는지도 시험했습니다. 무조건 재시작하지 않고 실패할 때만 재시작하도록 한 것이 기준입니다.

체크리스트

  • ExecStart 절대 경로가 실제 런타임과 같은가
  • SIGTERM 시 새 연결을 받지 않는가
  • 종료 대기 시간이 무한하지 않은가
  • 종료 원인이 journal에 남는가

이제 서비스가 살아 있는지만 보지 않고 재시작 이유와 종료 코드까지 확인합니다.