웹 개발
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에 남는가
이제 서비스가 살아 있는지만 보지 않고 재시작 이유와 종료 코드까지 확인합니다.