지난 3월에 저는 업로드 배치 작업을 두 번 실행했습니다. 첫 번째 실행은 불안정한 연결 때문에 중간에 멈췄고, 그래서 누구나 하듯이 다시 실행했습니다. Adobe는 중복 파일을 아무 문제 없이 받아들였습니다. 하지만 Vecteezy는 그렇지 않았습니다. 일요일 오후 내내 60개 정도의 제출물을 하나씩 삭제하는 데 시간을 보냈고, 동일한 콘텐츠를 재제출하는 것이 기여자 약관을 위반한다는 설명이 담긴 경고 이메일을 받았습니다. 바로 그 순간 저는 기억에 의존하는 것을 멈추고 원장(ledger)을 작성하기 시작했습니다.
이 글은 지루하지만 확실한 해결책, 즉 일반 텍스트 원장과 엄격한 CSV 헤더에 관한 것입니다. 흥미롭지는 않지만, 신뢰할 수 있는 파이프라인과 매번 감시해야 하는 파이프라인의 차이를 만들어줍니다.
CSV 헤더는 제안이 아니라 관문이다
세 가지 스톡 플랫폼 모두 다른 어떤 작업을 하기 전에 업로드 CSV를 구문 분석(parse)합니다. 그리고 잘못된 헤더는 즉각적인 거절을 의미하며, 경고가 아닙니다. 거절입니다. 각 플랫폼마다 필요한 헤더가 다르고, 서로 비슷하지도 않습니다:
- Adobe는 5개 열의 헤더를 요구합니다. 제목(Title), 키워드(keywords), 카테고리(category), 출시 정보(releases), 그리고 파일 참조(file reference)입니다. 정확한 순서로 다섯 개의 열이 필요합니다.
- Vecteezy는 4개의 열을 요구합니다. 필드는 적지만, Adobe 형식으로 제공하면 첫 번째 행에서 실패합니다.
- Dreamstime은 15개의 열을 요구합니다. 절반 정도는 비어 있어도 되지만, 모든 열이 올바른 위치에 존재해야 합니다.
처음에는 각 플랫폼마다 수동으로 편집하는 스프레드시트가 첫 번째 시도였습니다. 그것은 제가 한 열을 잘못 입력하여 제출 기회를 놓치기 전까지 약 2주 동안 지속되었습니다. 그래서 make_metadata.py는 이제 하나의 폴더에 있는 파일들로부터 세 가지 형식을 모두 작성합니다. 사용자는 이 스크립트를 ./my-assets를 가리키도록 설정하고, 플랫폼을 선택하면, 그 플랫폼이 기대하는 정확한 헤더만 출력하며 추가적인 것은 없습니다. Adobe는 5개 열을 받고, Vecteezy는 4개 열을 받고, Dreamstime은 15개 열을 받습니다. 템플릿의 이탈(template drift)도 없고, 수동 편집도 없습니다.
솔직한 주의사항이 하나 있습니다. 제목 파일(titles file)이 없으면 스크립트가 파일명을 제목 케이스(title-cases)로 변환하여 이를 제목으로 사용합니다. 첫 번째 시도에는 괜찮지만, 제출하기 전에 실제 제목과 키워드로 대체해야 합니다. 검토자들은 키워드 스팸과 파일명 기반의 제목을 알아차리며, 거절당하는 것은 수일간의 검토 대기 시간을 낭비하게 만듭니다.
중복 게시를 불가능하게 만드는 원장(Ledger)
제가 지난 3월에 실패했던 것을 해결한 방법은 놀라울 정도로 간단합니다. upload_tracker.py는 이미 제출된 항목들의 일반 텍스트 원장을 유지합니다. 세 가지 명령어만 실행하면 됩니다:
python upload_tracker.py pending items.txt # 아직 완료되지 않은 항목 확인
python upload_tracker.py done "asset-001.jpg"
python upload_tracker.py status
배치(batch)를 실행하기 전에, 저는 pending을 실행하고 그 출력을 업로더에 공급합니다. 만약 중간에 실행이 중단되더라도, 원장은 어떤 파일들이 완료되었는지 알고 있습니다. 재실행은 남아 있는 항목만 건드립니다. 손상시킬 상태가 없고, 유지해야 할 데이터베이스도 없으며, 다른 모든 것과 함께 읽고 백업할 수 있는 텍스트 파일일 뿐입니다.
이것이 단순히 편리함을 넘어 왜 중요할까요? 중복 제출은 기여자 계정(contributor account)에 플래그를 지정당하는 가장 빠른 방법 중 하나이기 때문입니다. Vecteezy는 제 중복 항목들을 아예 거부했고, Adobe는 통과시킨 후 검토 단계에서 보류했습니다. 어느 쪽이든, 검토자는 같은 에셋을 두 번 제출한 기여자를 보게 되며, 이는 볼륨(volume)을 쌓아 올리는 과정에서 원하는 인상이 아닙니다.
이 스크립트는 파이썬 표준 라이브러리만 사용합니다. pip install이나 종속성(dependencies)이 필요 없습니다. 메타데이터 빌더와 트래커만을 사용한다면, Python 3.9 이상 버전만 있으면 됩니다.
작은 박스에서 한 번에 하나의 프로세스를 처리하기
이 스크립트들 뒤에 있는 전체 파이프라인은 GPU가 없는 1 vCPU, 2 GB RAM 서버에서 실행됩니다. 이 제약 조건이 그 안에 있는 모든 습관을 형성했습니다:
- 하나의 코어에서 이미지 작업을 병렬로 분산(fan out)하지 마세요. 실제로는 쓰레싱(thrashing)을 막기 위해 순차적(Sequential) 방식이 더 빠릅니다.
- 각 에셋 처리 후
gc.collect()를 호출하여 메모리가 항목 간에 실제로 해제되도록 하세요.
- 평균 사용량이 아닌,
resource.getrusage(RUSAGE_SELF).ru_maxrss로 최대 RSS(Resident Set Size)를 측정하세요. OOM(Out Of Memory)-킬링을 당하는 원인은 바로 이 피크치입니다.
- 무거운 렌더링 단계는 서브프로세스(subprocess)당 파일 하나씩 실행하여, 서브프로세스가 종료될 때 OS가 메모리를 회수하도록 하세요.
- 미리보기는 60 dpi로 검사하고, 최종본은 300 dpi로 렌더링하세요. 전체 해상도로 미리보기를 하는 것이 제가 보는 가장 흔한 낭비입니다.
이 서브프로세스 규칙은 렌더링 단계가 시스템을 마비시키고 (ate the box), 커널이 90개 중 30번째 에셋에서 제 배치(batch)를 종료시켰을 때 알게 되었습니다. 이 장부(ledger) 덕분에 재실행이 31번째부터 시작할 수 있었는데, 이것이 제가 이 시스템에 충성하는 또 다른 이유입니다.
카탈로그를 안정적으로 유지하는 폴더 구조
수백 개의 에셋을 넘어서면, 구조화는 선택 사항이 아닙니다. 이 키트가 가정하는 레이아웃은 다음과 같습니다:
project/
assets/ 원본 출력물, 에셋당 파일 하나씩
output/ 제출 준비 완료 파일 + metadata.csv
...
제가 강조하고 싶은 부분은 research/입니다. 예전에
그 어떤 것도 영리하지 않습니다. 그것은 올바르게 작성된 헤더이며, 무엇이 배송되었는지 기억하는 텍스트 파일이고, 한 번에 하나의 일만 처리하는 기계입니다. 이 조합이 제가 수동으로 제출물을 재확인하는 것을 멈출 수 있게 해준 것입니다.
저는 네 개의 스크립트, 폴더 레이아웃, 그리고 RAM 노트를 파이프라인 스타터 키트로 함께 제공합니다. 왜냐하면 이것들이 제가 모든 배치에서 사용하는 정확한 도구들이기 때문입니다. 만약 여러분이 자신만의 파이프라인을 구축하고 있다면, 저에게 잃었던 중복 제출의 일요일을 아낄 수 있을 것입니다.
파이프라인 스타터 키트 받기
디지털 제품을 구축하고 계신가요? 디지털 제품 판매자를 위한 무료 가이드 및 키트.