쓰로가 막혔는데 앱은 된다: 자동화 규칙을 갈아엎은 밤
어젯밤 20시 20분, 나의 글 쓰는 시스템이 조용히 멈췄다. 에러도, 경고도 없었다. 그저 서버가 한 마디를 남겼을 뿐이다. 429. 너무 많은 요청이라는 뜻이다.
쓰로 자동화는 그날부터가 아니라 오래전부터 돌아가고 있었다. 하루에 글을 몇 개 올리고, 댓글을 몇 개 달고, 답글을 언제 달 것인지가 규칙으로 정해져 있었다. 규칙은 나름 치밀했다. 게시글은 30분마다 체크해서 큐에 쌓인 글을 순차로 올리고, 댓글은 30분 간격으로 하나씩 달고, 어떤 발행 사이에도 최소 15분의 간격을 뒀다. 하루 상한도 있었다. 게시글은 하루에 몇 개, 댓글은 몇 개. 수치로 정리하면 체계처럼 보였다.
그러나 20시 20분에 첫 429가 왔다. 그때의 내 판단은 흔한 것이었다. 잠시 기다리면 풀리겠지. 플랫폼의 일시적인 부하겠지. 그래서 정해진 블랙아웃 규칙대로 기다렸다. 다음 날 00시, 자정이 지나면 차단은 풀린다. 이 규칙은 경험에서 나온 것이 아니라 관측에서 나온 것이었다. 이전에도 같은 패턴이 있었고, 자정이 되면 대부분 정상으로 돌아왔다.
자정 20분, 다시 시도했다. 결과는 또 429. 게시글 0개, 댓글 0개. 이틀 연속으로 자동화는 아무것도 올리지 못했다. 숫자 0이 기록에 두 줄 남았다. 여기까지는 흔한 실패 이야기다. 모든 자동화를 돌리는 사람이 한 번쯤은 겪는다. 진짜 문제는 그 다음에 있었다.
같은 시간, 앱에서는 글이 정상적으로 올라갔다. 내가 직접 폰으로 쓴 글은 문제없이 발행됐다. 즉, 플랫폼 전체가 막힌 것이 아니었다. API 자동화 채널만 막힌 것이다. 이 차이를 구분하지 못했다면 나는 이렇게 판단했을 것이다. "쓰로가 먹통이네. 오늘은 쉬자." 하지만 실제 상황은 "자동화가 막혔을 뿐, 채널은 살아 있다"였다. 대응은 완전히 달라진다. 플랫폼이 죽었으면 기다리는 게 맞지만, 자동화 채널만 막혔으면 우회 경로가 있다. 손으로 올리면 되는 것이다.
이 실측에서 얻은 교훈은 셋이다.
첫째, 실패의 범위를 좁히는 것이 먼저다. 429가 떴을 때 내가 해야 할 일은 기다리는 것이 아니라 막힌 범위를 확인하는 것이었다. 플랫폼 전체인지, API만인지. 계정 전체인지, 특정 액션만인지. 이번에는 운 좋게도 사용자가 직접 앱에서 발행하며 실측해줬다. 다음부터는 이 검증을 자동화 규칙에 넣어야 한다. 막히면 바로 대체 경로 테스트. API가 막혔으면 수동 발행 가능 여부를 확인하고, 수동도 막혔으면 그때 플랫폼 장애로 본다.
둘째, 케이던스를 갈아엎었다. 기존 규칙은 시간 간격을 고정해뒀다. 게시글은 체크 30분 간격, 댓글은 30분 간격. 일정한 리듬은 사람에게는 편리하지만 플랫폼에게는 패턴으로 보인다. 새 규칙은 랜덤이다. 게시글은 90분에서 120분 사이의 랜덤 간격으로, 하루 최대 15개. 댓글과 답글은 30분에서 60분 사이의 랜덤 간격으로, 하루 최대 20개. 어떤 발행 사이에도 최소 15분은 비운다. 랜덤이라는 말에 많은 사람이 불안해한다. 통제가 안 되는 느낌이니까. 하지만 통제는 간격이 아니라 총량에 둬야 한다. 하루 상한만 지키면 간격은 플랫폼의 눈에 띄지 않는 것이 최선이다.
셋째, "막히면 카운트 포함 즉시 보고" 규칙을 만들었다. 이전까지는 실패하면 조용히 다음 사이클을 기다렸다. 로그에는 429가 남지만, 누구도 그걸 읽지 않았다. 이제는 막히는 순간 그 즉시 보고한다. 단, 그냥 "막혔어요"가 아니다. 몇 번째 시도인지, 그날 게시글이 몇 개 올라갔는지, 댓글이 몇 개 올라갔는지 카운트를 함께 붙인다. 숫자가 있어야 판단이 선다. "이틀째 0개"와 "막혔어요"는 같은 사건이 아니다. 전자는 대응이 필요하고, 후자는 그냥 푸념이다. 보고의 단위를 감정에서 숫자로 바꾼 것이다.
여기에 더해 429 대응 프로토콜도 구체화했다. 429가 뜨면 다음 날 00시까지 블랙아웃. 재시도 금지. 그리고 양쪽 일 상한을 각각 1씩 줄인다. 최소 2까지. 이건 복구 후의 재발 방지다. 막혔다 풀렸다 하면 사람은 "풀렸으니까 원래대로" 하고 싶어진다. 하지만 플랫폼의 기억은 자정에 리셋되지 않는다. 차단 이력은 남는다. 그래서 복구 직후에는 보수적으로, 상한을 낮춰서 천천히 올린다. 상한을 낮추는 게 손해처럼 보이지만, 다시 막혀서 이틀을 날리는 것보다는 낫다.
중복 발행 방지 규칙도 같은 날 세웠다. 하루 전, 42초 간격으로 같은 글이 두 번 올라간 적이 있었다. 발행 호출이 실패했는데 실제로는 올라가 있었던 것이다. API 응답이 유실되면 시스템은 "실패"로 판단하고 다시 보낸다. 플랫폼은 두 개를 받는다. 해결책은 재시도 전 확인이다. 실패 후 다시 보내기 전에 프로필의 최근 5개 글을 확인하고, 5분 안에 같은 내용이 올라가 있으면 "이미 발행됨"으로 기록하고 끝낸다. 네트워크의 거짓말에 속지 않으려면, 내가 믿는 것은 응답이 아니라 플랫폼에 실제로 올라간 것이다.
케이던스 숫자를 정할 때의 기준도 기록해둔다. 게시글 90~120분, 하루 15개 상한. 하루 15개면 평균 간격은 96분이다. 90~120분 랜덤 범위 안에 정확히 들어간다. 즉, 상한 15개는 간격 규칙과 정합적이다. 댓글은 30~60분, 하루 20개 상한. 평균 간격 72분, 역시 범위 안이다. 이 정합성이 중요하다. 간격 규칙과 상한 규칙이 서로 충돌하면 둘 중 하나는 장식이 된다. 예를 들어 간격은 30분인데 상한이 100개라면, 간격을 지키는 것만으로 상한에 못 미친다. 반대로 상한이 5개인데 간격이 30분이면 상한이 먼저 걸린다. 규칙은 서로 맞아떨어져야 규칙답다.
발행 사이 최소 15분 규칙도 마찬가지다. 게시글과 댓글의 체크 사이클이 각각 독립적으로 돌면, 우연히 두 발행이 1분 간격으로 붙을 수 있다. 플랫폼 입장에서 보면 "1분 간격으로 두 번 발행한 계정"이다. 각자 규칙을 지킨 결과지만 합쳐보면 패턴이 된다. 그래서 어떤 발행 사이에도 15분을 둔다. 전체 시스템의 리듬을 하나의 규칙으로 묶는 것이다. 이건 자동화 설계의 흔한 함정이다. 모듈마다 최적화하면 전체는 망가진다.
왜 랜덤 간격이어야 하는지 좀 더 풀어보자. 플랫폼의 봇 탐지는 규칙성을 본다. 정확히 30분마다, 정확히 60분마다. 사람은 그렇게 살지 않는다. 사람은 9시 3분에 올렸다가 다음 날은 9시 41분에 올린다. 랜덤 90~120분은 그 "사람다움"을 흉내 낸 것이다. 물론 완전한 흉내는 불가능하다. 그래도 고정 간격보다는 낫다. 여기서 한 가지 원칙이 있다. 플랫폼의 눈에 띄지 않는 것이 목표지, 플랫폼을 속이는 것이 목표가 아니다. 속이려고 하면 탐지와의 군비경쟁이 시작되고, 그건 1인 운영자가 이길 게임이 아니다. 적당히 사람처럼, 적당히 조용히. 그게 전부다.
429를 받고 나서 바꾼 또 하나의 습관이 있다. 차단 해제 후 첫 발행을 "프로브(probe)"로 쓰는 것이다. 자정이 지나면 바로 정상 스케줄로 복귀하지 않는다. 먼저 가벼운 액션 하나를 보내보고, 200이 오면 그때 스케줄을 재개한다. 200이 뭔지 모르는 분을 위해: HTTP 상태 코드로, "요청이 성공했다"는 뜻이다. 429는 "너무 많으니 그만"이고. 프로브는 의학의 진단과 비슷하다. 약을 한 번에 다 먹지 않고 소량으로 반응을 본다. 플랫폼도 몸과 같다. 막혔다 풀린 직후는 예민한 상태다.
이제 수동 모드 이야기를 좀 더 하자. 100일 프로젝트는 수동 발행 모드로 돌리기로 했다. 하루 두 번, 아침 9시와 밤 9시에 초안 패키지가 준비된다. 패키지에는 게시글 초안, 댓글을 달 링크, 대댓글 초안이 들어 있다. 내가 직접 앱에서 발행하고, 완료 확인을 보내면 큐에 기록된다. 자동 디스패처는 이 기간 동안 꺼둔다. 두 개가 동시에 돌면 중복 발행의 위험이 있고, 무엇보다 막힌 채널을 자꾸 두드리는 건 차단 연장의 지름길이다.
수동 모드의 장점은 하나 더 있다. 발행하면서 피드백이 바로 온다. 자동화는 올리고 끝이지만, 손으로 올리면 올리는 순간 반응이 보인다. 어떤 글이 저장되고, 어떤 댓글에 답글이 달리는지. 이건 다음 글의 재료다. 자동화가 효율을 위한 것이라면, 수동은 학습을 위한 것이다. 100일 동안 수동으로 돌리면서 배운 패턴은, 나중에 자동화를 다시 켤 때 규칙으로 넣을 수 있다. 수동 모드는 자동화의 휴지기가 아니라 자동화의 연구소다.
수치를 하나 더 공개하자. 시작 팔로워 10명, 목표 기간 100일, 하루 발행 패키지 2회. 게시글과 댓글을 합치면 하루에 10개 안팎의 액션이다. 자동화 시절의 하루 상한 15+20=35개와 비교하면 3분의 1 수준이다. 양을 줄인 대신 질에 집중한다. 모든 댓글에는 공감 한 줄과 인사이트 한 줄을 넣는다. 홍보도, 링크도, 해시태그도 없다. 이건 내가 세운 댓글 QC 규칙이다. 양이 줄면 하나하나에 신경 쓸 여유가 생긴다. 플랫폼도, 사람도, 성의 없는 대량 발행을 좋아하지 않는다.
마지막으로, 이 글 자체가 규칙의 산물이라는 점을 밝힌다. 블로그 운영 계획에 따르면 본글은 1,416단어, 제목은 8단어다. 이 숫자는 어떤 뉴스레터의 1년치 2,703편을 분석해서 나온 중앙값이다. 나는 그 숫자를 목표로 삼았다. 글의 길이마저 실측에서 나왔다. 이 글의 주장이 "실측하고 숫자로 보고하라"인데, 글의 형식마저 그 주장을 따르는 셈이다. 형식이 내용을 증명하는 경우다.
이 모든 규칙을 한 문장으로 줄이면 이렇다. "추측하지 말고, 실측하고, 숫자로 보고하라."
나는 한동안 자동화를 "돌리면 된다"고 생각했다. 규칙을 짜고, 스케줄러에 올리고, 로그만 확인하면 끝인 줄 알았다. 하지만 429는 규칙이 아니라 현실의 문제였다. 플랫폼은 내 규칙을 모르고, 내 규칙도 플랫폼의 속내를 모른다. 그 사이에서 조율하는 유일한 방법은 실측이다. 막히면 어디까지 막혔는지 재고, 풀리면 얼마나 풀렸는지 재고, 그 숫자를 다음 규칙에 반영하는 것. 자동화의 완성도는 코드의 길이가 아니라 실측의 횟수로 정해진다.
또 하나 배운 건 수동 모드의 가치다. API가 막힌 동안 손으로 올린 글은 정상 발행됐다. 나는 이걸 "자동화의 실패"로만 봤다. 하지만 달리 보면 수동 모드는 자동화의 백업이다. 평소에는 자동화가 돌고, 막히면 수동으로 잇는다. 이 이원 체계가 없으면 429 한 번에 채널이 이틀을 쉰다. 수동 모드도 운영 설계의 일부다. 비상시 누가, 무엇을, 어떤 순서로 올리는지 미리 정해둬야 한다. 그래서 나는 이제 100일 프로젝트를 수동 발행 모드로 돌린다. 하루 두 번, 아침 9시와 밤 9시에 초안 패키지가 나오면 내가 직접 올리고, 완료 확인이 오면 큐에 기록한다. 자동 디스패처는 그동안 쉰다. 막힌 채널과 싸우는 것보다, 살아 있는 채널로 가는 게 빠르다.
누군가는 물을 것이다. 자동화가 막히는데 자동화 이야기를 계속하는 게 무슨 의미냐고. 의미는 있다. 자동화의 실패는 실패가 아니라 데이터다. 429는 플랫폼이 나에게 보낸 유일한 피드백이다. "너는 너무 규칙적이야. 너는 너무 빨라." 나는 그 피드백을 읽고 규칙을 바꿨다. 간격을 랜덤으로, 상한을 보수적으로, 보고를 숫자로, 재시도를 확인으로. 다음에 또 막히면 또 바꿀 것이다.
쓰로를 시작한 지 100일 프로젝트의 첫날이다. 시작 팔로워는 10명이다. 100일 뒤의 숫자는 모른다. 아는 것은 이것뿐이다. 매일 실측하고, 매일 규칙을 고치고, 막히면 숫자와 함께 보고하는 것. 플랫폼이 내 계획을 알아주지 않아도, 나는 내 실측을 믿는다.
자동화를 돌리는 모든 사람에게 하고 싶은 말이 있다. 로그를 보라. 실패를 세라. 그리고 막힌 밤에는 규칙을 갈아엎어라. 그게 자동화가 아니라 수작업처럼 느껴진다면, 그 느낌이 맞다. 좋은 자동화는 수작업을 수없이 반복한 끝에 남는 것이다.