Skip to content
isdnetworks
Go back

정리가 전송 성공에 매달려 있다

(수정됨)

한 채널의 연동 해제 대상이 수십만 건이었고 신 경로에는 외부 호출 없이 즉시 정리하는 forceUnlink() 강제 수단이 있었다. 그런데 대상을 version으로 GROUP BY 해 세니 절반 넘게 구형이나 미분류여서 십수만 건은 그 수단을 못 쓰는 상태였다.

Table of contents

Open Table of contents

배경 — 구 경로의 두 단계

구 경로 코드를 직접 읽었다. unlink()는 event()만 발행하고 실제 작업은 다른 실행기에서 두 단계로 일어났다.

첫 단계에서 approval_type을 바꿔 작업 생성을 차단하고 관련 작업에 deleted_at을 찍은 뒤 두 번째 단계에서 연동 레코드에 deleted_at을 찍는다. 신 경로와 비교하니 복제본 생성 여부와 상품 상태를 건드리는지가 달라서 후처리 범위 자체가 달랐다.

검증 — 이름에 적힌 호출 조건

실행기 함수 이름에 AfterStopSucceeded라는 접미가 붙어 있었다. 무슨 이벤트 뒤인지를 찾아 호출 지점을 봤다.

stop 요청을 마켓에 보내고 그 결과가 성공일 때만 이 실행기를 부르고 있었다. 함수 이름의 접미가 호출 조건을 알려 주고 있었고 그것을 읽은 것이 이 조사의 전환점이었다.

원인 — 정리하려는 대상이라서 못 하는 것

우리 대상이 무엇이었는지가 여기서 문제가 됐다. 마켓에 이미 존재하지 않는 상품들이었고 그래서 정리하려는 것이었다.

stop 요청을 보내면 마켓이 그런 상품이 없다고 404로 답해 실패하고 그러면 후처리 자체가 안 돈다. 정리하려는 대상이라서 정리가 안 되는 순환이었다.

대안 — 우회 수단과 그 제약

신 경로에는 마켓 호출 없이 바로 정리하는 forceUnlink()가 있는데 구 경로에는 그것이 없었다. 이벤트와 전송과 성공과 후처리로 이어지는 흐름밖에 없다.

두 가지 방법이 있었는데 구 경로에도 forceUnlink()를 새로 만드는 것과 job_id로 직접 처리하는 기존 통합 헬퍼를 우회로 쓰는 것이다. 뒤쪽을 골랐다. 이유는 구 경로에 새 코드를 넣으면 배포와 검증이 이번 정리 일정을 넘어서다. 대신 제약을 감수했는데 작업이 이미 존재하는 대상만 처리할 수 있고 별도 권한이 필요하다. 각 단계가 연동 레코드 단건을 받으므로 여러 채널이 한꺼번에 영향받지는 않아서 범위는 안전하다는 것도 함께 확인했다.

교훈 — 경로 간 비대칭

이 조사의 순서가 중요했다. 대상을 버전별로 나눠 세고 구 경로 코드를 직접 읽은 뒤 실행 가능성을 판단하고 우회 수단을 찾는 순서였다.

코드를 읽지 않고 시작했으면 십수만 건에 처리를 돌리고 왜 안 되는지를 나중에 찾았을 것이다. 신 경로에 수단이 있으니 구 경로에도 비슷한 것이 있으리라는 가정이 틀린 것이었다. 새 경로를 만들 때 필요한 것을 추가하고 옛 경로는 그대로 두므로 둘의 기능은 대칭이 아니고 매번 그 경로에 그 기능이 있는지를 확인해야 한다.

정리


Share this post on:

Previous Post
안 쓴다를 확인하는 두 축
Next Post
Google Play 앱 정책 위반 알림 대응 — 한꺼번에 8건 받았을 때