크론(cron)으로 반복 작업 자동화하기 — 스케줄 표현식부터 실전까지

🌐 English

매일 아침 8시 50분에 봇을 켜고, 장 마감 후 리포트를 뽑고, 새벽에 로그를 정리합니다. 이걸 손으로 하면 언젠가 반드시 까먹습니다. 크론(cron)은 리눅스에서 "정해진 시각에 정해진 명령을 실행"해주는 기본 스케줄러입니다. 30년 넘게 쓰인 만큼 단순하고 확실합니다.

다만 처음 쓰면 거의 100% 안 돕니다. 그 이유가 이 글의 핵심입니다.

표현식 5필드

크론 스케줄은 공백으로 구분된 다섯 칸입니다.

┌───── 분   (0-59)

│ ┌─── 시   (0-23)

│ │ ┌─ 일   (1-31)

│ │ │ ┌───── 월     (1-12)

│ │ │ │ ┌─── 요일   (0-7, 0과 7은 일요일)

│ │ │ │ │

* * * * *  실행할 명령

기호는 네 개만 알면 됩니다.

  • * — 모든 값
  • , — 나열. 0,30 = 0분과 30분
  • - — 범위. 1-5 = 월~금
  • / — 간격. */10 = 10분마다

자주 쓰는 예시입니다.

0 9 * * 1-5      평일 오전 9시

50 8 * * 1-5     평일 오전 8시 50분 (장 시작 10분 전)

*/5 * * * *      5분마다

0 */2 * * *      2시간마다 정각

30 3 * * 0       일요일 새벽 3시 30분

0 0 1 * *        매월 1일 자정

헷갈리기 쉬운 지점 하나 — 일(day of month)과 요일(day of week)을 둘 다 지정하면 OR로 동작합니다. 0 9 1 * 1은 "1일이거나 월요일이면" 실행됩니다. AND가 아닙니다.

등록은 crontab -e로 편집기를 열고 한 줄씩 적으면 됩니다. crontab -l로 확인합니다.

초보가 반드시 밟는 함정 네 개

"크론에 등록했는데 아무 일도 안 일어나요"의 원인은 대부분 이 넷 중 하나입니다.

① PATH가 없다

크론은 당신의 셸 환경을 물려받지 않습니다. .bashrc도 안 읽고, PATH도 거의 비어 있습니다. 터미널에서 되던 python이 크론에서는 "명령을 찾을 수 없음"이 됩니다.

해법은 전부 절대경로로 쓰는 것입니다.

# 나쁨

0 9 * * 1-5 python bot.py

# 좋음 — 실행 파일도, 스크립트도 절대경로

0 9 * * 1-5 /opt/bot/.venv/bin/python /opt/bot/bot.py

가상환경을 쓴다면 activate를 거치지 말고 가상환경 안의 파이썬을 직접 지목하는 게 가장 확실합니다.

② 작업 디렉터리가 다르다

크론은 보통 홈 디렉터리에서 명령을 실행합니다. 코드 안에서 open("config.ini")처럼 상대경로를 쓰면 파일을 못 찾습니다.

# 실행 전에 디렉터리를 옮긴다

0 9 * * 1-5 cd /opt/bot && /opt/bot/.venv/bin/python bot.py

더 나은 방법은 코드 쪽에서 기준 경로를 잡는 것입니다.

from pathlib import Path

BASE = Path(__file__).resolve().parent   # 스크립트 자신의 위치 기준

config_path = BASE / "config.ini"

③ 출력이 어디에도 안 남는다

크론 작업의 출력은 기본적으로 메일로 가는데, 메일 설정이 없으면 그냥 사라집니다. 실패해도 흔적이 없어 원인을 못 찾습니다. 반드시 로그로 남기세요.

# 표준출력과 표준에러를 모두 파일에 append

0 9 * * 1-5 cd /opt/bot && ./run.sh >> /var/log/bot/cron.log 2>&1

2>&1에러 출력까지 같은 파일로 보내라는 뜻입니다. 이게 없으면 정작 보고 싶은 에러 메시지가 날아갑니다.

④ 타임존

서버가 UTC면 크론도 UTC로 돕니다. 0 9 * * *가 한국 시각 오후 6시에 실행됩니다. date 명령으로 서버 시각을 먼저 확인하고, 필요하면 crontab 상단에 명시하세요.

CRON_TZ=Asia/Seoul

0 9 * * 1-5 /opt/bot/.venv/bin/python /opt/bot/bot.py

중복 실행 방지 — flock

5분마다 도는 작업이 6분 걸리면 어떻게 될까요. 크론은 이전 실행이 끝났는지 확인하지 않습니다. 프로세스가 계속 쌓이다 서버가 뻗습니다. 주문을 넣는 스크립트라면 중복 주문이 나갑니다.

flock이 한 줄로 해결합니다.

# -n : 락을 못 잡으면 기다리지 말고 즉시 종료

*/5 * * * * /usr/bin/flock -n /tmp/report.lock /opt/bot/report.sh >> /var/log/bot/report.log 2>&1

이전 실행이 아직 돌고 있으면 이번 회차는 조용히 건너뜁니다. 반복 실행되는 크론 작업에는 웬만하면 다 붙이세요.

윈도우라면 — 작업 스케줄러

윈도우에는 크론이 없고 작업 스케줄러(Task Scheduler)가 그 역할을 합니다. GUI로도 되지만 명령으로 등록하는 게 재현 가능해서 좋습니다.

REM 평일 오전 8시 50분에 봇 기동

schtasks /create /tn "TradingBotStart" /tr "C:\bot\run.bat" /sc weekly /d MON,TUE,WED,THU,FRI /st 08:50

REM 등록 확인 / 즉시 테스트 실행

schtasks /query /tn "TradingBotStart"

schtasks /run   /tn "TradingBotStart"

윈도우에서 자주 막히는 지점 두 가지입니다. "사용자가 로그온한 경우에만 실행" 옵션이 켜져 있으면 재부팅 후 로그인 전까지 안 돕니다 — "사용자 로그온 여부와 상관없이 실행"으로 바꾸세요. 그리고 "시작 위치"를 지정하지 않으면 크론의 ②번 함정과 똑같이 상대경로가 깨집니다.

실전 조합 — 하루 스케줄

실제로 이런 식으로 묶어서 씁니다.

CRON_TZ=Asia/Seoul

# 08:50 장 시작 전 봇 기동 (평일)

50 8 * * 1-5 /usr/bin/flock -n /tmp/bot.lock /opt/bot/start.sh >> /var/log/bot/start.log 2>&1

# 15:40 장 마감 후 봇 정지 + 당일 리포트 텔레그램 발송

40 15 * * 1-5 /opt/bot/stop_and_report.sh >> /var/log/bot/report.log 2>&1

# 30분마다 생존 확인 — 죽어 있으면 알림

*/30 * * * * /usr/bin/flock -n /tmp/hc.lock /opt/bot/healthcheck.sh >> /var/log/bot/hc.log 2>&1

# 매일 새벽 3시 30일 지난 로그 삭제

0 3 * * * find /var/log/bot -name "*.log" -mtime +30 -delete

마지막 줄을 빠뜨리지 마세요. 로그 정리를 안 하면 몇 달 뒤 디스크가 가득 차서 봇이 죽습니다. 실제로 흔한 사고입니다.

크론이 맞지 않는 경우

크론은 분 단위가 최소 단위입니다. 그리고 매 실행마다 프로세스가 새로 뜹니다. 그래서 이런 건 크론으로 하면 안 됩니다.

  • 초 단위 반복 — 봇 안에서 루프나 타이머로 처리
  • 상태를 유지해야 하는 작업 — 매번 새 프로세스라 메모리 상태가 사라집니다
  • 죽으면 즉시 재시작 — 이건 크론이 아니라 systemd나 Docker의 restart 정책의 영역입니다

경계선은 이렇게 잡으면 됩니다. "정해진 시각에 한 번 하는 일"은 크론, "계속 돌아야 하는 일"은 프로세스 관리자.

정리

  • 표현식은 분·시·일·월·요일 다섯 칸, 일과 요일을 같이 쓰면 OR
  • 크론은 셸 환경을 안 물려받는다 → 모든 경로를 절대경로로
  • 작업 디렉터리가 다르다 → cd 하거나 코드에서 __file__ 기준 경로 사용
  • 출력은 사라진다 → >> 로그 2>&1 필수
  • 서버 타임존 확인, 필요하면 CRON_TZ 명시
  • 반복 작업에는 flock -n으로 중복 실행 차단
  • 윈도우는 schtasks, 로그온 여부 무관 실행 + 시작 위치 설정 주의
  • 로그 정리 작업을 반드시 하나 넣는다 — 디스크가 봇을 죽인다

크론은 배우는 데 20분, 함정에 걸리는 데 2시간이 걸리는 도구입니다. 위 네 가지 함정만 먼저 알고 시작하면 그 2시간을 건너뛸 수 있습니다.

댓글

이 블로그의 인기 게시물

한국투자증권 KIS API로 실시간 시세 받기 (WebSocket 실전)

파이썬으로 업비트 API 연동하기 — 시세 조회부터 주문까지 기초

Go로 자동매매 신호봇 프레임워크 설계하기