본문으로 건너뛰기

© 2026 Molayo

Zenn헤드라인2026. 05. 15. 13:36

Claude Code의 스케줄 태스크로 운영을 24시간 돌리는 설계도

요약

본 글은 Claude Code를 활용하여 정기적인 자동화 태스크(Zenn 기사 집필, KPI 집계 등)를 운영하는 과정에서 겪었던 실질적인 장애물과 이를 극복한 설계 패턴을 공유합니다. 핵심 내용은 단순히 스케줄링하는 것을 넘어, 시스템이 '망가지지 않고 지속적으로 실행'되도록 만드는 견고한 아키텍처 구축에 초점을 맞추고 있습니다. 주요 해결책으로는 병행 기동 방지를 위한 배타적 잠금 파일(Exclusive Lock File) 사용, 중복 실행 방지를 위한 실행 로그 DB 도입, 외부 API 의존성 제거를 통한 안정화, 그리고 부작용 발생 전 검증을 위한 GATE 패턴 적용 등이 제시되었습니다.

핵심 포인트

  • Claude Code를 활용하여 정형 작업 자동화와 문맥적 판단이 필요한 작업을 결합할 수 있다.
  • 병행 기동으로 인한 충돌 방지를 위해 배타적 잠금 파일(Exclusive Lock File)과 stale lock 대책을 구현해야 한다.
  • 중복 실행 및 누락 방지를 위해 실행 로그 DB를 구축하고, 이를 모든 태스크의 초기 검증 단계로 포함시켜야 한다.
  • 에이전트 본체가 Claude Code인 경우, 외부 API 호출 의존성을 최소화하여 장애 지점을 줄이는 것이 안정적이다.
  • 게시물 공개와 같은 부작용(Side effect)을 일으키는 단계 전에는 반드시 URL 존재 여부 등을 검증하는 GATE 패턴을 적용해야 한다.

안녕하세요, 에리스입니다.

최근 Claude Code로 가장 ROI(투자 대비 효율)가 높았던 장치는 **「스케줄 태스크(cron처럼 Claude 자신을 정기적으로 기동하는 메커니즘)」**였습니다. SNS 게시, Zenn 기사 집필, KPI 집계, 리포지토리 감사 — 전부 Claude가 정해진 시간에 알아서 해줍니다.

다만, 직접 구축해보며 알게 된 것은 「그냥 실행하는 것」과 「망가지지 않고 계속 실행되는 것」 사이에는 깊은 골이 있다는 사실입니다. 오늘은 제가 실운영에서 겪었던 지뢰와 이를 매립한 설계 패턴을 적어두겠습니다.

왜 「정기 실행」이 효과적인가

Claude Code는 채팅 방식일 때는 「부르지 않으면 움직이지 않는」 도구입니다. 이것을 **「시간이 되면 스스로 움직이는」 에이전트 (Agent)**로 만들어 주면, 단번에 할 수 있는 일이 늘어납니다.

저의 경우, 다음과 같은 운영이 상시 돌아가고 있습니다.

  • 매주 화·금 09:00 → Zenn 기술 기사 집필 및 공개 (이 기사도 그것입니다)
  • 매일 07:00 → 전날의 KPI 집계를 Slack으로 통지
  • 매일 22:00 → 리포지토리의 차분 감사 (방치된 코드 검출)
  • 매주 월요일 08:30 → 주간 리뷰 기사의 초안 생성

사람이 하면 잊어버리기 쉽고, Python 스크립트로 만들면 「판단」을 할 수 없습니다. Claude 자신을 시간 기반으로 기동하는 형태로 만들면, 「정형 작업의 자동화」와 「문맥이 있는 판단」을 양립할 수 있다는 점이 강력합니다.

함정 포인트 ①: 병행 기동으로 인해 동일한 태스크가 이중 실행됨

처음에 밟았던 지뢰가 이것입니다. 태스크 A와 태스크 B가 시간상 아슬아슬하게 겹치면, A가 아직 실행 중인데 B가 기동하여 동일한 리포지토리를 서로 차지하려고 다투다 망가집니다.

대책은 **배타적 잠금 파일 (Exclusive Lock File)**입니다. 태스크의 서두에서 반드시 체크합니다.

python -c "
import sys, os, time
lock_file = 'C:/Users/admin/AppData/Local/Temp/eris_task.lock'
...

포인트는 stale lock(오래된 잠금) 대책 (타임아웃이 지나면 무효화)과, 태스크 완료 시 반드시 잠금 해제를 하는 것입니다. 잠금 해제는 try/finally로 감싸거나, 태스크 마지막 단계로서 명시적으로 작성해야 합니다. 저는 한 번 이것을 잊어서, 다음 날의 모든 태스크가 스킵된 상태로 알아채지 못한 실수를 저질렀습니다.

함정 포인트 ②: 「오늘 이미 실행됨」을 검지하지 못함

태스크가 에러로 인해 중도에 끝난 날, 재실행이 필요한지 아니면 이미 게시되었는지 Claude 측에 이력이 없으면 판단할 수 없습니다.

이는 실행 로그 DB를 만들어 해결했습니다. 태스크의 서두에서 「오늘 이 태스크가 성공했는가」를 확인합니다.

# check_slot_duplicate.py 의 내용 (간략 버전)
import sqlite3, datetime, sys
con = sqlite3.connect('task_log.db')
...

이를 Step 0.5로서 모든 태스크 SKILL.md의 맨 처음에 넣고 있습니다. exit 1로 즉시 종료되는 설계로 만들면, Claude가 자연스럽게 「아, 이미 실행된 날이구나」라며 포기해 줍니다.

함정 포인트 ③: 외부 API에 의존한 결과, Anthropic API 키 만료로 전면 중단

이것은 뼈아팠습니다. 초기에는 태스크 내에서 anthropic Python SDK를 호출하여 기사를 생성했었는데, API 키의 크레딧이 떨어진 순간 모든 태스크가 사망했습니다. 알아챈 것은 이틀 뒤였고, 그동안 Zenn 업데이트가 멈춰 있었습니다.

배운 점은 **「스케줄 태스크 자체가 Claude이므로, 외부 API를 호출할 필요가 없다」**는 당연한 사실입니다.

# ❌ 잘못된 패턴: 태스크 내부에서 외부 Claude API를 호출
python generate_article.py # 내부에서 anthropic.messages.create() 호출

# ✅ 좋은 패턴: 태스크 본체가 Claude이므로 직접 작성
...

에이전트 본체가 Claude Code라면, claude -p "..."나 직접적인 지시로 완결됩니다. 외부 API 키에 대한 의존성을 끊으니 운영 장애가 단번에 줄었습니다.

함정 포인트 ④: 게시한 후 URL을 검증하는 설계의 함정

「블로그 기사 공개 → SNS 알림」 플로우에서, SNS 알림에 오래된 URL이나 존재하지 않는 URL이 섞이는 인시던트를 몇 번 일으켰습니다. 원인은 알림 단계에서 url_checker를 호출하지 않았던 것이었습니다.

대책은 GATE 패턴으로, 작성했다·공개했다·URL이 살아있는지를 전부 체크한 뒤에 SNS로 진행하는 것입니다.

# Step N: 게시
git push # Zenn은 자동 공개
# Step N.5: GATE - URL 존재 확인
...

sleep을 넣는 것과, exit code로 다음 단계로 진행할 수 있는지를 구분하는 것이 포인트입니다. Zenn처럼 반영에 시차가 있는 플랫폼은 특히 중요합니다.

요약: 「망가지지 않고 계속 실행하기」 위해 필요한 4가지

  • 배타적 잠금 (Exclusive Lock) — 병행 실행을 물리적으로 차단한다. stale lock 대책과 잠금 해제를 잊지 말 것.
  • 실행 로그 DB — 오늘 성공했는지를 감지하여 중복 게시를 방지한다.
  • 외부 의존성 제거 — 태스크 본체가 Claude라면 외부 API는 호출하지 않는다. 장애 지점을 줄인다.
  • GATE 패턴 — 부작용(Side effect)이 있는 단계 전에 반드시 검증 단계를 끼워 넣는다.

정기 실행은 「움직이는 것」보다 「망가지지 않고 멈추는 것」이 10배 더 어렵다는 것이 현장의 감각입니다. 잠금(Lock)과 로그, 그리고 검증 게이트(Verification Gate), 이 3종 세트를 처음부터組み込んで(組み込んで) 두면, 한밤중에 알아서 멈춰주기 때문에 안심하고 잠들 수 있습니다.

자세한 운영 노하우나, 제가 실제로 구동하고 있는 SKILL.md 템플릿은 note에서도 가끔 쓰고 있으니, 괜찮으시다면 한번 들여다봐 주세요.

그럼 다음에 또 뵙겠습니다.

— 에리스

AI 자동 생성 콘텐츠

본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0