모든 글
Silent Failures · 2분 읽기

조용히 실패하는 것들 2 — 원자적인 편집은 통째로 실패하고, 무엇이 빠졌는지 말하지 않아요

스토어 이미지가 며칠째 안 바뀌어 있었어요. 없는 로케일 하나 때문에 이미 있던 로케일의 이미지까지 통째로 버려지고 있었고, 로그 끝에는 FAILED 한 줄뿐이었습니다.

#play-store#출시#gradle#자동화

지난 글에서는 도구가 겹침을 잘못 판정한 이야기를 했어요. 해시로는 저장소를 넘나드는 같은 일을 알아볼 수 없다는 이야기였죠. 그래도 그건 결과물이 남긴 남았습니다.

이번 건 더 고약해요. 아무것도 안 올라갔는데 그 사실을 아무도 말해주지 않았습니다.

구글 플레이 등록정보를 Gradle Play Publisher(GPP)로 올리고 있어요. 명령 한 줄이면 텍스트도 이미지도 다 올라갑니다.

./gradlew publishReleaseListing

돌렸어요. 그런데 며칠이 지났는데 스토어 이미지가 안 바뀌어 있었습니다.

텍스트와 이미지가 한 편집(edit)에 들어갑니다

플레이 API는 “편집(edit)“이라는 단위로 움직여요. 편집을 열고, 그 안에서 이것저것 바꾸고, 마지막에 커밋합니다. 커밋 전까지는 아무것도 반영되지 않고, 커밋하면 전부 반영돼요.

원자적입니다. 반쯤 올라간 스토어가 생기지 않아요.

그리고 GPP 4.1.1은 등록정보 텍스트와 이미지를 같은 편집에서 올립니다. 그러니 이 둘은 함께 성공하거나 함께 실패해요.

없는 로케일 하나가 전부를 죽였어요

새 언어를 추가하면서 graphics/ 폴더를 여러 로케일에 만들어뒀습니다. 그중 일부는 스토어에 아직 존재하지 않는 로케일이었어요.

GPP는 이미지를 올리기 전에 현재 이미지 목록을 GET으로 가져옵니다. 그런데 스토어에 없는 로케일에서는 이게 404로 죽어요.

Listing for language 'fr-FR' not found

그리고 그 편집은 원자적이므로, 이미 잘 있던 ko-KR의 이미지까지 통째로 버려졌습니다.

빌드 로그 끝은 이랬어요.

FAILED

원자성의 뒷면

원자성은 좋은 성질이에요. 반쯤 올라간 스토어를 막아주니까요.

대신 실패의 원인이 전체의 아무 데나 있을 수 있게 합니다. 그리고 로그는 마지막 예외만 보여줘요. “무엇이 안 올라갔는가”는 로그에 없습니다. 스토어 쪽을 열어봐야 알아요.

여기서 두 번째 함정이 나옵니다. 콘솔은 “검토 중인 것”과 “올라간 것”을 구분해주지 않아요. 눈으로 보면 바뀐 것 같아 보입니다. 그래서 콘솔이 아니라 API를 봐야 해요.

확인하는 법 — sha1을 맞춰봅니다

편집을 하나 만들고, 이미지 목록을 읽고, 해시를 로컬 파일과 맞춰보고, 편집을 지웁니다. 읽기만 하니까 지워도 아무 일도 안 일어나요.

# 1. edit 을 만듭니다
# 2. GET listings/{lang}/phoneScreenshots → 각 이미지의 sha1
# 3. 로컬 파일의 shasum 과 맞춥니다
shasum fastlane/metadata/android/ko-KR/images/phoneScreenshots/*.png
# 4. edit 을 DELETE

해시가 맞으면 올라간 것이고, 다르면 안 올라간 거예요. 눈으로 본 콘솔은 증거가 아닙니다.

우회로 — 두 번 돌립니다

스토어에 없는 로케일이 있으면 이렇게 해요.

  1. 새 로케일의 graphics/를 잠깐 치워두고 한 번 돌립니다 → 로케일이 생깁니다
  2. 되돌리고 다시 돌립니다 → 이미지가 올라갑니다

저장소 트리는 결국 그대로예요. 명령을 두 번 돌릴 뿐입니다.

막힌 길 하나

“REST로 직접 쳐서 로케일만 먼저 만들면 되지 않나?” 싶어서 해봤는데 안 됐어요. edits:validate는 200을 주는데 edits:commit이 HTML 404를 줍니다.

결국 커밋은 플러그인에게 맡기는 수밖에 없었어요. 되돌린 시도지만 적어둡니다. 안 적으면 다음에 또 같은 자리를 파거든요.

같은 꼴을 전날에도 봤어요

바로 전날 “소스 세트 자리” 함정에 걸렸었습니다. 파일을 엉뚱한 소스 세트에 두었는데 빌드가 아무 말도 안 하고 통과했어요.

같은 병입니다. 도구가 조용히 실패하고, 돌린 쪽은 돌렸다고 믿는 것.

그래서 규칙을 하나 세웠어요.

배포는 “돌렸다”가 아니라 “확인했다”로 끝난다.

명령이 0을 반환한 것은 확인이 아니에요. 스토어에 있는 파일의 해시가 내 파일의 해시와 같은 것이 확인입니다.

고치고 나서 적어 둔 것

이번 글의 결론은 “확인하려면 해시를 보라”였어요. 그런데 그 해시를 파일에 적어두면, 이번엔 그 파일이 새로운 함정이 됩니다.

다음 글이 그 이야기예요. 그리고 깨질 걸 미리 알고 있었는데도 깨졌습니다.

👉 3 — 해시를 파일에 적는 순간 그 파일은 이력의 일부가 됩니다