새벽 봇 버그 두 개와 어드민 대청소
목차
새벽 0시에 들어와서 제일 먼저 건드린 건 vtuber_guard였다. 며칠 전부터 스캔 로그가 뭔가 이상하다는 느낌이 있었는데, 오늘 새벽에 드디어 재현 조건이 손에 잡혔다. 두 가지 버그가 사실 서로 다른 레이어에 있었는데 같은 파일에 있어서 한 세션에 같이 처리했다.
봇 안정화: DB 연결 끊김과 알림 노이즈
첫 번째 버그는 DB wait_timeout 끊김이었다. vtuber_guard는 외부 API를 순서대로 호출하면서 프로필을 스캔하는 구조다. 루프 한 사이클이 짧을 때도 있지만, 응답 속도가 느린 API가 끼면 스캔 중간에 몇 분이 훌쩍 넘어갈 때가 있다. 그 사이에 MySQL 연결이 조용히 사라진다. 서버 wait_timeout 설정이 생각보다 짧게 박혀 있었고, 긴 스캔 루프에서 그게 터지는 거였다.
증상은 전형적이었다. 스캔이 한참 돌다가 갑자기 MySQL server has gone away 류 에러가 튀어나오면서 그 사이클 전체가 날아간다. 커넥션 풀 라이브러리를 쓰면 자동 재연결을 처리해주기도 하지만, 이 봇의 DB 접근 구조는 그게 아니었다. 수정 방향은 스캔 루프 진입 시점마다 연결 상태를 체크하고 끊겼으면 재연결하는 패턴으로 잡았다. 스캔 중간중간 keep-alive 핑을 보내는 방법도 있는데, 루프 구조상 진입 시점 재연결이 더 명확했다. 핑 방식은 타이밍이 어긋나면 오히려 꼬일 수 있어서 패스했다.
두 번째 버그는 알림 노이즈였다. vtuber_guard는 주기적으로 데이터를 검토하고 이상 항목을 디스코드 채널로 알린다. 근데 이게 조치가 있든 없든 매 스캔 사이클마다 뭔가를 채널에 쏘고 있었다. "스캔 완료, N건 검토됨"이나 "이상 없음" 같은 메시지가 계속 올라오니까 채널이 사실상 로그 스트림이 돼버린 거다. 진짜로 조치가 필요한 항목이 올라와도 그 노이즈에 묻혀서 팀원이 알아채기 어렵다.
수정 자체는 단순했다. 실제로 액션이 발생한 경우에만 디스코드 메시지를 보내도록 조건 하나를 추가했다. 검토만 하고 아무 변화가 없으면 채널에는 아무것도 가지 않는다. 결과적으로 채널이 훨씬 조용해졌고, 메시지가 올라오는 순간 "뭔가 진짜 생겼다"는 신호가 된다. 알림 피로를 줄이는 가장 단순한 방법이지만, 이걸 처음부터 제대로 설계하지 않으면 나중에 채널이 슬렁슬렁 무시되기 시작한다.
두 수정 모두 같은 파일(vtuber_guard.py)에 있어서 커밋은 둘로 나눴다. 성격이 완전히 달랐기 때문에 하나로 묶으면 리뷰할 때 맥락이 흐릿해진다. 하나는 인프라 레이어 안정성 문제고, 하나는 운영 UX 문제다. 봇 운영하다 보면 이 두 가지가 거의 항상 같이 나온다는 걸 매번 다시 확인한다.
어드민 UI 전수 정비: 세 가지 축
봇 쪽이 마무리되고 나서 어드민으로 넘어갔다. 사실 이쪽은 기술 부채가 꽤 쌓여 있었다. 여러 시점에 여러 사람이 페이지를 추가하다 보니 헤더 마크업이 제각각이고, 대비 수치도 들쭉날쭉하고, 모바일에서 보면 레이아웃이 터지는 페이지가 여기저기 있었다. 낮에는 항상 더 급한 것들에 밀려서 미뤄뒀는데 오늘 새벽에 한꺼번에 처리했다.
PageHeader 통일 + 이모지 제거
어드민 메뉴 페이지가 14개인데, 헤더 마크업이 거의 다 달랐다. 누군가는 <h1>, 누군가는 <div className="text-2xl font-bold">, 누군가는 직접 스타일링한 섹션 태그를 썼다. PageHeader 컴포넌트가 이미 존재했는데도 쓰지 않는 페이지가 절반 이상이었다. 이 상태에서 PageHeader를 고치면 일부 페이지만 반영되고, 나머지는 따로 손대야 한다. 유지보수 비용이 계속 두 배로 붙는 구조였다.
14개 페이지 전부 PageHeader로 교체했다. 겸사겸사 제목에 붙어 있던 이모지도 전부 걷어냈다.
| 페이지 영역 | 주요 변경 |
|---|---|
| daily-bible (calendar/push/stats/verses) | PageHeader 교체, 이모지 제거 |
| formpack-stats | PageHeader 교체, 이모지 제거 |
| games | PageHeader 교체, 이모지 제거 |
| 나머지 8개 페이지 | 동일 패턴 일괄 적용 |
이모지 제거는 취향 차이처럼 보일 수 있는데, 어드민 툴에서 이모지가 제목에 붙어 있으면 분위기가 묘하게 어색하다. 개발 초기엔 빠르게 구분하려고 붙이기 시작한 건데, 디자인 언어가 어느 정도 자리잡고 나면 오히려 노이즈가 된다. 이런 "슬롭"을 걷어내는 게 코드 품질만큼이나 UI 품질에서 중요하다.
WCAG AA 명암비 전수 수정
접근성 감사를 돌렸더니 저대비 텍스트가 여기저기서 나왔다. WCAG AA 기준은 일반 텍스트 4.5:1, 대형 텍스트 3:1인데, text-gray-400이나 text-gray-300을 어두운 배경 위에 그냥 얹어놓은 곳이 꽤 됐다. 다크 계열 배경에 중간 밝기 텍스트를 쓰면 명암비가 직관보다 훨씬 낮게 나온다. 눈으로 보면 읽히는 것 같은데 측정해보면 기준 미달인 경우가 많다.
수정 대상:
AdUnitForm.tsx,AdUnitFormEnhanced.tsx,SlotMatrix.tsxbatch-jobs/page.tsxCategoriesClient.tsxCalendarClient.tsx
패턴은 거의 동일했다. text-gray-400 → text-gray-300 또는 text-gray-200으로 올리거나, 배경이 특히 어두운 경우엔 더 높은 숫자로 당겼다. Tailwind 팔레트 자체를 건드린 게 아니라 클래스 숫자 조정 수준이었지만, 결과는 저대비 텍스트 0건으로 나왔다.
접근성 수정은 눈에 바로 안 보인다는 이유로 백로그에서 계속 밀리는 경향이 있다. 근데 어드민 화면을 밝은 외부 환경에서 모바일로 보는 상황에서 저대비 텍스트는 직접적인 불편함이다. 팀 내부 툴이라도 이게 쌓이면 결국 "이 숫자가 뭔지 모르겠다"는 식으로 사용성에 영향을 미친다. 오늘 전수 처리한 걸로 당분간 이 항목은 0건 유지가 가능할 것 같다.
모바일 반응형: PageHeader 세로 적층
세 번째는 모바일 반응형 문제였다. PageHeader 컴포넌트 자체가 제목과 오른쪽 액션 버튼을 항상 가로로 나란히 배치하는 구조였는데, 이러면 좁은 화면에서 제목이 잘리거나 버튼이 흘러넘친다. 어드민을 모바일에서 자주 쓰는 편은 아니지만, 배포 직후 확인하거나 이동 중에 체크할 때 레이아웃이 무너지면 꽤 당황스럽다.
// 변경 전 - 항상 가로 flex
<div className="flex items-center justify-between">
<h1>{title}</h1>
<div>{actions}</div>
</div>
// 변경 후 - 좁은 화면에서 세로 적층
<div className="flex flex-wrap items-start justify-between gap-2 sm:items-center">
<h1>{title}</h1>
<div className="flex flex-wrap gap-2">{actions}</div>
</div>
flex-wrap을 추가하고 모바일 브레이크포인트에서 아이템이 세로로 쌓이도록 조정했다. sites insights 페이지의 헤더 액션 영역도 같은 이유로 wrap 처리를 추가했다. 수정 자체는 두 파일로 끝났는데, 이제 PageHeader를 사용하는 14개 페이지 전체에 자동으로 적용된다. 컴포넌트 통일의 부수효과가 딱 이런 경우다. 한 곳만 고치면 전체가 따라온다.
자동 생성 파이프라인 확인
새벽 작업 사이에 psy(심리 테스트 사이트) 쪽에서 일일 자동 생성 커밋이 올라온 걸 확인했다. animal-orchestra, competition-instinct, destiny-mythical-creature 세 개의 테스트가 새로 생성됐고, 커버 이미지(webp)와 JSON 콘텐츠 파일이 함께 커밋됐다. 이건 수동으로 손댄 게 아니라 매일 정해진 시간에 새 테스트를 생성해서 커밋하는 파이프라인이 정상 작동하고 있다는 신호다.
직접 확인한 것은 생성된 파일 구조가 올바른지, 커버 이미지가 제대로 들어갔는지 정도였다. 이상 없이 올라왔다. 파이프라인이 안정적으로 돌고 있을 때는 사실 이 커밋이 올라오는 걸 보는 것 자체가 확인 과정이다. 이게 빠지거나 구조가 이상하면 그때 파고드는 식이다.
이번 새벽 세션을 돌아보면 전부 "쌓아둔 것들 처리"였다. vtuber_guard 버그는 증상을 알면서도 재현 조건이 불명확해서 미루고 있었고, 어드민 UI 정비는 언제 한번 해야지 하던 것들이 목록에 올라와 있었다. 새벽 시간대는 배포 영향도 적고 다른 작업 요청도 없어서 이런 축적된 부채를 털기에 좋다. 결과물이 "0건", "통일", "안정화"처럼 눈에 안 띄는 단어들로 요약되는 작업들이지만, 이게 안 쌓이면 나중에 진짜 급한 것들을 처리할 때 배경 노이즈로 방해가 된다. 조용한 시간에 조용히 처리할 수 있어서 다행이었다.
🛒 이 글과 어울리는 추천 상품
*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.
댓글 0
첫 댓글 달아줘.