워치독 패턴 — 봇이 죽었을 때 스스로 살아나게 만들기 > 매매 기술 노트
본문 바로가기
코인랩 코인랩 업비트 자동매매 리서치 & 기술노트
사이트 내 전체검색

매매 기술 노트

시스템설계 워치독 패턴 — 봇이 죽었을 때 스스로 살아나게 만들기

게시물 옵션

본문

매매 기술 노트 · 19 · 시스템설계

워치독 패턴 — 봇이 죽었을 때 스스로 살아나게 만들기

자동매매 봇을 오래 돌리다 보면 결국 한 번은 죽는다. 거래소 API가 갑자기 타임아웃을 던지거나, 네트워크가 잠깐 끊기거나, 예외 처리를 못 한 엣지 케이스에 걸려서 프로세스가 그대로 멈춰버리는 식이다. 문제는 봇이 멈췄다는 걸 사람이 알아채는 시점이다. 포지션을 들고 있는 상태에서 몇 시간씩 방치되면, 그 사이 시장은 계속 움직인다. 워치독(Watchdog) 패턴은 이런 상황을 막기 위해 "봇을 감시하는 별도의 감시자"를 두는 설계 방식이다.

워치독
메인 프로세스의 생존 여부를 주기적으로 확인하는 독립된 감시 프로세스
하트비트
메인 봇이 "나 살아있다"고 주기적으로 남기는 신호(타임스탬프, 로그, DB 갱신 등)
자동복구
하트비트가 끊긴 걸 감지하면 프로세스를 재시작하거나 안전 모드로 전환하는 동작

왜 try-except만으로는 부족한가

예외 처리를 아무리 촘촘히 넣어도 예상 못 한 실패 지점은 항상 남는다. 프로세스 자체가 OS 레벨에서 죽는 경우(OOM킬, 세그폴트급 라이브러리 버그), 무한 대기에 빠져서 죽지도 살지도 않은 상태가 되는 경우는 코드 내부의 예외 처리로 못 잡는다. 그래서 감시는 프로세스 밖에서, 별도의 프로세스나 스케줄러가 해야 한다. 이게 워치독이 봇 코드와 물리적으로 분리돼 있어야 하는 이유다.

메인 봇 프로세스 워치독 하트비트 (30초마다) 신호 끊김 → 재시작 트리거

실제로 겪은 케이스

코인랩 봇을 처음 무인 운영으로 돌렸을 때, systemd로만 관리하면 충분할 줄 알았다. "프로세스 죽으면 자동으로 다시 뜨겠지"라는 생각으로 별다른 감시 장치 없이 몇 주를 그냥 돌렸다. 그런데 어느 날 아침, 전날 저녁부터 새벽까지 거래 내역이 하나도 없다는 걸 대시보드를 확인하다가 우연히 발견했다. 프로세스 목록을 보니 봇은 멀쩡히 떠 있었고, CPU도 정상적으로 돌아가고 있었다. systemd 입장에서는 아무 문제 없는 "정상 동작 중" 상태였던 거다.

로그를 뒤져보니 원인은 거래소 API 쪽에 있었다. 특정 시간대부터 API가 에러를 던지는 게 아니라, 응답 코드는 200을 반환하면서 본문은 텅 빈 값을 계속 돌려주고 있었다. 코드에서는 이 경우를 "일시적 오류"로 분류해서 재시도 로직으로 넘겼는데, 하필 재시도 간격과 재시도 횟수 설정이 맞물려서 사실상 무한 대기에 가까운 루프에 빠져버린 상태였다. 예외가 터진 것도 아니고 프로세스가 죽은 것도 아니니, 겉보기엔 멀쩡한데 실제로는 아무 일도 안 하고 있는 좀비 상태가 몇 시간이나 이어진 셈이다. 그날 시장이 크게 움직이지 않았던 게 그나마 다행이었지, 만약 그 구간에 급등이나 급락이 났으면 대응을 아예 못 했을 상황이었다.

이 사건 이후로 단순히 "프로세스가 살아있는가"가 아니라 "마지막으로 정상 로직을 수행하고 실제로 유의미한 작업(시세 조회, 신호 계산, 주문 판단)을 끝낸 시각"을 별도로 기록하는 방식으로 바꿨다. 이 시각을 파일이나 DB에 타임스탬프로 남기고, 워치독 프로세스가 별도 주기로 이 값을 확인해서 일정 시간 이상 갱신되지 않으면 무조건 강제 종료 후 재시작하도록 만들었다. 재시작 이후에는 곧바로 새 주문을 내는 대신 거래소에서 현재 포지션과 미체결 주문을 다시 조회해 내부 상태를 맞추는 단계를 먼저 거치게 했다. 이렇게 바꾸고 나서는 비슷한 좀비 상태가 몇 번 더 발생했지만, 이번엔 워치독이 알아서 감지하고 복구까지 처리해서 사람이 개입할 필요가 없었다.

실전 팁

재시작 시 바로 새 주문을 내지 않고, 먼저 거래소에서 현재 포지션·미체결 주문 상태를 다시 조회해서 내부 상태와 동기화하는 단계를 거치는 게 중요하다. 재시작 직전 상태를 그대로 신뢰하면 중복 주문이나 포지션 인식 오류로 이어질 수 있다.

흔한 오해

"프로세스 매니저(systemd, pm2, supervisor)가 죽으면 알아서 재시작해주니 워치독은 필요 없다"는 생각은 절반만 맞다. 이런 도구들은 프로세스가 완전히 종료됐을 때만 감지한다. 위 사례처럼 프로세스는 살아있는데 로직만 멈춘 좀비 상태는 잡아내지 못한다.

last_heartbeat = now() def main_loop(): global last_heartbeat while True: run_trading_logic() last_heartbeat = now() # 정상 동작마다 갱신 sleep(interval) def watchdog(): while True: if now() - last_heartbeat > TIMEOUT: restart_process() resync_positions_with_exchange() sleep(check_interval)

이 글은 매매 시스템 설계 과정에서의 개인적인 경험과 학습을 기록한 것으로, 특정 종목·전략에 대한 투자 권유가 아닙니다. 실제 수익을 보장하지 않으며, 투자 판단과 책임은 본인에게 있습니다.

추천0 비추천0
스크랩 · 신고

댓글목록

등록된 댓글이 없습니다.

매매 기술 노트 • OFFICIAL

매매 기술 노트

RSI·볼린저밴드·이동평균선·MACD·거래량 지표 정리와 적용 경험
22TOTAL
22POSTS

매매 기술 노트

22건
매매 기술 노트 목록
번호 제목 글쓴이 날짜 조회
22
<
코인랩
09-10 41
21
<
코인랩
08-08 709
20
<
코인랩
09-01 56
열람중
<
코인랩
08-27 145
18
<
코인랩
08-22 216
17
<
코인랩
08-19 209
16
<
코인랩
08-18 404
15
<
코인랩
08-17 219
14
<
코인랩
08-14 270
13
<
코인랩
08-13 307
12
<
코인랩
08-10 240
11
<
코인랩
08-09 228
10
<
코인랩
08-09 256
9
<
코인랩
08-07 290
8
<
코인랩
08-07 278
WELCOME
ID/PW 찾기
회원가입
오늘의 마켓
업비트 원화마켓 기준 · 5분 갱신
상승 210하락 57
24H 거래대금 15,948억
거래대금 TOP
JPYC-4.80%
XRP+0.67%
FOLD-7.84%
ETH+0.62%
BTC+0.61%
NEAR+8.16%
LSK-3.76%
PYUSD-0.29%