WANY의 무료 배포 수집 시스템에서는 “무료”라는 표현을 찾는 것과 신뢰할 수 있는 목록을 만드는 일이 달랐다. 받을 수 있는 항목인지 확인하는 일, 정상가를 표시하는 일, 외부 요청이 제한됐을 때 다음 실행을 처리하는 일을 따로 다뤄야 했다.
Epic Free Games의 가격 처리와 모바일 게임·앱 후보 탐색에서는 서로 다른 시점에 세 가지 문제를 해결했다. 외부 게시물의 무료 표현을 어디까지 믿을지, 가격 값을 어떻게 해석할지, 요청 제한을 다음 실행에 어떻게 이어갈지가 각각 다른 판단을 요구했다.
무료라는 표현은 후보를 찾는 단서였다
후보 게시물에는 원래부터 무료인 앱도 있고, 여러 Store 링크가 함께 들어가기도 했다. 제목에 free apps라고 쓰여 있어도 모든 링크가 기간 한정 무료배포라는 뜻은 아니었다.
그래서 Store 링크를 찾는 단계와 배포 후보로 인정하는 단계를 분리했다. 유료 가격에서 무료로 내려갔다는 표현, 무료 기간이 한정돼 있다는 표현, 최근 유료로 관측한 가격과 현재 무료 신호를 구분했다. $4.99 → Free와 free until …은 서로 다른 단서이고, free 하나만으로는 이 근거를 부여하지 않았다.
링크가 여러 개인 게시물에서는 각 링크 주변의 문장을 따로 확인하도록 했다. 링크가 하나이고 제목에 강한 근거가 있을 때는 제목도 사용할 수 있지만, 제목의 무료 표현을 여러 앱에 한꺼번에 적용하지 않도록 바꿨다. 이전 규칙으로 저장된 자동 후보에도 같은 검사를 적용했다.
이 단계는 후보를 고르는 과정이다. 게시물의 표현이 현재 가격을 대신하지는 않는다. 실제 목록의 무료 상태는 공식 Store 확인으로 이어진다. 지금 받을 수 있는 항목은 무료 게임 페이지에서 확인할 수 있다.
₩190으로 보이던 가격은 변환 방식의 문제였다
정상가를 붙인 화면에는 Epic 한국 가격이 ₩190, ₩153처럼 표시됐다. 당시 코드는 응답의 originalPrice를 통화와 관계없이 100으로 나누고 있었다.
당시 수정한 코드는 먼저 유효한 fmtPrice.originalPrice가 있으면 그 표시값을 사용한다. 직접 변환해야 할 때는 응답의 통화 코드와 자릿수를 확인한다. 당시 코드의 기본 자릿수는 KRW·JPY 0, USD·EUR·GBP 2였다. 요청 지역만 보고 통화를 고정하지도 않았다.
새 계산만 고치면 이전에 저장한 잘못된 가격이 다시 나타날 수 있었다. 새 가격에 변환 버전을 남기고 이전 방식의 Epic 가격은 표시하지 않도록 구분했다. 회귀 검사에도 KRW 변환, USD 응답, 공식 표시값 사용, 이전 저장값의 비노출을 포함했다.
여기서 확인한 것은 금액을 해석하는 코드와 오래된 값의 처리다. 처음 보인 숫자만으로 특정 게임의 정확한 정상가까지 확정할 수는 없다.
요청 제한도 다음 실행까지 이어져야 했다
Reddit RSS 요청 상태에는 HTTP 429가 기록됐다. 주기적으로 실행되는 수집기에서 제한 상태를 보관하지 않으면 다음 실행이 다시 같은 요청을 보낼 수 있었다.
처리 코드는 Retry-After와 rate-limit reset 정보 등을 확인해 대기 시간을 계산하고, 여유 시간을 더한 다음 요청 가능 시각을 저장하도록 바뀌었다. 다음 실행이 그 시각보다 빠르면 새 요청을 보내지 않고 대기 상태로 끝낸다. 외부 응답의 제한을 실행 사이에도 유지하는 방식이다.
요청 실패와 마지막 정상 수집 기록도 분리했다. 성공했을 때만 성공 시각을 갱신하고, 429나 새 결과가 없는 상황에서 이전 성공 기록과 후보 관련 값을 무조건 지우지 않도록 했다. 이 처리는 RSS 응답에 적용한 것이며 OAuth Data API의 특정 제한 수치를 그대로 가져온 설정은 아니다.
429의 정확한 원인과 변경 후 제한이 완전히 사라졌는지는 단정하지 않는다. 무료 표현은 탐색의 단서로, 가격은 통화 정보에 맞춰, 제한 응답은 다음 실행의 조건으로 처리한 것이 이 구축 사례에서 바뀐 부분이다.