ETL 이 새벽 4시에 죽었다
월요일 아침, RSS 가 비어 있었다. 새벽 4시에 무슨 일이 있었는가.
월요일 아침 메일함을 열었는데 한국어 RSS 다이제스트가 비어 있었다.
처음엔 “한 번 거를 수도 있지” 했다. 화요일도 비었다. cron 로그를 보니 매일 새벽 4시 13분에 같은 줄에서 죽고 있었다.
Traceback (most recent call last):
...
File "/opt/rss-pipeline/fetch.py", line 84, in fetch
feed = feedparser.parse(url, request_headers=headers)
TimeoutError: [Errno 60] Operation timed out
원인은 한 줄
피드 30개 중 한 곳이 일요일부터 응답을 안 했다. feedparser.parse 는 기본 timeout 이 없다. 그 한 곳 때문에 전체 cron 이 3시간 매달려 있다가 systemd TimeoutSec 에 잘렸다. 나머지 29개는 아예 처리도 못 했다.
고친 것
requests.get(url, timeout=10)으로 직접 받아feedparser.parse(text)에 넣음 —feedparser.parse(url)은 쓰지 않는다.- 30개 피드를
concurrent.futures.ThreadPoolExecutor(max_workers=8)로 병렬화. 한 곳이 timeout 나도 27초면 다 끝남. - 실패한 피드는 다음 5회까지 재시도, 그 다음엔 자동 비활성. 알람만 띄움.
”왜 알람이 안 왔지?”
이게 더 아팠다. cron 실패를 메일로 받게 해놨는데 sendmail 이 같은 호스트에서 돌고 있었고, 호스트가 멈춰 있으니 알람도 못 나왔다. 알람 채널은 같은 머신 밖에 있어야 한다는 걸 그때 알았다.
지금은 알람을 텔레그램 봇으로 받는다. 메일은 보조.
다음에는 다르게 할 한 가지
feedparser.parse(url) 처럼 timeout 옵션이 없는 함수 는 일찍 끊어내야 한다. 사용 전에 signature 한 번 보고 timeout 키워드가 없으면 직접 fetch 로 우회한다. 외부 의존이 들어가는 모든 줄에서 동일하게.
🛒 이 글과 어울리는 추천 상품
위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.