
시스템 구축 배경 및 목적
최근 개발 및 시스템 관리 환경에서 AI 코딩 어시스턴트인 Claude Code를 활용한 백그라운드 자동화 작업이 크게 증가하고 있습니다.
이러한 자동화 프로세스는 효율성을 극대화하지만, 관리자가 콘솔을 직접 확인하지 않는 이상 작업의 진행 상태나 예기치 않은 오류 발생 여부를 즉각적으로 파악하기 어렵다는 단점이 있습니다.
특히 장시간 소요되는 데이터 처리 로직이나 스크립트 실행이 완료되었을 때, 혹은 치명적인 오류로 인해 프로세스가 중단되었을 때 즉각적인 대응 시스템이 필수적입니다.
이를 해결하기 위해 널리 사용되는 모바일 메신저인 Telegram API를 활용하여 양방향 알림 시스템을 설계하게 되었습니다.
본 프로젝트의 핵심은 Python을 기반으로 브릿지 데몬(Bridge Daemon)을 구성하고, 정지 훅(Stop Hooks) 메커니즘을 통해 프로세스 이벤트를 감지하여 Telegram 메신저와 통신하는 환경을 구축하는 것입니다.
초기 설계 및 접근 방식
시스템 초기 설계 단계에서는 비교적 단순한 단방향 로직을 구상했습니다.
Claude Code의 실행 로그 및 표준 출력(Standard Output)을 특정 텍스트 파일(log.txt)로 지속적으로 기록하게 한 뒤, 별도의 Python 스크립트가 해당 로그 파일을 주기적으로 읽어들이는 폴링(Polling) 방식을 채택했습니다.
Telegram Bot API Token을 발급받아 requests 라이브러리를 통해 새로운 로그 라인이 추가될 때마다 지정된 Chat ID로 메시지를 발송하는 구조였습니다.
더 나아가 사용자가 외부에서 Telegram 봇 대화창에 특정 명령어를 입력하면, 서버가 이를 수신하여 대기 중인 프로세스에 새로운 매개변수를 전달하는 기초적인 양방향 통신을 기획했습니다.
개발 과정에서 발생한 주요 오류 및 실수
1. 파일 폴링(Polling) 방식의 한계와 리소스 누수
첫 번째로 직면한 문제는 비효율적인 파일 동기화 방식으로 인한 서버 리소스 낭비였습니다.
실시간 알림을 구현하기 위해 Python 스크립트에 while True 루프와 time.sleep(1)을 적용하여 1초 단위로 로그 파일을 읽어들이도록 설계했습니다.
그 결과, 끊임없이 발생하는 디스크 I/O 작업으로 인해 서버의 CPU 점유율이 비정상적으로 상승하는 현상이 발생했습니다.
또한, 프로세스가 로그를 기록하는 시점과 스크립트가 파일을 읽어들이는 시점 사이에 미세한 타이밍 충돌(Race Condition)이 발생하여, 동일한 로그 메시지가 중복으로 전송되거나 일부 중요 에러 로그가 누락되는 심각한 동기화 오류가 빈번하게 나타났습니다.
2. 정지 훅(Stop Hooks) 처리 로직 부재 및 좀비 프로세스 발생
두 번째 치명적인 실수는 프로세스의 생명 주기를 관리하는 정지 훅 로직의 누락이었습니다.
백그라운드에서 실행되는 Claude Code 프로세스가 정상적으로 모든 작업을 마치고 종료되는 상황과, 메모리 부족(OOM)이나 문법 오류 등으로 인해 비정상적으로 강제 종료(Crash)되는 상황을 시스템이 전혀 구분하지 못했습니다.
그 결과, 치명적인 오류로 프로세스가 이미 죽었음에도 불구하고 데몬 스크립트는 이를 인지하지 못한 채 계속해서 로그 파일을 감시하는 무의미한 대기 상태(Zombie 상태)에 빠졌습니다.
반대로 프로세스가 아직 실행 중임에도 불구하고 일시적인 지연을 ‘작업 완료’로 오인하여 잘못된 알림을 전송하는 논리적 결함도 발견되었습니다.
프로세스의 상태 코드(Exit Code)를 명확하게 반환받아 예외 처리를 진행하는 구문을 설계 단계에서 간과한 것이 원인이었습니다.
3. Telegram API 네트워크 타임아웃 및 데몬 크래시
세 번째 문제는 외부 API 통신 과정에서 발생한 네트워크 예외 처리 부족입니다.
사용자의 명령을 수신하기 위해 Telegram 서버와 지속적인 연결(Long Polling)을 유지해야 했는데, 서버의 네트워크 상태가 불안정해지거나 Telegram API 서버의 응답이 지연될 경우 스크립트에서 ReadTimeout 또는 ConnectionError가 발생했습니다.
단순한 스크립트 실행 시에는 오류 메시지 출력 후 재실행하면 그만이지만, 백그라운드 서비스(Daemon)로 동작하는 환경에서는 이러한 단 한 번의 네트워크 예외가 전체 데몬 스크립트를 완전히 다운시키는 결과를 초래했습니다.
외부 API 연동 시 필수적으로 구현해야 할 타임아웃 방어 로직과 재접속 알고리즘을 기본값으로 방치한 명백한 설계 오류였습니다.
문제 해결 및 최종 시스템 구현 로직
1. 비동기 서브프로세스(Subprocess) 통신 도입
가장 먼저 디스크 I/O를 유발하던 비효율적인 로그 파일 폴링 방식을 폐기했습니다.
대신 Python의 내장 라이브러리인 subprocess 모듈을 심도 있게 활용하여, 브릿지 데몬이 Claude Code를 직접 하위 프로세스로 실행하고 제어하는 이벤트 기반(Event-driven) 아키텍처로 전환했습니다.
subprocess.Popen을 사용하여 stdout과 stderr를 파이프(PIPE)로 연결하고, 메인 메모리 상에서 실시간 스트리밍으로 데이터를 읽어들이는 방식을 채택했습니다.
이를 통해 물리적인 파일 입출력이 완전히 제거되었으며, CPU 점유율을 획기적으로 낮추고 메시지 전송의 딜레이를 0.1초 미만으로 단축할 수 있었습니다.
2. 명시적인 정지 훅(Stop Hooks) 및 에러 트레이스백 캡처
프로세스 생명 주기 관리 문제를 해결하기 위해, 하위 프로세스의 반환 코드(Return Code)를 지속적으로 모니터링하는 로직을 추가했습니다.
process.poll() 메서드를 활용하여 종료 코드가 0일 경우에는 정상 완료 메시지를 전송하고, 0이 아닌 다른 값이 반환될 경우에는 비정상 종료로 분류하여 즉각적인 경고 알림을 발생시키도록 분기 처리했습니다.
특히 프로세스가 비정상 종료될 때 파이프에 마지막으로 남아있는 stderr 데이터(에러 트레이스백)를 캡처하여 Telegram 메시지 본문에 그대로 포함시켰습니다.
이로 인해 관리자는 PC를 켜지 않고도 모바일 환경에서 즉각적으로 어떤 코드 라인에서 오류가 발생했는지 원인을 파악할 수 있게 되었습니다.
3. 예외 처리 강화 및 시스템 레벨의 무결성 확보
네트워크 타임아웃으로 인한 데몬 크래시를 방지하기 위해 Telegram API 통신 블록 전체를 견고한 try-except 구문으로 감쌌습니다.
네트워크 단절 오류가 감지되면 스크립트가 종료되는 대신, 점진적 백오프(Exponential Backoff) 알고리즘을 적용하여 5초, 10초, 20초 단위로 대기 시간을 늘려가며 재접속을 시도하도록 자가 복구(Self-healing) 로직을 구현했습니다.
마지막으로 이 완성된 Python 스크립트를 Linux 운영체제의 systemd 서비스로 정식 등록했습니다.
서비스 설정 파일에 Restart=always 옵션을 부여하여, 메모리 부족 등 OS 차원의 예기치 않은 문제로 브릿지 데몬이 죽더라도 시스템이 즉각적으로 스크립트를 자동 재시작하도록 조치하여 서비스의 무중단 운영을 보장했습니다.
적용 결과 및 시스템 확장성
이러한 일련의 트러블슈팅과 최적화 과정을 거쳐, 현재는 완벽하게 동작하는 안정적인 양방향 Telegram 알림 데몬 시스템을 완성했습니다.
복잡한 시스템 운영 환경에서 발생할 수 있는 파일 I/O 병목, 백그라운드 프로세스 관리 실패, 외부 API 통신 오류라는 3대 주요 장애 요인을 직접 겪고 해결함으로써 서비스 안정성의 중요성을 다시 한번 확인했습니다.
현재 구현된 정지 훅 처리 로직과 비동기 파이프라인 관리 방식은 단순히 Claude Code뿐만 아니라 향후 추가될 데이터 크롤링 봇이나 대규모 데이터베이스 백업 스크립트 등 어떠한 백그라운드 작업에도 모듈 형태로 즉시 이식할 수 있는 높은 범용성을 확보했다는 점에서 큰 의미가 있습니다.