나의 Claude 스택에서 크론 잡(Cron Jobs)으로 실행하는 6가지 자동화
요약
Claude를 활용하여 퍼블리싱 파이프라인을 자동화하는 6가지 크론 잡(Cron Jobs) 구축 사례를 소개합니다. 저렴한 서버 비용으로 콘텐츠 검증, 자동 배포, 인덱스 재구축 및 링크 관리 등을 자동화하는 실무적인 워크플로우를 다룹니다.
핵심 포인트
- Claude를 활용한 콘텐츠 품질 검증 및 자동 발행
- 크론 잡 간의 실행 순서 설계의 중요성
- 로그 기록을 통한 시스템 신뢰성 확보
- 저비용 서버를 활용한 효율적인 자동화 스택 구축
-
월 2유로(EUR) 서버에서 내 스튜디오의 퍼블리싱 파이프라인을 실행하는 6개의 크론 잡 (cron jobs)
-
매일 09:00에 4개 채널로 게시물을 자동 배포 (Auto-syndicate)
-
링크를 최신 상태로 유지하기 위해 6시간마다 실행되는 블로그 인덱스 재구축 (Blog-index rebuild)
-
독자들이 발견하기 전에 깨진 링크를 잡아내는 가든 워크 (Garden-walk) 작업
내 스튜디오는 매일 게시물을 발행하지만, 나는 그 과정의 대부분을 건드리지 않습니다. 월 2유로(EUR) 비용이 드는 서버에서 6개의 크론 잡 (cron jobs)이 전체 파이프라인을 실행합니다. 여기 실제 테이블과 각 작업의 역할, 그리고 이를 구축하며 제가 저지른 실수들을 소개합니다.
모든 것을 시작한 퍼블리시(Publish) 작업
제가 처음 작성한 크론 잡 (cron job)은 자동 발행 (auto-publish) 단계였습니다. 이 작업은 매일 아침 08:30에 실행됩니다. 대기열 (queue) 폴더에서 다음 기사를 가져와, 저의 규칙(글자 수, 금지 문구, 최소 링크 수)에 따라 검증(validate)한 뒤, 통과하면 라이브로 게시합니다.
검증 (validation)이 가장 중요한 부분입니다. 이 작업을 도입하기 전에는 엠 대시(em dashes) 세 개와 깨진 내부 링크가 포함된 포스트를 발행한 적이 있습니다. 이틀 동안 아무도 저에게 말해주지 않았죠. 이제 이 작업은 검증에 실패한 것은 무엇도 발행하지 않으며, 실패 원인을 로그 (log)에 기록합니다. 저는 커피를 마시며 이 로그를 읽습니다. 지난 4개월 동안 이 작업은 11개의 포스트를 차단했습니다. 각각의 포스트는 그대로 발행되었다면 작은 공개적 망신이 되었을 것입니다.
작업 자체는 짧습니다. 최종 검토를 수행하는 Claude 호출 (call)을 감싸고 있는 쉘 스크립트 (shell script)이며, 여기에 몇 가지 엄격한 규칙을 위한 grep 체크가 포함되어 있습니다. grep 체크는 단순하고 빠릅니다. Claude를 통한 읽기는 더 느리지만, 제목과 모순되는 문단이나 너무 절박하게 들리는 CTA (Call to Action)와 같이 grep이 잡아낼 수 없는 것들을 포착합니다.
저는 대기열 (queue)을 날짜별로 번호가 매겨진 일반 마크다운 (markdown) 파일로 유지합니다. 작업은 파일 이름순으로 정렬하여 발행되지 않은 가장 오래된 파일을 가져옵니다. 대기열이 비어 있으면 아무것도 하지 않고 "queue empty"라고 로그를 남깁니다. 이 마지막 문장은 생각보다 중요합니다. 소리 없이 실패하는 크론 잡 (cron job)은 크론 잡이 없는 것보다 더 나쁩니다. 왜냐하면 자신의 로그 (log)를 더 이상 신뢰하지 않게 되기 때문입니다.
타이밍 또한 중요합니다. 08:30은 대부분의 독자가 깨어나기 전이지만, 인덱스 재구축 (index rebuild, 아래에서 자세히 설명)이 완료된 후입니다. 스택 내의 크론 잡 (cron job)들은 서로 다른 시간에 실행되더라도 순서가 있습니다. 순서를 잘못 잡으면, 아직 해당 포스트의 존재를 알지 못하는 인덱스로 연결되는 링크가 포함된 포스트를 게시하게 됩니다.
이 시스템이 포함된 전체 아키텍처를 알고 싶다면, Claude Blueprint에서 각 요소가 어떻게 연결되는지 확인할 수 있습니다. 게시 (publish) 잡은 심장 박동과 같지만, 여기에 데이터를 공급하는 나머지 다섯 개의 잡이 없다면 무용지물입니다.
4개 채널로의 자동 신디케이션 (Auto-syndicate)
포스트가 라이브된 지 30분 후인 09:00에 신디케이션 (syndicate) 잡이 실행됩니다. 이 잡은 방금 게시된 기사를 가져와 플랫폼별 버전을 생성하고, 이를 4개의 채널로 전송합니다.
각 채널은 서로 다른 형태를 갖게 됩니다. 롱폼 (long-form) 네트워크에는 처음 세 단락과 링크가 전달됩니다. 짧은 소셜 채널에는 하나의 후크 (hook) 문구와 링크가 전달됩니다. 이메일 리스트에는 TLDR 항목이 불렛 포인트로 나열된 일반 텍스트 요약본이 전달됩니다. 하나의 소스, 네 개의 출력
이 과정이 절약해 주는 시간을 기록해 보았습니다. 하나의 포스트를 네 개의 채널에 수동으로 배포할 때는 답글을 읽느라 주의가 분산되는 일이 잦아 약 25분이 소요되었습니다. 약 90개의 포스트를 기준으로 계산하면, 동일한 문구를 네 번씩 다시 서식화하는 데 쓰지 않아도 되는 시간이 37시간이 넘습니다. 또한, 배포 작업(syndicate job)은 주의가 분산되지도 않고, 채널을 누락하지도 않으며, 서두르다가 잘못된 링크를 게시하는 일도 없습니다.
여기서 발생할 수 있는 실패 모드(failure mode)는 채널 API가 다운되는 경우입니다. 그런 일이 발생하면 작업은 채널별로 실패를 로그(log)에 기록하고 나머지 채널에 대한 작업을 계속합니다. 하나의 채널이 작동하지 않는다고 해서 전체 실행이 중단되지는 않습니다. 이러한 격리(isolation) 구조를 구축하는 데 오후 내내 시간이 걸렸지만, 이미 수십 번은 그 가치를 충분히 해냈습니다.
자동 풀(Auto-pull) 및 블로그 인덱스 재구축(blog-index rebuild)
두 가지 작업이 제 콘텐츠의 무결성을 유지해 줍니다. 첫 번째는 매일 06:00에 실행되는 자동 풀(auto-pull)입니다. 이 작업은 제 콘텐츠 저장소(repo)를 동기화하고, 전날 밤 노트북에서 수행한 모든 수정 사항을 가져와(pull) 당일 작업을 위해 스테이징(stage)합니다. 저는 마크다운(markdown) 파일로 글을 쓰며, 때로는 자정에 오타를 수정하기도 합니다. 풀(pull) 작업 덕분에 인덱스 재구축(index rebuild)이 시작되기 전에 이러한 수정 사항들이 반영됩니다.
두 번째는 6시간마다 실행되는 블로그 인덱스 재구축(blog-index rebuild)입니다. 이것은 제가 가장 과소평가했던 작업입니다. 인덱스는 모든 기사 목록, 클러스터 페이지(cluster pages), 태그 그룹화, 그리고 각 기사 하단의 "관련 포스트(related posts)" 블록을 나열하는 페이지입니다. 이 모든 것은 직접 작성하는 것이 아니라 생성되는 것입니다.
새 포스트를 게시하면, 수십 개의 기존 페이지가 이제 해당 포스트로 링크를 걸어야 합니다. 클러스터 페이지에 새로운 항목이 추가되어야 하고, 태그 페이지에도 반영되어야 합니다. 동일한 클러스터 내의 이전 기사들의 관련 블록에도 해당 포스트가 나타나야 합니다. 실제적인 규모에서 이 작업을 수동으로 하는 것은 불가능합니다. 따라서 재구축 작업은 모든 기사를 훑으며 태그와 클러스터를 읽고, 모든 교차 링크(cross-links)를 처음부터 다시 생성합니다.
매번 처음부터 다시 생성하는 것이 낭비처럼 들릴 수 있습니다. 약간은 그렇습니다. 전체 재구축에는 약 40초가 소요됩니다. 하지만 인덱스(index)를 점진적으로 패치(patch)하려고 시도하는 대안은 제가 추적할 수 없는 버그의 근원이었습니다. 전체 재구축은 지루하지만 정확합니다. 저는 매 순간 영리하지만 망가진 방식보다 지루하지만 정확한 방식을 택하겠습니다.
하루에 한 번 대신 6시간마다 실행한다는 것은 정오에 게시된 포스트가 관련 블록(related blocks)에 나타나기 위해 내일까지 기다릴 필요가 없음을 의미합니다. 하루에 네 번의 재구축이 이루어지며, 각 실행은 마지막 실행 이후 변경된 모든 사항을 포착합니다. 크론(cron) 스케줄은 0 */6 * * *이며, 설정한 이후로 한 번도 건드리지 않았습니다.
재구축 작업은 또한 로그(log)에 카운트(count)를 기록합니다: 얼마나 많은 기사, 얼마나 많은 링크가 생성되었는지, 그리고 얼마나 많은 클러스터(clusters)가 있는지 말입니다. 그 카운트가 예상치 못하게 감소하면, 무언가가 삭제해서는 안 될 콘텐츠를 삭제했다는 것을 알 수 있습니다. 이는 저렴한 카나리(canary, 위험 신호) 역할을 합니다. 저는 많은 파일을 다루는 모든 작업에서 카운트를 기록하는 법을 배웠습니다. 배경을 설명하자면, 인덱스 재구축은 아래에 설명할 garden-walk 작업에도 데이터를 공급하며, 이것이 두 작업의 타이밍이 어긋나 있는 이유입니다.
Garden-walk 및 /now-page 새로고침
마지막 두 작업은 고장 나기 전까지는 아무도 눈치채지 못하는 조용한 작업들입니다.
Garden-walk는 아무도 읽지 않는 시간인 03:00에 실행됩니다. 이 작업은 게시된 모든 기사를 크롤링(crawl)하고 모든 링크를 확인합니다. 내부 링크(Internal links)는 실제 파일 구조와 대조하여 검증됩니다. 외부 링크(Outbound links)는 여전히 연결되는지 확인하기 위해 HEAD 요청(HEAD request)을 보냅니다. 깨진 모든 항목은 제가 매일 아침 받는 보고서에 포함됩니다.
이 작업은 저를 정말 창피한 상황에서 구해준 적이 있습니다. 제휴(affiliate) URL의 형식이 변경되면서 제 오래된 포스트 중 14개가 갑자기 죽은 페이지를 가리키게 되었습니다. Garden-walk는 다음 날 아침에 이를 포착했습니다. 저는 템플릿을 수정했고, 인덱스 재구축이 수정 사항을 전파했으며, 대부분의 독자는 깨진 버전을 보지 못했습니다. 크롤링이 없었다면 몇 주 뒤에 짜증 섞인 이메일을 받고서야 알게 되었거나, 더 나쁘게는 영영 알지 못했을 것입니다.
Garden-walk는 아무것도 자동으로 수정하지 않습니다. 저는 의도적으로 그렇게 결정했습니다. 당신이 잠든 사이에 라이브 콘텐츠 (live content)를 편집하는 작업은 결국 편집해서는 안 될 무언가를 편집하게 될 작업입니다. 작업은 보고하고, 결정은 제가 합니다. 매일 아침 보고서를 읽는 데 쓰는 몇 분은, 자동화된 수정이 90개의 기사에 한꺼번에 잘못 적용될 위험보다 훨씬 가치 있습니다.
/now-page 새로고침은 가장 작은 작업이자 제가 가장 좋아하는 작업입니다. 저의 /now 페이지는 제가 이번 주에 무엇을 작업하고 있는지를 보여줍니다. 이 작업은 매일 아침 07:00에 실행되며, 단일 상태 파일 (status file)과 최근 발행된 기사 3개를 가져옵니다. 따라서 이 페이지는 희망 섞인 계획 세션에서 발행하려고 의도했던 것이 아니라, 실제로 발행된 내용을 항상 반영합니다.
아주 작은 디테일입니다. 하지만 3주 동안 멈춰 있는 /now 페이지는 방문자에게 스튜디오가 망했다고 말해줍니다. 오늘 아침에 업데이트된 /now 페이지는 누군가 집에 있다는 것을 알려줍니다. 새로고침 작업은 제가 아무런 노력을 기울이지 않아도 그 신호를 정직하게 유지해 줍니다. 상태 파일을 읽고, 최근 게시물을 포맷팅하고, 페이지를 작성합니다. 매일 8초가 소요됩니다.
이 여섯 가지 작업이 모여 제가 책상에 있든 없든 스튜디오가 운영되도록 합니다. 저는 기차 안에서, 한 줄짜리 커밋 (commit)을 담은 휴대폰으로, 그리고 한 번은 게시물 3개를 미리 대기시켜 두었다가 실수로 잠든 사이에 발행하기도 했습니다. 크론 테이블 (cron table)은 제가 어디에 있는지 상관하지 않습니다. 그것이 바로 이런 방식으로 시스템을 구축한 핵심 목적입니다.
결론 (Bottom Line)
여섯 개의 크론 잡 (cron jobs), 저렴한 서버 한 대, 그리고 대부분 스스로 돌아가는 일일 발행 스튜디오. 이 모든 작업에 적용된 패턴은 동일합니다. 각 작업은 한 가지 일만 수행하고, 수치나 상태를 로그 (log)로 남기며, 조용히 실패하는 대신 요란하게 실패를 알립니다. 08:30에 발행합니다. 09:00에 신디케이트 (syndicate)합니다. 06:00에 가져옵니다 (pull). 6시간마다 인덱스 (index)를 재구축합니다. 03:00에 가든을 산책 (walk the garden)합니다. 07:00에 /now를 새로고침합니다.
이 중 복잡한 것은 아무것도 없습니다. 어려운 부분은 무엇을 자동화하고 무엇을 수동으로 유지할지 결정하는 것이었습니다. 저는 지루하고 검증 가능한 것은 무엇이든 자동화합니다. 판단 (judgment)에 기반하여 라이브 콘텐츠를 편집하는 것은 무엇이든 수동으로 유지합니다. 이 경계가 바로 전체 철학입니다.
자신만의 버전을 구축하고 있다면, 게시 작업 (publish job)부터 시작하여 불편함이 나타날 때마다 다른 작업들을 추가하세요. 첫날부터 6가지가 모두 필요하지는 않습니다. 신뢰할 수 있는 작업 하나가 필요하고, 그다음 두 번째가 필요할 뿐입니다. 직접 연결하기 전에 각 요소가 어떻게 맞물리는지 확인하고 싶다면, Claude Blueprint에서 전체 그림을 확인할 수 있습니다.
이 기사에는 제휴 링크가 포함되어 있습니다. 이 링크를 통해 가입하시면, 귀하에게 추가 비용 부담 없이 저에게 소정의 수수료가 지급될 수 있습니다. (광고)
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기