"[260903] 야간 크래시 하나가 부른 하루 종일의 뒤처리"
어젯밤 배선 실수로 밤새 못 돈 배치를 아침에 발견해 복구하다가, 우회 경로의 허점과 이틀째 재발한 테스트 오염 버그까지 같이 잡았습니다
밤새 열 시간 동안 한 번도 못 끝난 배치
어제 낮에 장중 관측 파이프라인을 새로 배선하면서, 모델을 고르는 함수 안의 코드 한 줄을 실수로 조건문 안으로 옮겨버렸습니다.
문제는 그 코드가 매일 밤 정상적으로 도는 프로덕션 배치에서도 똑같이 쓰인다는 점이었습니다. 조건이 안 걸리는 이 경로에서는 변수가 정의조차 안 된 채로 넘어가 버그가 터졌습니다.
밤 8시부터 다음 날 아침 6시까지, 5분마다 자동으로 재시도했는데 매번 같은 자리에서 즉시 죽었습니다. 열 시간 동안 백 번 가까이 시도했지만 단 한 번도 끝까지 못 갔습니다.
자체적으로 이상을 알리는 장치가 없었던 탓에, 아침에 사람이 직접 "밤새 별일 없었냐"고 물어보고서야 발견됐습니다. 원인 코드 한 줄을 되돌려 바로 고쳤고, 상주 프로세스들을 전부 재시작했습니다.
기존 회귀 테스트 천 몇백 건이 이 버그를 못 잡은 이유도 확인했습니다. 문제가 된 함수 자체를 통째로 가짜로 바꿔치기하는 테스트만 있어서, 진짜 내부 로직을 실행해보는 테스트가 하나도 없었습니다.
그래서 그 함수의 기본 경로를 실제로 실행하는 테스트를 새로 만들었습니다. 수선 전 코드로 되돌려서 같은 오류로 정말 실패하는지까지 확인한 뒤에야 통과 상태로 커밋했습니다.
복구 과정에서 튀어나온 우회 경로의 허점
배치가 밤새 못 돌았다는 건, 아침 시점에 매매 판단 근거가 이틀 전 것에서 멈춰 있다는 뜻이었습니다.
무거운 모델을 다시 처음부터 돌려 오후까지 완주시키기로 하고, 그동안은 낮 시간대 자동거래 라운드를 걸러내는 안전장치에 기대기로 했습니다.
모델이 오후에 완주하자, 그 결과로 그날의 매매 기준을 다시 확정하는 스크립트를 돌리고 수동으로 거래 라운드를 한 번 트리거했습니다.
그런데 이 수동 트리거가 전부 무발주로 실패했습니다. 원인을 보니, 정기 자동 실행에서만 써야 할 표식이 실행 유닛 자체에 고정으로 박혀 있어서 수동 실행도 "정기 라운드인데 너무 늦게 도착했다"는 지연 판정에 걸려 차단된 것이었습니다.
우회 경로(더 낮은 단계에서 직접 실행)를 찾아 다시 트리거하니 정상적으로 처리됐습니다. 다만 이 허점 자체는 나중에 정식으로 수선이 필요한 항목으로 남겨뒀습니다.
실전 계좌에서도 같은 계열의 사고가 있었다
낮 동안 자동거래 타이머 몇 개를 잠깐 꺼뒀는데, 그중 하나가 사람이 모르던 별도의 자동 재기동 장치 때문에 조용히 다시 켜졌습니다.
그 결과 실전 계좌가 이틀 전 기준으로 굳어 있던 매매 기준으로 거래를 몇 건 내버렸습니다. AI에게 안전성 검증을 맡겼더니, 주문 실행/안전장치 계층(새 창)에서 회전량을 묶는 장치와 손실 상한선 같은 안전장치들은 전부 정상 작동했고 실제로 있을 수 있는 손실 폭도 매우 작은 수준이라는 판정이 나왔습니다.
이 판정을 근거로, 이미 나간 주문은 되돌리지 않기로 했습니다.
다만 이 사고를 조사하다가 비슷한 계열의 두 번째 위험도 함께 찾아냈습니다. 아침에 사람이 직접 등록해 둔 복구용 트리거 하나가, 알고 보니 같은 방식으로 타이머를 되살릴 수 있는 장치였습니다.
지금 끄면 오후 자동거래 재개 자체가 무산되는 상황이라, 유지할지 여부를 사람에게 직접 확인했습니다. 오후 재개를 원한다는 답을 받아 그대로 뒀습니다.
앞으로 뭔가를 잠깐 정지시킬 때는, 그걸 되살릴 수 있는 다른 자동화가 또 있는지부터 먼저 전부 찾아본 뒤에 함께 다뤄야 한다는 교훈으로 남았습니다.
이틀 연속 재발한 원장 오염, 결국 뿌리를 찾았다
어제 모의투자 계좌 하나에서 정체불명의 유령 거래 기록이 발견됐는데, 정확한 원인을 못 찾고 넘어갔던 일이 있습니다.
오늘 같은 증상이 또 나타났고, 이번엔 재발 시점을 거꾸로 추적해서 뿌리를 찾아냈습니다. 범인은 회귀 테스트 파일 하나였습니다.
이 테스트가 주문 체결을 기록하는 내부 함수의 정상 처리 경로를 가짜로 바꿔치기하지 않고 그대로 열어둔 채로 돌고 있었습니다. 그래서 전체 테스트를 한 번 돌릴 때마다 실제 운영 데이터베이스에 가짜 거래가 몇 건씩 섞여 들어가고 있었던 겁니다.
오염된 기록을 백업해두고 정확히 골라내 지운 뒤, 실제 보유 내역과 다시 맞춰봤습니다.
테스트 코드도 그 함수를 제대로 격리하도록 고쳤습니다. 그리고 이런 사고가 반복되지 않도록, 운영 중 새로 생기는 데이터베이스 파일은 테스트 격리 대상 목록에 곧바로 등록하는 규칙도 다시 한번 챙겼습니다.
같은 하루에 우연히 전체 테스트를 장중에 돌렸다가 나온 다수의 실패 보고도 살펴봤는데, 이건 진짜 버그가 아니라 장중에 프로덕션이 실제로 쓰고 있는 파일을 테스트가 오탐한 것으로 확인됐습니다. 전체 회귀 테스트는 장이 열려 있는 시간에는 돌리지 않기로 다시 정리했습니다.