남의 서버를 두드릴 때
품앗이가 AI와 함께 업무 자동화를 하며 남긴 실패 기록을 다른 조직이 다시 쓸 수 있게 옮긴 글입니다. 묶음 전체는 API 없는 업무 프로그램 자동화에서 볼 수 있습니다.
요지
자료 수집, 링크 검사, 포털 조회처럼 우리 것이 아닌 서버에 요청을 보내는 일은 그 서버의 사정에 기대는 일입니다. 남의 서버는 우리 일정에 맞춰 존재하지 않고, 사고가 나면 그 책임은 AI가 아니라 조직이 집니다. 그래서 요청의 상한은 처음부터 걸어 두고, 실패의 대가가 조직에 돌아오는 시스템에서는 재시도를 한 번으로 봅니다.
1. 요청 간격, 동시 접속, 총량 상한은 처음부터
우리 기록에 따르면 어느 새벽, 한 협동조합의 자료를 수집하던 작업이 그 조합 홈페이지를 관리하는 업체의 낡은 서버를 눌러 홈페이지가 응답하지 않게 됐습니다. 신청서 상세 1,040건을 0.08초 간격, 그러니까 초당 12건으로 읽었고, 같은 시간에 외부 링크 검사가 실패한 링크를 되풀이해 다시 확인하고 있었습니다. 하나하나는 작아 보여도 낡은 서버에는 쌓이면 무겁습니다.
그 뒤로 우리 것이 아닌 서버에는 다음을 기본값으로 둡니다.
- 요청 사이 간격은 1초 이상, 동시 접속은 1, 서버마다 총량 상한을 둡니다.
- 링크 검사는 요청 하나로 머리만 확인하고, 실패해도 다시 시도하지 않습니다. 우리 검증의 편의를 남의 서버가 부담하게 하지 않습니다.
- 대량 수집은 한 번에 끝내지 말고 나눕니다. 시작 전에 같은 서버로 나가는 다른 작업이 있는지 먼저 보는데, 다른 AI가 돌리는 작업까지 셉니다.
- 서버 오류나 응답 지연이 한 번이라도 보이면 바로 전부 멈춥니다. 재시도로 상태를 확인하려는 그 요청이 마지막 일격이 됩니다.
- 같은 서버에 다시 들어갈 때가 가장 위험합니다. 「저번엔 괜찮았으니까」로 상한을 풀지 않습니다.
이 규칙을 문서로만 두었더니 다시 어긴 일이 있었습니다. 그래서 AI가 쓰는 명령에 상한 없이 남의 서버를 반복 호출하는 모양이 보이면 막는 장치를 두었고, 그 장치가 명령줄만 보느라 스크립트 안의 요청을 놓친 뒤에는 스크립트 안의 요청도 저절로 늦추는 장치를 더했습니다. 상한을 걸면 남의 서버에서도 일은 끝납니다. 첫 사고 직후 그 서버에서 이미지 746개를 다시 받아야 했을 때는 요청 사이 1초, 재시도 없음, 연속 실패 5회면 자동 중단을 걸어 14분 만에 서버 탈 없이 끝냈습니다.
빈 응답을 실패로 세면 재시도가 폭주한다
다른 협동조합에서는 업무 프로그램을 해지하기 전에 쌓인 자료를 전부 받아 두려 했습니다. 월 단위로 받고, 실패하면 7일, 다시 하루 단위로 쪼개 받게 짰습니다. 그런데 서버는 자료가 없는 기간에 엑셀 대신 조회 화면을 돌려줬고, 어떤 보고서는 기능 자체가 없어 404를 돌려줬습니다. 두 경우 모두 「엑셀이 아니니 실패」로 처리돼 하루 단위까지 쪼개졌고, 한 보고서에서만 2,479번의 헛요청이 나갔습니다. 업체가 우리 계정과 접속 주소를 막았습니다. 그 주소는 매장 PC와 같이 쓰던 회선이라 매장 업무 회선까지 함께 막혔습니다.
- 응답은 셋으로 가릅니다. 첨부 파일이 오면 받음, 정상 응답인데 첨부가 없으면 자료 없음, 시간 초과나 연결 오류나 서버 오류면 실패입니다. 쪼개 다시 받는 것은 실패에만 합니다.
- 404 같은 요청 오류는 쪼개도 낫지 않으니 바로 멈추고 다른 통로를 찾습니다.
- 남의 운영 서버에서 대량으로 받을 때는 업체에 미리 알리고, 상한을 걸고, 매장 회선이 아닌 곳에서 받습니다. 해지 전 회수라도 「백업을 받겠다」는 한 줄을 먼저 보냅니다.
2. 실패의 대가가 조직에 가면 재시도는 한 번이다
한 회계 ERP의 공개 API는 로그인에 연속 10번 실패하면 그 매장의 접속 주소 전체를 영구 차단합니다. 우리가 평소 쓰는 API들은 실패해도 「너무 많이 요청했다」나 「인증이 안 됐다」는 답이 올 뿐이라 다시 시도해도 비용이 거의 없습니다. 그래서 「안 되면 몇 번 더 해 본다」가 몸에 뱁니다. 그러나 ERP에서는 인증 실패 자체가 횟수로 쌓이고, 벌은 개발자 한 명이 아니라 조직 전체에 떨어집니다. 매장 ERP가 막히면 회계와 매입 업무가 통째로 섭니다.
- 인증 시험은 한 번만 하고, 실패하면 원인을 밝히기 전에 다시 시도하지 않습니다.
- 원인은 응답 본문에서 읽습니다. 우리 경우엔 「인증 키가 유효하지 않다」는 문장이 그대로 와 있어서, 다시 시도해 알아낼 것이 없었습니다.
- 로그인이 아닌 조회부터 해서 통신 경로와 회사 코드가 맞는지 먼저 확인하고, 로그인은 그다음에 한 번 합니다.
- 받은 세션은 다시 씁니다. 그 ERP는 로그인을 10분에 한 번만 받으므로, 요청할 때마다 로그인하는 코드는 그 자체로 차단을 부릅니다.
은행과 카드 결제, 국세청과 4대 보험, 공공기관 인증도 같은 칸에 넣습니다. 외부 시스템에 붙기 전에 「실패의 대가가 누구에게 가는가」를 먼저 봅니다. 나에게만 오면 다시 시도해도 되고, 조직에 가면 한 번입니다.
3. 화면 긁기보다 세션으로
다운로드는 로그인 세션을 이어받아 직접 요청한다
한 의료사협이 쓰는 ASP.NET 계열 업무 포털에서 화면 없는 브라우저로 「버튼 눌러 파일 받기」를 하다가 세 번 깨졌습니다. 기간을 길게 잡으니 서버가 파일을 만드는 동안 시간이 초과됐고, 버튼을 누르니 브라우저가 다운로드를 페이지 이동처럼 다루다 멈췄고, 저장 폴더를 지정해도 파일이 어디에도 떨어지지 않았습니다.
되는 방법은 일을 나누는 것이었습니다. 브라우저 자동화는 로그인과 화면 입력 상태를 만드는 데까지만 쓰고, 다운로드는 그 브라우저의 세션 쿠키와 입력 폼 전체를 그대로 담아 직접 요청으로 보냈습니다. 응답이 엑셀이면 파일이고, 화면 문서가 오면 「자료 없음」 같은 안내입니다.
쿠키 챌린지와 봇 챌린지
- 국내 사이트 가운데 자바스크립트로 쿠키를 계산하게 하는 곳은 단순 요청 도구로는 넘지 못합니다. 프로필을 유지하는 화면 없는 크롬을 두 번 띄워, 첫 번째로 쿠키를 통과하고 두 번째로 본문을 받습니다.
- CDN의 봇 챌린지는 화면 없는 브라우저만 막는 경우가 있습니다. 같은 페이지를 가상 화면 위의 일반 크롬으로 열자 몇 초 만에 통과했습니다. 정적인 첫 화면만 보고 통과했다고 판단하지 말고 실제로 쓸 화면에서 확인합니다.
- 공식 API가 없는 서비스는 「늘 켜 둔 크롬, 유지되는 프로필, 원격 제어」 묶음으로 다룹니다. 구글 로그인을 하는 동안에는 원격 제어 통로를 꺼야 로그인이 됩니다. 서비스 내부 API를 부를 때는 브라우저 밖에서 따로 요청하지 말고 페이지 안에서 부릅니다. 브라우저가 붙이는 정보가 실려야 통과합니다.
일회용 링크와 남의 PC 로그인
- 이메일 확인 링크 같은 일회용 링크를 「상태만 보자」며 요청 도구로 먼저 찌르면 그 순간 소진되므로, 첫 열기는 브라우저로 합니다.
- 남의 윈도 PC 브라우저에 로그인돼 있는 세션은 원격에서 이어받을 수 없습니다. 쿠키 암호가 그 사용자 계정에 묶여 있어 프로필을 복사해도 로그아웃 상태로 열립니다. 그 계정으로 할 일은 그 사람이 직접 누르거나, 우리가 읽을 수 있는 주소를 목적지로 추가해 돌아갑니다.
도구 메모
- 남의 서버용 스크립트에 넣을 것: 순차 실행, 요청 사이 1초, 요청마다 시간 제한, 재시도 없음, 연속 실패 N회면 중단.
- 응답 판정: 첨부 헤더나 엑셀 파일 머리 바이트로 「받음」, 정상 응답인데 화면 문서면 「자료 없음」.
- ASP.NET 계열 폼을 직접 보낼 때는
__VIEWSTATE같은 숨은 상태값까지 폼 전체를 직렬화한다.