빈 배열 하나가 한도 도달을 일반 실패로 만들었다

새벽 두 시간 동안 프로젝트를 가리지 않고 잡이 전부 실패했다. 남은 문구는 한 줄이고 원인 자리가 비어 있었다. 그리고 그걸 고치자 공시 본문의 "429억원"이 전역 정지를 부를 수 있게 됐다

공유 LLM 큐에서 새벽 두 시간 동안 모든 프로젝트의 잡이 실패했다. 뉴스 일간 편집도 여섯 건 걸려 그날 호가 안 나갔다. 원인은 한도 도달인데, 그걸 알려 주는 문구가 빈 배열에 담겨 오는 경우를 못 읽고 있었다. 고치고 나니 이번엔 공시 본문의 숫자가 전역 정지를 부를 수 있게 됐다.

하려던 것

새벽 네 시 반부터 여섯 시 반까지 두 시간, 프로젝트를 가리지 않고 잡이 전부 실패했다. 뉴스의 일간 편집 잡 여섯 건도 여기 걸려서 그날 호가 안 나갔다.

로그에 남은 건 한 줄이었다.

claude 오류(success):

콜론 뒤가 비어 있다. 그리고 괄호 안이 success다. 오류인데 성공이라고 적혀 있고 원인은 없다.

어디서 막혔나

CLI 응답에 이런 봉투가 있었다. 오류 표시는 참인데, 오류 배열은 비어 있고, 설명은 다른 자리에 담겨 온다. 한도에 닿았을 때가 대표적이다.

우리 코드는 그 배열만 문구로 썼다. 그러니 이 봉투에서는 문구가 빈 문자열이 된다.

빈 문자열은 분류가 안 된다. 분류기는 문구를 보고 한도 도달인지 인증 문제인지 일반 오류인지 가르는데, 볼 게 없으니 일반 오류로 떨어진다.

여기서부터가 진짜 문제다. 한도 도달로 분류되면 워커는 잡을 큐로 되돌리고 30분 쉰다. 일반 실패로 분류되면 그 경로를 못 탄다. 대신 재시도 세 번을 쓰고 영구 실패로 굳는다.

그 재시도가 몇 초 만에 끝난다. 처리 시간이 1~2초고 재시도 간격이 없다. 그러니 한도에 닿은 잡이 잠깐 쉬었다 다시 오는 대신, 3초 만에 세 번 실패하고 죽는다. 그리고 그 결과가 멱등 키 캐시에 남는다. 같은 잡을 다시 넣어도 죽은 결과가 그대로 돌아온다.

빈 배열 하나가 “잠깐 기다려”를 “영구히 실패”로 바꿔 놓은 셈이다.

어떻게 풀었나

문구를 고르는 순서를 만들었다. 오류 배열을 먼저 보고, 비었으면 설명 자리를, 그것도 비었으면 표준 오류를 본다. 셋 다 비면 “메시지 없음”이라고 적는다. 적어도 콜론 뒤가 비지는 않는다.

여기서 한 가지를 갈랐다. 분류는 세 자리를 다 보고, 표시 문구만 하나를 고른다. 우선순위를 분류에까지 적용하면, 설명 자리에 담긴 본문 일부가 표준 오류에 있는 진짜 원인을 가린다. 보여 줄 문구를 고르는 일과 무엇인지 판정하는 일은 다른 일이다.

고치는 동안 주변에서 몇 개가 더 나왔다.

오류 배열이 빈 문자열 두 개짜리면 이어 붙인 결과가 구분자만 남은 문자열이 된다. 그게 “비었나” 검사를 통과해 버린다.

깨진 멀티바이트 문자와 NUL이 섞이면 데이터베이스가 행을 거절한다. 그러면 기록 자체가 실패해서 잡이 진행 중 상태로 굳는다. 이건 실패 경로뿐 아니라 성공 경로에도 필요한 정리였다.

문자열을 자르는 곳이 바이트 단위였다. 룬 경계에서 자르도록 바꿨다. 특히 발췌 함수는 모델이 산문을 뱉은 경로에서만 불리는데, 그쪽은 한글일 확률이 제일 높다. 자르는 길이 100을 3으로 나누면 나머지가 1이라 항상 깨지고 있었다.

예산 초과 알림 문구도 잘랐다. 안 자르면 텔레그램의 4,096자 상한에 걸려서 알림이 안 간다. 하필 사람이 반드시 봐야 하는 알림이 조용히 사라지는 자리였다.

그리고 고친 게 새 구멍을 만들었다

분류기가 한도 도달을 알아보는 방법 중에 429라는 숫자를 찾는 게 있었다. 전에는 오류 배열만 훑었으니 이 숫자가 본문에서 나올 일이 없었다.

이제는 설명 자리도 훑는다. 그 자리에는 모델 출력이 들어올 수 있다. 공시 요약 파이프라인이 이 큐를 쓴다. 공시 본문에 “429억원”이라는 말이 한 번만 나오면, 분류기가 그걸 한도 도달로 읽고 전역으로 30분을 멈춘다. 그리고 재시도가 그 정지를 계속 늘린다.

그래서 맨 숫자 대신 앞말이 붙은 형태 아홉 가지만 찾도록 좁혔다.

좁히고 나서 리뷰가 하나를 더 짚었다. 좁힌 목록에 (429)가 들어 있었는데, 회계에서 괄호는 음수 표기다. “영업손실 (429)억원”이 그대로 걸린다. 맨 괄호를 빼고 앞에 오류를 뜻하는 단어를 요구하도록 고쳤다. 회귀 테스트에 실제 표기 두 개를 넣었다.

인증 관련 키워드는 반대로 넓게 뒀다. 이쪽은 오탐이 나도 사람이 보면 풀리는데, 누락되면 안 풀린 채로 남는다.

배운 점