
Claude Code로 자동화 태스크를 병행 운용하며 알게 된 함정과 대책
요약
Claude Code를 활용해 여러 자동화 태스크를 병행 운용할 때 발생하는 프로세스 감시 오류, 쓰기 경합, 상태 불일치 문제와 그 해결 방안을 다룹니다. 프로세스 생존 여부와 실제 처리 상태를 분리하여 확인하고, 파일 수정 시간을 통한 경합 방지 전략을 제안합니다.
핵심 포인트
- 프로세스 생존과 내부 처리 정상 여부는 별개로 감시해야 함
- PID 기반의 정확한 프로세스 생사 확인 메커니즘 필요
- 여러 에이전트 간 파일 쓰기 경합 방지를 위해 수정 시간(mtime) 체크 활용
- 데이터의 정답(Source of Truth)을 명확히 정의하여 상태 불일치 방지
「돌아가고 있을 것」이 가장 위험하다
개인 개발이나 부업으로 자동화 스크립트를 단 하나만 돌리고 있을 때는 그렇게 큰 사고가 일어나지 않습니다. 무언가 이상하면 바로 알아챌 수 있고, 확인해야 할 대상도 하나뿐이기 때문입니다. 하지만 정기 실행 스크립트나 스케줄 운용 태스크를 Claude Code와 함께 여러 개 병행해서 돌리게 되면 상황이 달라집니다. 하나하나의 스크립트는 단순하더라도, 「병행해서 돌리고 있다」는 사실 자체가 원인이 되는 트러블이 발생하기 시작했습니다.
이 기사에서는 제가 실제로 자동화를 여러 개 병행 운용하는 과정에서 마주한 구체적인 현상과, 그로부터 얻은 사고방식을 정리합니다. 미리 말씀드리자면, 여기에 적는 내용은 1차 정보로서의 실체험과 그로부터의 추측입니다. 「~라는 현상이 있었다」와 「~가 아닐까라고 추측하고 있다」는 의식적으로 구분하여 작성하고 있으니, 그 전제하에 읽어주시기 바랍니다.
실제로 일어난 일
상주 프로세스가 「돌아가고 있다고 착각」하며 멈춰 있었다
시장 조사용 데이터를 정기적으로 수집하는 Python 스크립트를 상주 프로세스로 돌리고 있었습니다. 그런데 이것이 원인이 불분명한 타이밍에 프로세스째로 사라져 멈춰 있는 일이 여러 번 있었습니다.
처음에 까다로웠던 것은 감시 메커니즘 자체가 오검출을 하고 있었다는 점입니다. pgrep으로 프로세스 이름을 검색하여 생사를 판정하고 있었는데, 프로세스 이름의 패턴이 미묘하게 일치하지 않는 경우가 있어, 실제로는 살아있는 프로세스를 「돌아가지 않고 있다」고 오판하는 일이 있었습니다. 이를 깨달은 후에는 pgrep을 통한 패턴 매칭이 아니라, 기록해 둔 PID에 대해 ps -p <PID>를 실행하여 해당 PID가 실제로 존재하는지로 생사를 확인하는 방식으로 전환하여 오검출을 해소했습니다.
또 하나 까다로웠던 것은 프로세스 자체는 살아있는데 내부 처리만 실패하는 케이스입니다. 어느 날, sqlite3.DatabaseError: authorization denied라는 OS 레벨의 권한 에러가 발생하여, 데이터베이스 쓰기만 계속 실패하고 있는 상태가 되었습니다. 프로세스의 생사만 보고 있으면 정상으로 보이기 때문에, 이는 프로세스 감시와는 별개로 알아챌 필요가 있었습니다. 장시간 가동되는 동안 OS 측의 권한이 어떤 이유로 해제된 것이 아닐까 추측하고 있지만, 정확한 원인은 특정하지 못했습니다.
이 사건을 통해 「프로세스가 살아있다」와 「처리가 정상적으로 진행되고 있다」는 별개의 레이어에서 확인할 필요가 있다는 교훈을 얻었습니다.
여러 에이전트가 같은 곳을 건드리러 간다
자동화 태스크를 병행해서 돌리다 보면, 여러 AI 에이전트나 세션이 동일한 작업 폴더나 리포지토리(Repository)를 동시에 건드리러 가는 상황이 발생합니다. 혼자서 하나의 작업을 할 때는 의식할 필요가 없었던 「쓰기 경합 (Write Contention)」을 의식하지 않을 수 없게 되었습니다.
이에 대해서는 무언가를 파일에 쓰기 전에 대상 파일의 수정 시간(mtime)을 확인하여, 최근 10분 이내에 다른 곳에서 업데이트된 흔적이 없는지 체크하는 규칙을 세웠습니다. 최근에 업데이트되었다면 해당 영역은 건드리지 않고 처리를 보류합니다. 엄격한 배타 제어(Exclusive Control)는 아니지만, 수정 시간이라는 얻기 쉬운 정보만으로도 「지금은 누군가 건드리고 있을 가능성이 있다」는 단서를 얻을 수 있어 구현 비용 대비 효과를 느끼고 있습니다.
「상태의 정답(Source of Truth)」이 어긋나 공개물이 의도치 않게 되돌아갔다
Zenn의 기사나 스크립트의 공개·비공개 관리에서도 유사한 구조의 문제에 직면했습니다. Web 관리 화면의 공개 버튼으로 상태를 바꿨다고 생각했는데, 리포지토리 내의 frontmatter 설정과 불일치하여 의도치 않게 공개물이 비공개 상태로 되돌아간 일이 있었습니다.
원인은 「공개 상태의 정답이 어디에 있는가」를 결정하지 않았기 때문이라고 생각합니다. 관리 화면과 리포지토리 내용이라는 두 곳을 모두 정답(Source of Truth)으로 취급하려 한 결과, 어느 한쪽을 업데이트하는 것을 잊은 타이밍에 어긋남이 발생한 것입니다. 이후로는 공개 상태 관리는 반드시 리포지토리 내의 설정 파일을 변경하여 push하는 방식으로 통일하고, Web 관리 화면의 버튼 조작으로는 공개 상태를 바꾸지 않는다는 규칙을 세웠습니다. 상태의 정답을 한 곳으로 정해둠으로써 이러한 종류의 불일치는 일어나기 어려워졌습니다.
Zenn 책의 공개가 즉시 반영되지 않는 경우가 있었다
여러 권의 유료 도서를 운영하다 보면, Zenn 측에 도서 공개와 관련하여 최근 1주일 정도 단위의 Rate Limit (속도 제한) 같은 것이 있는 것 같다고 느껴지는 장면이 있었습니다. 상한선에 대한 상세 내용은 공개되지 않았기에 확신할 수는 없지만, 신간을 공개하려고 할 때 직전에 다른 도서를 공개했다면 변경 사항이 즉시 반영되지 않는 일이 실제로 있었습니다.
몇 번이고 재전송 (re-push)을 시도해도 즉시 반영되지 않았고, 결국 시간을 두고 다시 시도했더니 반영되었습니다. 아마도 Rate Limit (속도 제한)과 같은 창이 열리기를 기다리는 형태가 되었던 것이 아닐까 추측합니다. 이 경험을 통해 여러 권의 도서나 기사의 공개 스케줄을 세울 때는, "연속해서 공개 작업을 하면 직후의 반영이 늦어질 수 있다"라는 전제를 고려하도록 하고 있습니다.
X(구 Twitter)의 예약 포스팅이 이유도 모른 채 사라짐
X의 예약 포스팅 기능에서도 원인을 알기 어려운 현상을 마주했습니다. 포스팅 본문에 특정 도메인, 구체적으로는 무료 호스팅에서 자주 사용되는 workers.dev와 같은 서브도메인을 포함하는 링크를 넣었을 경우에 한해서, 에러 표시도 아무것도 나오지 않은 채 예약 자체가 실행되지 않고 사라져 버리는 현상을 여러 차례 확인했습니다.
구분 테스트로서 동일한 포스팅 문구의 링크 부분만 다른 도메인으로 교체해 보았더니, 문제없이 예약할 수 있었습니다. 에러 메시지가 전혀 나오지 않기 때문에 시스템 측의 결함인지 의도적인 사양인지 판단할 수는 없지만, 링크 스팸 대책과 같은 동작으로 무료 호스팅 계열의 도메인이 어떤 형태로든 필터링되고 있는 것이 아닌가 추측하고 있습니다. 어디까지나 추측이며 실제 이유는 공개되지 않았습니다.
이후로는 예약 포스팅에 링크를 포함할 때, 가능하다면 독자 도메인 등 다른 링크를 사용하도록 하고, 무료 호스팅 계열의 서브도메인을 포함하는 포스팅은 예약 후에 반드시 반영되었는지 확인하는 방식으로 운영하고 있습니다.
일본어 글자 수 카운트를 잘못 계산함
마지막은 사소하지만, 사소하게 곤란했던 이야기입니다. X의 글자 수 카운트는 일본어(전각 문자)를 1글자당 2카운트로 계산하는 사양으로 되어 있습니다. "이 정도 분량이라면 아직 짧겠지"라는 감각으로 본문을 작성했더니, 실제로는 상한을 초과하여 포스팅 버튼을 누를 수 없는 일이 있었습니다.
이것 자체는 X의 사양으로 명시되어 있는 내용이지만, 일본어로 문장을 쓸 때의 체감 글자 수와 실제 카운트 수 사이에는 괴리가 생기기 쉽습니다. 이후 일본어 문장량을 가늠할 때는 대략적으로 "글자 수 × 2"로 개산하도록 하고 있습니다. 엄밀한 계산은 아니지만, 포스팅 버튼을 누르지 못해 다시 써야 하는 수고는 상당히 줄었습니다.
대책으로서 익힌 사고방식
지금까지의 현상들을 되돌아보면 대책 자체는 하나씩 개별적이지만, 뿌리에 있는 사고방식은 몇 가지 공통 패턴으로 정리할 수 있습니다.
- "동작하고 있음"의 판정 기준을 한 단계 구체화하기: 프로세스 이름에 의한 패턴 매칭이 아니라, 기록된 PID를 통한 생사 확인처럼 더 확실한 수단에 가깝게 가져간다. 프로세스의 생사와 처리의 정상성은 별개로 보고 둘 다 확인한다.
- 병행해서 건드려질 가능성이 있는 곳에는 건드리기 전에 완충 단계를 두기: 갱신 일시 등의 단서를 통해 "최근에 다른 곳에서 건드려지지 않았는지"를 확인한 후 기록한다.
- 상태의 정답(Truth)을 한 곳으로 정하기: 공개 설정처럼 여러 곳에서 변경할 수 있는 것은 변경해도 좋은 장소를 하나로 정하고, 그 외의 곳에서는 건드리지 않는다.
- 외부 서비스의 제약은 경험칙으로서 기록해 두기: 공개 관련 Rate Limit (속도 제한)이나 특정 도메인 취급처럼 공식 정보가 부족한 제약은, 한 번 조우하면 재현 조건을 메모로 남겨 다음에 같은 조작을 할 때의 전제로 삼는다.
- 감각치가 아니라 실측치로 가늠하기: 글자 수 카운트처럼 체감과 실제 값이 어긋나기 쉬운 것은 간단한 기준 계산식으로 바꾸어 둔다.
모두 특별한 기술이 아니라, "수상한 징후가 나타나면 판정 방법 자체를 의심한다"라는 자세에 가깝다고 생각합니다.
뿌리를 따라가 보면 이들 중 상당수는 "한 사람(한 에이전트)이 모든 공정을 담당하고 있다"는 점에서 기인하는 문제이기도 합니다. 작업을 계획·실행·검품의 세 가지 역할로 나누어 생각하는 프레임워크에 대해서는 유료 도서 『비엔지니어(Non-engineer)를 위한 AI 에이전트 위임·검품 설계 가이드』에서 자세히 다루고 있습니다.
이 운용의 한계
솔직히 말하면 이 운용은 만능이 아닙니다.
우선 프로세스의 권한 에러처럼 근본 원인을 완전히 특정할 수 없는 현상이 있습니다. sqlite3.DatabaseError: authorization denied
발생한 건에 대해서는 대증요법으로서 모니터링 방법을 재검토할 수는 있었지만, 왜 장시간 가동 도중에 권한이 해제되었는지에 대한 근본 원인까지는 파악하지 못했습니다. 동일한 종류의 문제가 형태를 바꾸어 재발할 가능성은 남아 있습니다.
다음으로, Zenn의 레이트 리밋 (Rate Limit)이나 X의 예약 포스팅 동작과 같이 외부 서비스의 내부 사양에 의존하는 현상은, 이쪽의 운영만으로는 완전히 컨트롤할 수 없습니다. 시간을 두고 재시도하거나, 링크의 도메인을 변경하는 등의 대처는 가능하더라도, 사양 자체가 바뀌면 동일한 대처가 통하지 않게 될 가능성이 있습니다. 어디까지나 "지금까지 관측된 범위에서의 경험칙"으로서 다루어야 한다고 생각합니다.
마지막으로, 이러한 함정의 대부분은 실제로 자신이 직접 겪고 나서야 비로소 언어화할 수 있었던 것들입니다. 병행 운용을 시작하기 전부터 모든 것을 예견하고 대책을 세워두는 것은, 적어도 저에게는 불가능했습니다. 이 기사에 쓴 내용도 향후 다른 함정에 맞닥뜨리게 된다면 추가로 검토하게 될 것이라고 생각합니다.
요약
자동화 태스크를 하나만 돌리고 있을 때는 표면화되지 않았던 문제가, 여러 개를 병행해서 돌리게 되면서 비로소 보이기 시작한다는 것이 이번에 가장 실감한 부분입니다. 프로세스의 생사 판정, 쓰기 경합 (Write Contention), 상태의 단일 진실 공급원 (Single Source of Truth) 확보, 외부 서비스 제약의 경험칙화 등, 모두 사소한 이야기처럼 들릴 수 있지만 병행 운용을 지속하는 데 있어서는 매우 중요합니다.
이러한 "AI 에이전트에게 정형 작업을 맡길 때의 권한 설계 및 운영 규칙"을 보다 체계적으로 다룬 내용으로서, 『AI 에이전트로 정형 업무를 자동화하는 실전 가이드』라는 책을 쓰고 있습니다. 또한, 엔지니어가 아닌 분들이 AI 에이전트에게 작업을 위임하고 결과물을 검품할 때의 사고방식을 정리한 『비엔지니어를 위한 AI 에이전트 위임·검품 설계 가이드』라는 책도 공개하고 있습니다. 둘 다 "머리말"은 무료로 읽을 수 있으니, 관심이 있다면 살펴보시기 바랍니다.
또한, "내 업무는 어느 정도 자동화에 적합한가"를 대략적으로 알고 싶은 분들을 위해, 무료인 정형 업무 자동화 포텐셜 진단도 공개하고 있습니다. 6개의 질문에 답하는 것만으로 자동화 포텐셜 등급과 절감 시간의 기준을 알 수 있습니다 (입력 내용은 브라우저 내에서 처리되며, 서버로는 전송되지 않습니다).
Discussion

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