같은 파이프라인인데 절반만 실패했습니다
릴스 자동 게시 파이프라인에서 이상한 패턴이 보였습니다. 영문 슬러그로 된 이미지와 릴스는 정상적으로 게시됐습니다. 그런데 띠(zodiac)와 일주(ilju) 콘텐츠처럼 슬러그가 한글인 릴스는 전부 실패했습니다.
실패하는 방식도 특이했습니다. 영상이 처리되다가 멈춘 게 아니었습니다. 미디어 컨테이너를 만들고 플랫폼이 영상을 가져가는 수집(ingest) 단계에서 상태가 곧바로 ERROR로 떨어졌습니다. 영상 인코딩이나 길이, 용량을 의심하기 쉬운 상황이었지만, 실패를 가르는 기준은 콘텐츠 종류가 아니라 슬러그에 쓰인 문자였습니다.
여러분의 파이프라인이 외부 서비스에 URL을 넘길 때, 그 URL 경로에 비 ASCII 문자가 그대로 들어가 있지는 않습니까?
브라우저가 대신 해주던 일
제 쪽에서는 한글 경로 URL이 멀쩡해 보였습니다. 브라우저 주소창에 붙여 넣으면 열리고, 파일도 서버에 정상적으로 올라가 있었습니다. 브라우저는 보내기 전에 경로를 알아서 인코딩해 주기 때문입니다.
플랫폼 쪽 미디어 수집기는 그렇게 해주지 않았습니다. 인코딩되지 않은 UTF-8이 들어간 video_url을 받으면 가져오기를 시도하지 않고 바로 거부했습니다. 영문 슬러그는 애초에 인코딩할 문자가 없으니 문제가 드러나지 않았고, 그래서 이 버그는 한글 콘텐츠에서만 보였습니다.
고칠 자리를 고르는 문제
당신이라면 슬러그를 영문으로 바꾸시겠습니까, 아니면 URL을 넘기는 곳을 고치시겠습니까?
저는 후자를 골랐습니다. 영상, 이미지, 커버 URL은 모두 하나의 게시 함수를 지나갑니다. 그 지점에서 URL의 경로 부분에만 urllib.parse.quote를 적용했습니다.
from urllib.parse import urlsplit, urlunsplit, quote
def encode_media_url(url):
p = urlsplit(url)
return urlunsplit(p._replace(path=quote(p.path, safe="/%")))핵심은 safe="/%"입니다. /를 남겨야 경로 구조가 유지되고, %를 남겨야 이미 인코딩된 URL이 다시 인코딩되지 않습니다. 이중 인코딩을 막지 않으면 영문 URL이나 이미 처리된 URL이 오히려 깨집니다. 이 동작은 테스트 파일로 따로 고정해 두었습니다.
한 곳만 고쳤기 때문에 video_url, image_url, cover_url이 한꺼번에 해결됐습니다. 실제 게시로도 확인했습니다. 한글 슬러그 릴스의 컨테이너가 FINISHED 상태에 도달했고 릴스가 게시됐습니다. 변경은 게시 모듈 11줄 추가와 테스트 26줄이 전부였습니다.
자가진단 체크리스트
- 외부 API에 넘기는 미디어 URL 경로에 한글 같은 비 ASCII 문자가 인코딩 없이 들어가 있지 않습니까?
- 실패를 콘텐츠 종류별로만 나눠 보고, 슬러그에 쓰인 문자 종류별로는 나눠 보지 않았던 것은 아닙니까?
- URL 인코딩을 호출하는 곳마다 따로 하지 않고, 모든 게시 경로가 지나가는 한 지점에서 하고 있습니까? 그리고 이미 인코딩된 URL을 다시 인코딩하지 않는다는 것을 확인했습니까?
솔직한 부분
플랫폼이 왜 인코딩되지 않은 UTF-8 경로를 거부하는지, 정확한 규칙은 모릅니다. 확인한 것은 "그대로 넘기면 즉시 ERROR, 경로를 인코딩하면 FINISHED"라는 결과뿐입니다. safe에 %를 넣었기 때문에, 경로에 이스케이프가 아닌 진짜 % 문자가 들어 있으면 인코딩되지 않고 그대로 넘어갑니다. 쿼리 문자열은 이번 수정 범위에 넣지 않았습니다. 그리고 이 버그가 드러나기 전까지 한글 슬러그 릴스가 얼마나 게시되지 못했는지는 따로 세어 보지 않았습니다.