블로그 자동화 파이프라인을 통째로 갈아엎은 새벽
목차
왜 바꿨나 — "커밋마다 글 하나"의 한계
처음 설계는 단순했다. 커밋이 올라오면 → 그 커밋을 보고 → 글 한 편 뚝딱. 얼핏 깔끔해 보이지만 실제로 돌려보니 문제가 바로 드러났다. 새벽 1~2시처럼 집중 작업하는 타임에 커밋이 10개, 20개씩 쏟아지면 글도 10개, 20개가 된다. 품질은 둘째치고 블로그가 스팸처럼 도배된다. 독자 입장에서 "이 사람 한 시간에 뭘 20개 올리는 거야?" 싶을 거고, SEO 관점에서도 얇은 글 여러 편보다 맥락이 있는 글 한 편이 훨씬 낫다.
거기다 또 다른 문제 — 하루를 마무리하는 호흡이 없었다. 기술 커밋 단위로는 "오늘 어땠나"를 담기가 구조적으로 불가능하다. 그래서 이번에 파이프라인을 두 레이어로 분리하기로 했다.
새 구조 — 두 개의 리듬
| 트리거 | 범위 | 출력물 |
|---|---|---|
| 매시간 cron | 직전 1시간 커밋 묶음 | 종합 회고 글 1편 |
| 자정 cron | 오늘 하루 전체 | 오늘의 회고 일기 1편 |
핵심은 집계 단위다. 커밋 하나하나를 이벤트로 보지 않고, 시간 또는 날짜를 슬라이딩 윈도우로 잡아서 그 안에 쌓인 커밋들을 한 번에 처리한다. 커밋이 0개면 글도 안 쓴다. 커밋이 30개면? 그 30개를 관통하는 주제 1~2개로 압축해서 글 하나로 만든다.
작업 순서와 각 파일의 역할
CLAUDE.md부터 손댔다. 이게 봇 동작의 단일진실이라 새 파이프라인의 규칙 — "커밋당 발행 금지", "시간 단위 집계", "일기 발행 조건" — 을 여기에 먼저 박아두지 않으면 스크립트가 바뀌어도 봇이 엉뚱하게 행동할 수 있다. 지침이 코드보다 먼저다.
그 다음 scripts/bulk_seed.py. 기존에 커밋 하나씩 처리하던 루프를 시간 범위 기반 쿼리로 바꿨다. 직전 1시간치 커밋을 긁어서 배열로 넘기면, 그걸 받아서 하나의 프롬프트 컨텍스트로 조립한 뒤 Claude한테 종합글 작성을 요청하는 구조다. 일기 모드는 별도 플래그로 분기 — 하루치 커밋 전체를 받아서 좀 더 서사적인 톤으로 프롬프트를 바꾼다.
마지막으로 scripts/run_scheduled.sh. cron에서 직접 물리는 진입점이다. 인자 없이 실행하면 "지금 몇 시?"를 보고 자정이면 일기 모드, 아니면 시간 집계 모드로 bulk_seed.py를 호출한다. 환경변수 세팅, 로그 경로, 실패 시 슬랙 알림 훅도 여기서 처리한다.
# run_scheduled.sh 핵심 분기 (의사코드)
HOUR=$(date +%H)
if [ "$HOUR" = "00" ]; then
python bulk_seed.py --mode diary --since "today"
else
python bulk_seed.py --mode hourly --since "1h"
fi
실제로 느낀 것들
설계 자체는 단순한데, 막상 구현하면서 신경 쓸 게 생각보다 많았다. 특히 경계 시간대 — 자정 직전 커밋이 시간 집계에 들어갔다가 일기에도 중복으로 들어가는 상황. 윈도우 기준을 UTC로 통일하고 일기는 "오늘 00:00~23:59" 범위를 명시적으로 받도록 해서 덮어썼다.
또 하나는 빈 시간대 처리. 아무 커밋도 없는 시간에 cron이 돌면 예전엔 그냥 에러 없이 빈 글이 발행됐다. 이번엔 커밋 수 체크를 앞단에서 하고, 0개면 조용히 종료하도록 바꿨다. 블로그에 "이 시간에 한 일: 없음" 같은 글이 올라오는 건 어떤 이유로도 용납이 안 된다.
새벽 1시에 이 작업을 한 건 이유가 있다. 낮에는 커밋이 튀어나오는 타이밍을 제어하기 어렵고, 파이프라인을 교체하는 중에 기존 훅이 동시에 돌면 중복 발행 사고가 날 수 있다. 트래픽이 가장 적은 새벽에 조용히 갈아끼운 다음, 당장 이 커밋 자체가 새 파이프라인의 첫 입력이 되는 구조로 자연스럽게 이어지도록 했다. 새 시스템이 제 첫 글감으로 자기 자신의 탄생을 쓰는 셈이다.
🛒 이 글과 어울리는 추천 상품
*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.
댓글 0
첫 댓글 달아줘.