sgkstudio.
엔지니어링

크롤러 세션 만료 추세, 표본 2개로 내린 판정이 하루 만에 뒤집혔다

크롤러 세션 만료가 짧아지는 추세라는 판정은 틀렸습니다. 로그인 두 번이 각각 55분·137분 만에 끊긴 것을 보고 추세를 적었는데, 바로 다음 날 같은 수집기가 158건을 모으는 동안 거부를 한 줄도 남기지 않았습니다. 이 글은 그 판정을 세운 과정, 반증이 4일 동안 묻혀 있던 이유, 그리고 아직 풀지 못한 진짜 질문까지 그대로 남긴 기록입니다.

2026-10-22판정 근거: 2026년 8월 10일 런 2개: 09:03 로그인 55분/14건, 20:22 로그인 137분/22건, 비교 기준 직전 정상 런 11시간/107건관측 수단: 수집 로그 hero_harvest.log 의 [N/250] 진행 줄과 중단·거부 줄을 런마다 셈반증: 8월 11일 13:20 런 158건 수집 · 중단·거부 0줄배제한 오답: 프로필 점검 코드(PR #849)는 8월 10일 08:38 머지로 이미 짧은 런에 적용돼 있었다반증이 묻힌 기간: 작업 목록 파일이 8월 10일 상태로 멈춰 4일 동안 읽히지 않았다미해결: 런 길이가 10~229건으로 흩어지는 원인은 아직 모른다

크롤러 세션 만료가 왜 갑자기 짧아진 것처럼 보였나?

크롤러 세션 만료가 짧아진 것처럼 보인 이유는, 하루에 연달아 짧게 끊긴 런 두 개를 추세로 읽었기 때문입니다. 실제로 짧아지고 있었던 게 아니라, 원래 길이가 들쭉날쭉한 런 가운데 짧은 쪽 둘이 하루에 몰렸을 뿐이었습니다. 다만 그날 밤에는 그렇게 보이지 않았습니다.

2026년 8월 10일은 수집이 잘 안 풀린 날이었습니다. 아침 08:20에 정해진 일정으로 시작한 배치가 108번째 항목(08:23:59)에서 세션을 잃고 멈췄습니다. 09:03에 다시 로그인했는데 55분 만에, 14건을 모으고 또 끊겼습니다. 20:22에 한 번 더 로그인했고, 이번에는 137분, 22건에서 끊겼습니다.

비교할 기준도 손에 있었습니다. 그 직전에 정상으로 끝난 런은 11시간 동안 107건을 모았습니다. 11시간 대 55분, 107건 대 14건이면 차이가 크게 보입니다. 같은 날 두 번 연속으로 1~2시간대에 끊겼다는 사실까지 더하면, 무언가 바뀌었다고 결론 내리기 쉬운 그림이었습니다.

통계 카드. 8월 10일 09:03 로그인 런 55분 14건, 20:22 로그인 런 137분 22건, 직전 정상 런 11시간 107건, 표본 수 2개
그날 밤 판정의 근거 전부: 런 2개와 비교 기준 1개

세션이 끊기면 비용이 큽니다. 이 사이트의 로그인 화면에는 키보드 보안 프로그램(안랩 E2E)이 붙어 있어서, 수집기가 자동으로 다시 로그인하려 해도 구조적으로 실패합니다. 세션이 끊길 때마다 사람이 직접 로그인해 줘야 수집이 이어집니다. 그래서 세션이 얼마나 오래 버티는지는 곧 사람이 하루에 몇 번 불려 나오는지와 같은 문제였습니다.

처음 의심한 것: 세션 수명이 짧아지는 추세

그날 22:42, 작업 목록 파일에 이렇게 적었습니다. “오늘 2회 재로그인 모두 1~2시간대 재사망, 09:03 로그인→55분/14건, 20:22 로그인→137분/22건. 직전 정상 런(11시간/107건) 대비 세션 수명이 뚜렷이 짧아진 상태.” 같은 내용을 커밋 메시지에도 “세션 생존시간 단축 추세”라고 남겼습니다.

오늘 2회 재로그인 모두 1~2시간대 재사망, 09:03 로그인→55분/14건, 20:22 로그인→137분/22건. 직전 정상 런(11시간/107건) 대비 세션 수명이 뚜렷이 짧아진 상태.

이 판정이 그럴듯했던 데는 이유가 있었습니다. 두 런 모두 1~2시간대에 끊겼고, 둘 다 비교 기준인 정상 런보다 훨씬 짧았습니다. “짧아지는 중”이라는 진단은 다음 행동까지 정해 줍니다. 무엇이 세션을 일찍 끊는지 찾는 쪽으로 수사 방향이 기울게 됩니다.

돌아보면 이 판정의 근거는 표본 두 개였습니다. 그날 밤에는 그 사실을 문제로 보지 않았습니다. 두 번 연속으로 같은 방향의 결과가 나오면 사람은 그것을 패턴으로 읽습니다. 게다가 그날 아침에는 세션 점검 코드를 새로 머지한 상태였기 때문에, “무언가 바뀐 날”이라는 인상이 더 강했습니다.

확인 수단: 수집 로그의 [N/250] 줄을 런마다 셌다

판정을 다시 들여다본 계기는 8월 15일이었습니다. 수집 상태를 확인하던 중, 작업 목록의 판정과 지금 돌고 있는 런의 모습이 맞지 않았습니다. 그래서 기억이나 메모 대신 로그를 직접 세기로 했습니다.

수집기는 항목 하나를 처리할 때마다 수집 로그 파일(hero_harvest.log)에 `[N/250]` 형식의 진행 줄을 남깁니다. 런 하나의 수집 건수는 그 런 구간에 찍힌 진행 줄 수와 같습니다. 같은 구간에서 중단이나 거부를 알리는 줄도 따로 셌습니다. 이 방식은 사람이 남긴 메모가 아니라 수집기가 스스로 찍은 기록이라, 판정을 내린 사람의 인상이 끼어들 자리가 없습니다.

8월 10일부터 15일까지의 런을 이 기준으로 다시 셌습니다. 결과는 아래 표와 같습니다.

표. 런별 수집 건수와 중단·거부 줄. 8월 10일 20:22 22건 5줄, 8월 11일 13:20 158건 0줄, 8월 13일 08:20 46건 0줄, 8월 13일 15:09 10건 0줄, 8월 15일 09:38 50건 이상 진행 중 0줄
로그를 직접 센 런별 실측: 8월 11일 런이 표의 중심이다

8월 10일 20:22 런은 22건을 모으는 동안 중단·거부 줄을 5줄 남겼습니다. 판정의 근거가 된 바로 그 런입니다. 그런데 그다음 줄이 문제였습니다. 8월 11일 13:20에 시작한 런은 158건을 모았고, 중단·거부 줄은 0줄이었습니다.

알리바이 1: 다음 날 158건짜리 런은 왜 추세를 뒤집었나?

세션 수명이 정말 짧아지는 중이었다면, 다음 날 런은 더 짧거나 적어도 비슷해야 했습니다. 실제로는 정반대였습니다. “단축 추세”를 적은 바로 다음 날, 직전 정상 런의 107건보다도 많은 158건을 거부 없이 끝낸 런이 나왔습니다. 추세 가설은 하루 만에 반증됐습니다.

그 뒤의 런도 한 방향을 가리키지 않았습니다. 8월 13일 08:20 런은 46건, 같은 날 15:09 런은 10건이었습니다. 10건은 8월 10일의 두 런보다도 짧습니다. 8월 15일 09:38 런은 50건을 넘긴 채 계속 돌고 있었습니다. 짧은 런과 긴 런이 순서 없이 섞여 나왔습니다.

막대 그래프. 8월 10일 09:03 14건, 8월 10일 20:22 22건, 직전 정상 런 107건, 8월 11일 13:20 158건, 8월 13일 08:20 46건, 8월 13일 15:09 10건, 8월 15일 09:38 50건 이상
런 하나가 모은 건수: 짧은 런과 긴 런이 순서 없이 섞인다

이 막대를 시간 순서로 보면 “점점 짧아진다”는 선을 그을 수 없습니다. 14건과 22건 바로 뒤에 158건이 있고, 그 뒤에 다시 10건이 있습니다. 이 런 길이는 넓게 보면 10~229건 범위로 흩어집니다. 이 정도 분산 폭이면 짧은 런 두 개가 연달아 나오는 일은 우연으로도 흔합니다. 8월 10일 밤의 두 런은 추세의 시작이 아니라, 흩어진 분포에서 아래쪽 두 점을 연달아 뽑은 결과였습니다.

알리바이 2: 프로필 점검 코드 덕분에 좋아졌나?

추세가 반증되자 곧바로 다른 설명이 떠올랐습니다. 8월 10일에 세션 점검 코드를 고쳐 머지했으니, 8월 11일부터 런이 길어진 것은 그 코드 덕분이 아니냐는 설명입니다. 시간 순서만 보면 아주 그럴듯합니다. 그래서 이 설명은 원인을 찾기 전에 먼저 걸러 둘 필요가 있었습니다.

그 코드가 하는 일은 이렇습니다. 원래 세션 점검 함수 `check_session()` 은 랭킹 목록 화면에 들어갈 수 있는지만 확인했습니다. 그런데 목록은 열리는데 랭커 프로필을 열면 로그인 화면으로 튕기는 경우가 있었습니다. 목록 접근 권한과 프로필 조회 권한이 따로 만료되는 셈입니다. PR #849는 목록 확인을 통과한 뒤 실제 랭커 1명의 프로필 페이지까지 열어 보고, 로그인·거부 화면으로 튀지 않는지 한 번 더 확인하는 2차 점검을 넣었습니다.

흐름도. 세션 점검에서 랭킹 목록 접근이 실패하면 완전 세션 사망으로 자동 재로그인 시도가 키보드 보안에 막혀 사람이 직접 로그인. 목록 접근 성공 후 랭커 1명 프로필 열기에서 로그인·거부 화면이면 부분 사망, 정상이면 수집 계속
세션이 죽는 두 가지 모양: 새 점검 코드는 오른쪽 아래 경로만 맡는다

시간을 맞춰 보면 이 설명은 성립하지 않습니다. PR #849는 커밋 0fd81137로 2026년 8월 10일 08:38에 머지됐습니다. 그날 09:03 런과 20:22 런은 이미 새 코드 위에서 돌았습니다. 즉 22건에서 끊긴 짧은 런에도, 다음 날 158건을 간 긴 런에도 같은 코드가 적용돼 있었습니다. 같은 코드 아래에서 짧은 런과 긴 런이 둘 다 나왔으니, 그 코드가 차이를 만들었다고 말할 수 없습니다.

이 코드가 막는 범위도 애초에 좁았습니다. 위 그림처럼 세션이 죽는 모양은 두 가지입니다. 목록은 살고 프로필만 죽는 부분 사망은 새 점검이 잡아냅니다. 목록과 프로필이 함께 죽는 완전 세션 사망은 원래 점검으로도 “죽었다”고 정확히 판정하고, 그다음 자동 재로그인이 키보드 보안에 막힙니다. 이 경우는 새 코드가 전혀 건드리지 않고, 여전히 사람이 직접 로그인하는 길밖에 없습니다.

진짜 원인: 분산이 큰 데이터와 4일 동안 멈춘 작업 목록

잘못된 판정의 원인은 두 겹이었습니다. 첫째는 분산이 큰 데이터에서 표본 두 개로 추세를 읽은 일입니다. 런 길이가 10~229건 사이로 흩어지는 프로세스에서 두 점은 방향을 말해 주지 않습니다. 반대 방향 표본이 하나만 나와도 무너지는 판정이었고, 실제로 하루 뒤에 나왔습니다.

둘째가 더 아팠습니다. 반증은 8월 11일에 이미 로그에 있었는데, 8월 15일까지 4일 동안 아무도 그것을 읽지 않았습니다. 작업 목록 파일이 8월 10일 상태에서 멈춰 있었기 때문입니다. 작업을 새로 시작할 때마다 그 파일을 “지금 상태”로 읽었고, 거기에는 여전히 “세션 수명이 뚜렷이 짧아진 상태”라고 적혀 있었습니다. 이미 죽은 판정이 4일 동안 현재형으로 남아 수사 방향을 붙잡고 있던 셈입니다.

흐름도. 8월 10일 08:38 PR 849 머지, 09:03 로그인 55분 14건에서 끊김, 20:22 로그인 137분 22건에서 끊김, 22:42 작업 목록에 단축 추세 기록, 8월 11일 13:20 런 158건 거부 0줄, 작업 목록은 8월 10일 상태로 멈춰 4일 동안 아무도 안 읽음, 8월 15일 반증 발견
판정이 세워지고, 반증되고, 4일 동안 묻힌 순서

한 가지는 분명히 해 둡니다. 여기서 찾은 원인은 “판정이 왜 틀렸나”의 원인입니다. “왜 어떤 런은 짧고 어떤 런은 긴가”의 원인은 아직 모릅니다. 처음부터 답을 알고 있었던 것처럼 쓰면 이 둘이 섞이기 쉬운데, 이 글에서 확정한 것은 앞쪽뿐입니다.

고친 방법: 판정을 거두고 정상 런을 대조군으로 모은다

먼저 “세션 수명 단축 추세”라는 판정을 거뒀습니다. 근거였던 두 런은 그대로 기록에 남기되, 같은 표에 그 뒤의 런을 나란히 두어 짧은 런이 흩어진 분포의 일부라는 점을 함께 보이게 했습니다. 판정 하나를 지우는 대신 반증을 같은 자리에 붙여 두면, 나중에 같은 숫자를 다시 보는 사람도 같은 결론으로 미끄러지지 않습니다.

다음으로 “#849 덕분에 좋아졌다”는 설명을 기록에 미리 배제해 두었습니다. 머지 시각과 런 시각을 나란히 적어, 누가 다시 이 설명을 꺼내도 시간 순서로 바로 걸러지게 했습니다. 매력적인 오답은 한 번 떠오르면 또 떠오릅니다. 반증을 남겨 두지 않으면 다음 사람이 같은 길을 다시 걷습니다.

마지막으로 수사 방향을 바꿨습니다. 짧은 런의 원인을 찾으려면 비교할 긴 런이 필요합니다. 8월 15일 당시 돌고 있던 런은 거부 없이 길게 가고 있었고, 이런 런이 곧 “정상 런”의 대조군 데이터가 됩니다. 짧은 런만 들여다보던 방식에서, 짧은 런과 긴 런을 같은 기준으로 나란히 모으는 방식으로 옮겼습니다.

같은 시기에 비슷한 모양의 문제가 하나 더 있었습니다. PR #849가 `check_session()` 의 반환값에 `profile_probe` 필드를 더하면서, 옛 반환 형태를 기대하던 기존 단위 테스트 2건이 머지 시점부터 실패했습니다. 이 실패는 여러 번 작업 목록에 “테스트 2건 실패”로 기록만 되고, 실제 수정은 8월 17일 커밋 707b8a8b에서야 들어갔습니다. 8월 10일부터 17일까지 테스트가 빨간 상태로 남아 있었고, 빨간 테스트 묶음은 그 사이에 생길 수 있는 진짜 회귀를 가리는 잡음이 됩니다.

같은 실수를 막는 장치는 무엇인가?

이번 일에서 남긴 장치는 두 가지 점검 질문과 두 가지 습관입니다. 아직 코드로 강제하는 단계는 아니고, 판정을 적는 순간과 작업을 여는 순간에 거치는 점검 목록입니다. 그 한계는 숨기지 않고 적어 둡니다.

통계 카드. 런 길이의 분산 폭 10~229건, 반대 방향 표본 158건, 반증이 묻혀 있던 기간 4일
추세를 적기 전에 거칠 두 질문과, 이번에 그 질문을 건너뛴 대가
  • (a) 표본 수가 분산 폭에 비해 충분한가: 런 길이가 10~229건으로 흩어지는 데이터에서 런 2개는 추세가 아니다
  • (b) 반대 방향 표본이 이미 나와 있는가: 이번에는 하루 뒤에 158건짜리 런이 나왔고, 작업 목록만 갱신했어도 바로 보였다
  • 작업을 열 때 작업 목록의 판정 문장을 현재 상태로 믿지 않는다. 판정을 적은 날짜를 보고, 그 뒤의 로그를 먼저 센다
  • PR이 스스로 깨뜨린 기존 테스트는 같은 PR 안에서 고친다. 테스트 묶음 전체 결과를 정기로 확인했다면 8일이 아니라 한 번의 작업 안에서 잡혔을 문제다

네 항목 가운데 앞의 두 질문은 이 데이터에만 해당하지 않습니다. 광고 성과든 서버 응답 시간이든, 값이 넓게 흩어지는 지표에서 “요즘 나빠졌다”는 말이 나오면 같은 두 질문을 그대로 쓸 수 있습니다. 비슷한 함정을 다른 데이터에서 다룬 글로 약세장 표본 하나로 필터를 판단한 기록도 함께 참고할 만합니다.

뒤의 두 습관은 기록이 멈추는 문제를 다룹니다. 판정이 틀릴 수 있다는 점보다, 틀린 판정이 갱신되지 않은 채 남는 점이 더 큰 비용을 냈습니다. 세션이 끝나도 맥락이 이어지도록 문서를 나누는 방법은 작업 맥락을 문서 4개로 유지하는 구조에 따로 정리해 두었습니다.

아직 남은 질문: 왜 어떤 런은 10건, 어떤 런은 158건인가?

판정은 바로잡았지만 진짜 질문은 그대로입니다. 같은 수집기인데 어떤 런은 10건에서 끝나고 어떤 런은 158건을 갑니다. 이 차이를 만드는 원인은 2026년 8월 15일 기준으로 확정하지 못했습니다.

이미 기각한 가설도 적어 둡니다. 요청 속도(페이스), 랭킹 등급(티어), 특정 프로필 하나하나를 원인으로 본 가설은 앞선 조사에서 각각 기각했습니다. 사이트가 요청을 거부하는 현상은 원인이 아니라 세션이 끊긴 뒤에 나타나는 증상이라는 점도 앞서 확인했습니다. 남은 후보는 개별 요인이 아니라 그 조합이거나, 아직 관측하지 못한 다른 무엇입니다.

그래서 지금 할 일은 새 가설을 서둘러 세우는 일이 아니라 대조군을 쌓는 일입니다. 거부 없이 길게 가는 정상 런의 데이터가 모이면, 짧은 런과 무엇이 다른지 같은 기준으로 비교할 수 있습니다. 표본 두 개로 추세를 세웠던 실수를 같은 방식으로 반복하지 않으려면, 이번에는 충분히 모일 때까지 기다리는 쪽이 맞습니다.

크롤러나 업무 자동화가 들쭉날쭉하게 멈추는데 원인을 어디서부터 볼지 막막하다면, 로그를 어떤 단위로 세어야 하는지부터 함께 정리해 볼 수 있습니다. 필요하면 상담으로 문의해 주세요.

같은 방식으로 우리 업무를 재보고 싶다면

이 글에 쓴 계측·판정·자동화는 저희가 실제로 매일 돌리는 방식 그대로입니다. 어떤 작업을 자동화할 수 있고 어디를 사람이 잡아야 하는지, 현재 업무 흐름을 놓고 같이 짚어 드립니다.

새 글이 올라오면 알려 드립니다

이런 계측 기록을 새로 쓰면 메일로 한 통 보냅니다. 광고나 판촉은 보내지 않습니다.