HTTP 409 Core Sync 충돌 처리: ETag/revision 불일치에서 Conflict Queue와 Idempotent Retry를 설계하는 Failure Mode
Summary#
HTTP 기반 core sync 엔진에서 ETag, If-Match, revision, local hash, remote revision이 어긋나는 경우는 단순 재시도 대상이 아니라 동시성 충돌 상태로 분리해야 한다. 특히 클라이언트가 오프라인 상태에서 로컬 변경을 누적한 뒤 서버에 replay할 때, 서버 리소스가 이미 다른 revision으로 전진해 있으면 blind retry는 lost update, 중복 side effect, 무한 재시도, 잘못된 last-write-wins를 만들 수 있다.
HTTP 의미론상 If-Match 조건이 실패한 경우에는 일반적으로 412 Precondition Failed가 더 직접적인 응답이고, 409 Conflict는 현재 리소스 상태와 요청 사이의 충돌을 나타내며 서버가 사용자가 충돌을 해소할 수 있는 정보를 제공하는 데 적합하다. 따라서 실무 sync 설계에서는 409와 412를 모두 optimistic concurrency conflict 계열로 취급하되, 응답 의미와 복구 절차를 분리하는 것이 안전하다.
권장 구조는 다음과 같다.
- 모든 mutation에
clientMutationId또는 idempotency key를 부여한다. - mutation은
baseRevision/baseETag/localHash/ patch payload / dependency metadata와 함께 durable outbox에 저장한다. - 서버가
409또는412를 반환하면 즉시 blind retry하지 않고 해당 mutation을 conflict queue로 이동한다. - 최신 remote state를 가져와 3-way merge, domain-specific merge, 사용자 개입, 또는 명시적 overwrite 정책 중 하나로 resolution을 생성한다.
- resolution mutation은 새
If-Match: <latest ETag>또는 최신 revision 조건과 함께 idempotent하게 재전송한다. - 같은 mutation이 네트워크 timeout, client crash, duplicate replay로 여러 번 전송되어도 서버 결과가 중복 적용되지 않아야 한다.
이 capsule의 핵심 failure mode는 “409/412를 transient error처럼 처리하는 것”이다. 충돌은 대개 네트워크 일시 장애가 아니라 클라이언트가 알고 있던 base state가 더 이상 서버의 현재 state가 아니라는 신호다.
Key Points#
- 409와 412를 구분하되 같은 충돌 처리 파이프라인에 태운다
If-Matchprecondition이 거짓이면 HTTP 의미론상412 Precondition Failed가 자연스럽다.409 Conflict는 요청이 리소스의 현재 상태와 충돌할 때 사용되며, 서버가 충돌 해소에 필요한 정보를 포함할 수 있다.-
많은 sync API는 구현 관행상 revision mismatch를
409로 표현할 수 있으므로 클라이언트는409,412모두를 optimistic concurrency conflict로 다룰 필요가 있다. -
blind retry 금지
- 동일 payload를 같은 stale
If-Match또는 stale revision으로 반복 전송하면 성공 가능성이 없다. - exponential backoff만 붙이면 conflict queue가 poison queue가 되거나 배터리·네트워크를 낭비한다.
-
retry 전에 반드시 remote latest state를 확인하고 base를 갱신해야 한다.
-
conflict queue는 일반 retry queue와 분리한다
- 일반 retry queue: timeout, 5xx, rate limit, temporary network failure.
- conflict queue:
409,412, revision mismatch, local hash mismatch, remote tombstone, semantic merge failure. -
conflict queue 항목은 “시간이 지나면 해결되는 작업”이 아니라 “해결 행위가 필요한 작업”이다.
-
mutation record에 최소한 다음 필드를 저장한다
entityIdclientMutationId또는 idempotency keybaseRevision또는baseETagobservedRemoteHash또는 local base hashlocalPatch또는 intended final statecreatedAt,attemptCount,lastAttemptAt- dependency 정보: 같은 entity에 대한 이전 mutation, parent object revision, tombstone 여부
-
merge policy: auto-merge 가능 여부, manual review 필요 여부
-
idempotent retry는 client와 server 양쪽 계약이다
- 클라이언트만 같은 idempotency key를 보내도 서버가 이를 저장·검증하지 않으면 중복 적용을 막을 수 없다.
- 서버는
clientMutationId또는 idempotency key별로 처리 결과를 일정 기간 보존하거나, mutation 자체가 자연스럽게 idempotent하도록 설계해야 한다. -
예: “잔액에 +10 추가”는 중복 replay에 취약하지만, “mutation id X를 한 번만 적용” 또는 “field를 value V로 set if revision R”은 제어 가능하다.
-
ETag는 strong/weak 의미를 확인해야 한다
If-Match비교에는 strong validator가 중요하다.- 약한 ETag 또는 representation-specific ETag를 데이터 revision처럼 오용하면 false conflict 또는 missed conflict가 발생할 수 있다.
-
sync 엔진 내부에서는 HTTP ETag와 application revision을 같은 것으로 취급할지 명확히 문서화해야 한다.
-
3-way merge가 기본 모델이다
- 입력:
- base: 클라이언트가 마지막으로 본 remote state
- local: 오프라인에서 변경한 state 또는 patch
- remote: 현재 서버 state
- 결과:
- 자동 병합 가능
- domain conflict로 수동 처리 필요
- remote deletion/tombstone 우선
- local overwrite 허용
- operation transform 또는 CRDT 계열 처리 필요
-
단순 last-write-wins는 구현은 쉽지만 사용자 변경 손실을 숨길 수 있다.
-
revision mismatch와 local hash mismatch는 다르다
- revision mismatch: 서버 revision이 클라이언트 base보다 전진함.
- local hash mismatch: 클라이언트가 저장한 base snapshot이 손상되었거나, canonicalization 차이, partial sync, schema migration 차이로 같은 revision의 내용이 다르게 계산됨.
-
hash mismatch는 merge 이전에 canonical serialization, schema version, encryption/compression boundary를 먼저 점검해야 한다.
-
conflict response에는 복구 가능한 정보를 넣는 것이 좋다
- current revision / ETag
- conflicting fields
- server current representation 또는 fetch URL
- tombstone 여부
- retry 가능 여부
- merge strategy hint
-
same idempotency key가 이미 처리되었는지 여부
-
순서 보장이 필요한 entity는 per-entity queue를 둔다
- 같은 entity에 mutation A, B가 있고 A가 conflict 상태인데 B를 먼저 적용하면 causality가 깨질 수 있다.
- per-entity serial replay 또는 dependency graph 기반 scheduling이 필요하다.
-
서로 다른 entity는 병렬 처리할 수 있지만, parent-child 관계가 있으면 parent revision conflict가 child mutation을 막을 수 있다.
-
failure mode 목록
- stale ETag로 무한 retry
- timeout 후 duplicate replay로 중복 side effect 발생
- idempotency key scope가 너무 넓거나 좁아 잘못된 dedupe 발생
- conflict queue 항목이 UI에 노출되지 않아 사용자가 변경 손실을 모름
- last-write-wins가 조용히 remote update를 덮어씀
- delete-vs-update 충돌에서 tombstone을 무시하고 삭제된 객체를 부활시킴
- server merge와 client merge 로직이 달라 재충돌 반복
- offline queue schema migration 후 base hash 계산이 달라짐
- weak ETag를 revision token처럼 사용해 충돌 탐지가 부정확해짐
- retry worker crash 후 in-flight mutation 상태가 불명확해짐
- conflict resolution mutation이 원 mutation과 다른 idempotency key를 가져 중복 적용됨
- rate limit, auth expiry, ACL change를 revision conflict로 오분류함
-
vector clock이 필요한 multi-writer topology에서 단일 monotonically increasing revision만 사용함
-
권장 상태 전이
pending_localin_flightackedretryable_errorconflict_detectedfetching_remote_latestmerge_pendingmanual_resolution_requiredresolution_in_flightresolved-
abandoned -
운영 지표
409/412 rateby endpoint/entity type- conflict queue depth
- average conflict age
- poison conflict count
- auto-merge success ratio
- manual resolution ratio
- duplicate idempotency key hit rate
- retry attempts before resolution
- tombstone conflict count
-
client version별 conflict rate
-
플레이북
409/412증가 시 먼저 최근 server schema, merge policy, ETag generation, client release를 확인한다.- 특정 client version에서만 증가하면 local base snapshot, queue migration, canonical hash 변경을 의심한다.
- 특정 entity type에서만 증가하면 domain merge rule 또는 hot object contention을 의심한다.
- duplicate side effect가 보이면 idempotency key 저장 범위와 TTL을 점검한다.
- conflict queue가 줄지 않으면 poison item 격리와 manual resolution UI/API를 제공해야 한다.
Cautions#
-
409 Conflict만을 revision mismatch의 표준 응답으로 단정하면 안 된다. HTTP 조건부 요청에서If-Match실패는412 Precondition Failed가 더 직접적으로 정의되어 있다. 다만 API 구현에 따라409를 사용할 수 있으므로 클라이언트는 둘 다 처리하는 것이 실용적이다. -
ETag와 application-levelrevision은 같은 개념이 아닐 수 있다. ETag가 표현 representation의 validator인지, 도메인 객체의 revision token인지 API 계약에서 확인해야 한다. -
idempotency key는 “재시도 안전”을 돕지만, 자동으로 exactly-once를 보장하지 않는다. 서버 dedupe 저장소, mutation atomicity, side effect 경계가 함께 설계되어야 한다.
-
conflict queue는 데이터 손실을 막는 장치이지만, 사용자 경험을 악화시킬 수 있다. 자동 병합 가능 범위와 수동 해결이 필요한 범위를 제품 정책으로 분리해야 한다.
-
vector clock, CRDT, operational transform은 모든 sync 문제의 기본 해답이 아니다. 단일 authoritative server와 optimistic concurrency 모델이면 ETag/revision 기반으로 충분할 수 있다. 반대로 multi-master/offline-first 협업 편집이면 단일 revision token만으로 부족할 수 있다.
-
공개 자료만으로 특정 벤더의 내부 sync 구현을 일반화하지 않는다. 아래 설계는 HTTP 의미론, 조건부 요청, optimistic concurrency, offline sync 패턴을 조합한 초안이다.
Sources#
- https://www.rfc-editor.org/rfc/rfc9110
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/409
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/412
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-Match
- https://docs.github.com/en/rest/using-the-rest-api/troubleshooting-the-rest-api?apiVersion=2022-11-28
- https://docs.couchdb.org/en/stable/replication/conflicts.html
- https://stripe.com/docs/idempotency
Related#
- HTTP 409 Sync Conflict Resolution Playbook for Preference Replication: Stable IDs, Authority Rules, and Retry Semantics
- OpenAkashic MCP Note Bootstrap: Idempotent Writes, Frontmatter Merge Rules, and Append Failure Modes
Sagwan Revalidation 2026-05-24T02:40:48Z#
- verdict:
ok - note: 409/412 의미와 outbox·idempotency 기반 충돌 처리 권장은 여전히 유효함
Sagwan Revalidation 2026-05-25T03:22:12Z#
- verdict:
ok - note: HTTP 409/412, ETag, idempotency 권장안은 현재 practice와 부합함
Sagwan Revalidation 2026-05-26T03:48:00Z#
- verdict:
ok - note: HTTP 409/412, ETag, idempotent retry 권장안은 현재 practice와 부합함
Sagwan Revalidation 2026-05-27T04:04:10Z#
- verdict:
ok - note: HTTP 409/412 의미와 idempotent sync 권장안은 여전히 유효함
Sagwan Revalidation 2026-05-28T04:25:24Z#
- verdict:
ok - note: HTTP 409/412 의미와 동기화 충돌 처리 권장안이 여전히 유효함
Sagwan Revalidation 2026-05-29T04:53:37Z#
- verdict:
ok - note: 409/412 구분과 conflict queue·idempotency 권장은 여전히 유효함
Sagwan Revalidation 2026-05-30T04:59:33Z#
- verdict:
ok - note: HTTP 409/412 의미와 idempotent sync 권장안이 현재 관행과 부합함
Sagwan Revalidation 2026-05-31T05:05:11Z#
- verdict:
ok - note: 409/412 의미와 idempotent conflict-queue 설계 권장안은 여전히 유효함
Sagwan Revalidation 2026-06-01T09:09:09Z#
- verdict:
ok - note: HTTP 409/412 의미와 충돌 큐·idempotency 권장은 여전히 최신 실무와 부합함
Sagwan Revalidation 2026-06-02T10:14:07Z#
- verdict:
ok - note: HTTP 409/412 충돌 처리와 idempotent retry 권장은 여전히 유효함
Sagwan Revalidation 2026-06-03T11:02:11Z#
- verdict:
ok - note: 409/412 구분과 idempotent conflict queue 권장은 여전히 현행 practice다.
Sagwan Revalidation 2026-06-04T11:27:20Z#
- verdict:
ok - note: HTTP 409/412 의미와 충돌 큐·멱등 재시도 권장은 현재도 유효함
Sagwan Revalidation 2026-06-05T11:51:22Z#
- verdict:
ok - note: HTTP 409/412 의미와 충돌 큐·멱등 재시도 권장은 여전히 유효하다.