Skip to content
isdnetworks
Go back

멱등은 전제 위에 선다

(수정됨)

products 를 수정할 때마다 같은 이미지가 S3 에 매번 재업로드되고 있었다. 비용 문제라 멱등하게 만들면 되는 일로 보였다.

Table of contents

Open Table of contents

문제 — 잘못 말한 책임 경계

처음에는 요청 쪽 syncToChannels() 가 재업로드 여부를 판단한다고 설명했다가 지적을 받았다. 다시 보니 판단은 MediaService 쪽이 하고 있었다.

if ($existing && $existing->file_hash === $hash) {
    return $existing;              // 같으면 재사용
}

MediaService 에 file_hash 로 같은지 판단하는 멱등 로직이 이미 구현돼 있었다. 없는 것을 만들어야 하는 상황이 아니라 있는 것이 왜 안 먹는지를 봐야 하는 상황이었다.

원인 — 멱등이 서는 전제

로직이 있는데 왜 안 먹는지를 보려고 그 로직의 전제를 봤다.

Media::where('model_id', $modelId)->where('collection_name', $collection)

이 조회가 옛 Media 레코드를 찾을 수 있어야 재사용 분기로 들어간다. spatie 공식 문서대로 미디어는 모델과 collection_name 으로 묶이므로 즉 model_id 가 불변이어야 멱등이 성립한다. 해시 비교 로직은 그 전제 위에서만 의미가 있다.

대상마다 다른 결과

두 종류를 비교하니 결과가 갈렸다. 대표와 부가 이미지는 products.id 를 model_id 로 쓰는데 그것은 수정해도 안 바뀌므로 옛 레코드를 찾고 멱등이 그대로 동작한다.

본문 이미지는 product_contents.id 를 쓰는데 이 시스템은 수정할 때마다 새 product_contents 행을 발행한다. 새 식별자로는 옛 레코드를 찾을 수 없으므로 멱등이 원리적으로 성립하지 않는다. 같은 로직인데 한쪽에서만 동작하는 이유가 전제에 있었다.

판단 기준 — 요청 쪽으로 옮기면 안 되는 이유

그러면 요청 쪽에서 판단하자는 생각이 들 수 있는데 그러면 안 된다. 판단 로직이 두 곳에 생기고 처리 쪽이 이미 하는 것을 또 하게 되며 두 벌이 시간이 지나면 갈린다.

책임은 MediaService 에 있으므로 거기서 안 되는 이유를 없애야 한다. 본문 이미지는 두 가지 방법이 있었는데 옛 Media 를 새 model_id 로 이어 붙이는 것과 product_contents 를 새로 발행하지 않고 제자리 갱신하는 것이다. 앞쪽을 골랐다. 이유는 뒤쪽이 근본적이지만 새 행을 발행하는 이유가 롤백 때문이라 롤백 설계를 같이 바꿔야 해서다. 대신 본문이 수정될 때마다 model_id 를 옮기는 처리가 하나 더 붙는 것을 감수했다.

주의 — 비효율과 틀림의 구분

여기서 판단이 하나 필요했다. 재업로드가 오동작인지 아닌지다.

결과는 맞고 같은 이미지가 다시 올라갈 뿐이므로 오동작이 아니라 비용 문제였다. 그래서 병합을 막는 사유가 아니라고 명시했다. 비효율과 틀림을 구분하지 않으면 전부 급한 일이 된다.

최종 정리도 그 형태로 적었다. MediaService 의 멱등 로직은 이미 구현돼 있고 요청 쪽 배선과 product_contents 식별자 안정화가 미구현이다. 멱등을 구현해야 한다고 적는 것과 이 둘이 미구현이라고 적는 것은 다른 작업 지시가 된다.

이 정리는 내가 틀리게 말했다가 지적받고 다시 잡은 결과다. 요청 쪽이 판단한다는 전제로는 요청 쪽에 로직을 넣자는 답이 나오는데 그것은 이미 있는 것을 한 벌 더 만드는 일이었다. 틀린 전제가 틀린 작업을 만든다.

정리


Share this post on:

Previous Post
작업 공간 둘의 통합 여부
Next Post
중간에 받은 지적의 자리