기술 · 실용 가이드
PostgreSQL SQLSTATE 40001? 실패한 문장이 아니라 전체 트랜잭션을 재시도하세요
SQLSTATE, 격리 수준과 실패 경계를 기록하고 롤백한 뒤 모든 읽기와 결정을 제한된 루프에서 다시 실행하세요. 되돌릴 수 없는 부수 효과는 커밋 뒤로 옮깁니다.

SQLSTATE 40001은 PostgreSQL의 serialization_failure입니다. Repeatable Read나 Serializable에서 발생하며 COMMIT 때 처음 반환될 수도 있습니다. 데이터베이스가 거절한 단위는 전체 트랜잭션이므로 마지막 문장만 재시도하면 무효가 된 스냅샷의 결정을 재사용하게 됩니다.
안전한 처리기는 트랜잭션 callback과 COMMIT 전체를 감쌉니다. 40001을 확인하고 롤백한 뒤 제한된 backoff와 jitter를 적용하고 BEGIN부터 모든 읽기, 결정, 쓰기를 다시 합니다. 데이터베이스는 SQL과 값을 선택한 애플리케이션 로직을 자동 재생할 수 없습니다.
재시도로 경합을 숨기지 마세요. 횟수나 시간 예산과 지표를 두고 계속되는 실패를 드러내야 합니다. 이메일, 결제, 게시 같은 되돌릴 수 없는 효과는 커밋 뒤에 실행하고 outbox나 멱등 키로 전달을 연결합니다.
재시도 전에 실패 경계를 기록하세요
SQLSTATE, 격리 수준, 시도 횟수, 경과 시간, 문장 또는 COMMIT 경계를 기록합니다. 메시지 문자열이 아니라 SQLSTATE로 제어하세요.
COMMIT 실패도 정상적인 판정 지점입니다. 서버가 안전한 직렬 순서를 판단하려면 전체 읽기/쓰기 집합이 필요할 수 있습니다.
BEGIN부터 읽기와 결정을 재생하세요
롤백 뒤 첫 읽기부터 다시 시작합니다. 존재 검사, 재고, 가격, 권한, 파생 값을 다시 계산하세요. 실패한 UPDATE나 savepoint만 반복하면 오래된 가정이 남습니다.
callback 한 번을 DB 시도 한 번으로 만들고 callback과 COMMIT 오류를 같은 경로에서 처리하세요.
재시도를 제한하고 경합을 보이세요
작은 최대 횟수나 전체 시간, backoff와 jitter를 둡니다. 매번 상태를 초기화하고 중단된 트랜잭션을 재사용하지 마세요.
작업별로 측정하고 반복 고갈 시 긴 트랜잭션, 핫 키, 인덱스, 풀과 격리 요구를 점검하세요. 단순히 격리 수준을 내리지 마세요.
부수 효과는 커밋 안전선 밖에 두세요
callback 코드는 여러 번 실행될 수 있습니다. 커밋 전에 이메일, 결제, 게시나 비멱등 API를 호출하지 마세요.
같은 트랜잭션에 outbox를 쓰고 별도 worker가 커밋 뒤 전송하게 하세요. 외부 멱등 키는 안정된 비즈니스 요청에서 만듭니다.
인접 SQLSTATE를 다른 경로로 보내세요
40P01 deadlock은 재시도할 수 있지만 lock order 진단이 필요합니다. 23505 자동 재시도는 애플리케이션별 증명이 필요합니다.
40003은 완료 여부 불명이므로 반복 전 결과를 대조하세요. class 40 전체 자동 재시도는 중복 작업을 만들 수 있습니다.
