Files
document-haness/docs/clean-architecture-backend-template/tech-log-studio/commit-ambiguity-as-a-result/case/case-commit-ambiguity-is-not-only-sqlstate-08.md
T
DongHyeonkaandClaude Opus 5 b2963105a8 docs(keycloak-session-store): import the session-storage lab as a new project
The keycloak project ended with four open questions that design could not
settle. A two-VM lab was built to answer them by measurement, and this is
that material: 26 experiments, 125 raw command outputs, 22 browser captures.

Follows the import procedure in README.md.

  source/     the originating repository verbatim — 78 documents, 28 SVGs,
              8 manifests, plus .source-revision recording the commit
  final/      the SSOT
    document.md   729 lines written from the 29 experiment documents, not
                  concatenated: what was predicted, what was measured, and
                  where the measurement itself was wrong
    evidence/raw    125 outputs, flattened to <experiment>__<file> because
                    the originals collided (01-baseline.txt appeared three
                    times) and the audit only globs the top level
    evidence/meta   one per raw file; command and exitCode are null and the
                    README says why rather than inventing them
    evidence/browser  22 captures
    assets/       three diagrams through techviz
    .techviz/     their VizSpecs

A separate project rather than an addition to keycloak: the B-layer answers
that project's four questions, but the A, C and D layers are about cluster
failure, SSO and operations, and one document.md should hold one subject.
The four question records there can point here through 관계.

Recorded rather than papered over: only three of the 28 diagrams were
remade. The repository forbids hand-drawn SVG and forbids titles inside the
canvas; all 28 originals carry both, so converting them is redrawing, not
reformatting. They stay in source/ and the gap is written into the document.

verify-pipeline.py passes. audit-records.py reports no issues.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 22:51:59 +09:00

103 lines
5.5 KiB
Markdown

---
kind: CASE
slug: commit-ambiguity-is-not-only-sqlstate-08
title: pg_terminate_backend가 57P01로 도착하고 커밋 레코드는 이미 WAL에 있었다
topic: commit-ambiguity-as-a-result
project: clean-architecture-backend-template
status: 게시 전
sourceRevision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916
rootTreeNode: case:commit-ambiguity-is-not-only-sqlstate-08
evidenceCapturedOn: 2026-09-01
body: case-commit-ambiguity-is-not-only-sqlstate-08.body.md
assets:
- key: commit-ambiguity-is-not-only-sqlstate-08
file: ../../../final/evidence/rendered/commit-ambiguity-is-not-only-sqlstate-08.svg
evidence:
- ../../../final/evidence/raw/commit-ambiguity-is-not-only-sqlstate-08.txt
source:
- 원본 분석 절은 final/document.md#4-1 · analysis/05 §3.5 이다.
---
# pg_terminate_backend가 57P01로 도착하고 커밋 레코드는 이미 WAL에 있었다
커밋 모호성을 SQLSTATE class 08로만 정의했던 규칙이, 서버가 자기 종료를 알리는 57P01 앞에서 성립하지 않았다. 그 시점에 커밋 레코드는 이미 WAL에 있을 수 있다.
## 관계
- **모르는 것은 성공도 실패도 아닌 세 번째 결과여야 한다**
이 사례가 그 세 번째 결과를 필요로 하는 이유다.
- **커밋 모호성 판정은 넓혀도 좁혀도 해롭다**
이 사례가 규칙을 넓힌 쪽이고, 그 규칙의 반대편 비용을 함께 다룬다.
- **completion-unknown은 자동으로도 수동으로도 재시도하지 않는다**
이 분류가 만들어 내는 예외를 어떻게 다룰지 정한 결정이다.
- **커밋 모호성 계약 레인이 이 리비전에서 통과하는지 실행으로 확인되지 않았다**
이 사례의 회귀 방지 레인에 대한 미해결 질문이다.
## 문제
설계는 커밋 모호성을 SQLSTATE class 08, 즉 연결 예외로 정의했다. 그 정의는 클라이언트가 자기 연결에서 무슨 일이 일어났는지를 기준으로 삼는다.
문제는 서버가 스스로 종료를 알리는 경우다. in-flight 커밋 중인 백엔드를 pg_terminate_backend 로 끊으면 클라이언트는 57P01 을 받는다. 이것은 class 08 이 아니다. 클라이언트의 연결 시도에 대한 이야기가 아니라 서버가 자기 종료를 알린 것이기 때문이다.
그러나 커밋 입장에서 결과는 같고 오히려 더 나쁘다. 57P01 이 도착한 시점에 커밋 레코드가 이미 WAL 에 있을 수 있다. class 08 만 모호성으로 보는 규칙은 이 실패를 평범한 실패로 분류하고, 평범한 실패는 재시도된다. 커밋됐을 수도 있는 쓰기를 다시 실행하는 경로가 여기서 열린다.
## 결론
규칙이 57P01 과 57P02 와 57P03 까지 넓어졌다.
현재 CommitFailureClassifier 는 네 가지를 모호성으로 본다.
40003 : statement completion unknown
08 으로 시작하는 상태 : connection exception
57P01 57P02 57P03 : 서버가 자기 종료를 알린 상태
transport 수준 단절
세 상태를 함께 넣은 이유는 코드 주석에 남아 있다. 57P01 은 종료된 백엔드나 fast shutdown 이나 failover 가 보고하는 것이고, 그것이 도착할 때 커밋 레코드가 이미 WAL 에 있을 수 있다. 57P02 는 crash shutdown, 57P03 은 지금 접속할 수 없음이며, 서버가 in-flight 커밋을 어떻게 했든 클라이언트가 그것을 알지 못했다는 점에서 같다.
넓어진 규칙이 다시 좁아지지 못하도록 CommitAmbiguityContractTest 가 SQLSTATE 를 직접 assert 한다.
이 규칙에는 반대 방향의 비용도 함께 기록되어 있다. 커밋 단계의 모든 연결 오류를 모호성으로 표시하면 평범한 풀 고갈과 서버 재시작이 조정 큐로 밀려들고, 운영자는 그 큐를 읽지 않고 비우는 습관을 배운다. 그리고 정작 중요한 항목 하나가 나머지와 함께 지워진다.
## 검증 환경
OpenJDK : 21.0.12
Gradle : 9.0.0
Spring Boot : 4.0.8
데이터베이스 : PostgreSQL
관측 출처 : 저장소가 기록한 컨테이너 레인. 이 분석에서 재실행하지 않았다
## 재현 조건
원래 관측은 컨테이너 레인에서 나왔다. 절차는 다음과 같다.
1. 커밋이 진행 중인 트랜잭션을 만든다.
2. 그 백엔드를 pg_terminate_backend 로 끊는다.
3. 클라이언트가 받는 SQLSTATE 와 그 시점의 WAL 상태를 확인한다.
이번 사이클에서 확인한 것은 규칙의 현재 코드 형태와 그 근거 문장이다.
## 본문
<!-- body:start -->
설계가 "커밋 모호성은 SQLSTATE class 08뿐"이라고 적었다.
## 컨테이너 레인이 보인 것
in-flight 커밋 중인 백엔드를 `pg_terminate_backend`로 끊었을 때 `57P01`(admin_shutdown)이 도착하며, 그 시점에 커밋 레코드가 이미 WAL에 있을 수 있다.
## CommitAmbiguityContractTest 참조 위치
:::evidence key="commit-ambiguity-is-not-only-sqlstate-08" alt="코드베이스에서 CommitAmbiguityContractTest 를 검색한 출력 1줄. 이 기록이 세는 참조가 그 출력에 그대로 보인다." caption="CommitAmbiguityContractTest 코드베이스 검색 — 1줄 · exit 0" zoom="true"
:::
## 규칙이 넓어지고 다시 좁아지지 못하게 고정됐다
`57P01/57P02/57P03`까지 넓어졌고 `CommitAmbiguityContractTest`가 SQLSTATE를 직접 assert한다.
## 확인하지 못한 것
jpaPlatformFailureTest 를 이 리비전에서 실행하지 않았다. 57P01 관측이 PostgreSQL 16 과 17 과 18 전부에서 재현되는지도 확인하지 않았다. 관련 미해결 질문에 그 조건을 적어 두었다.
<!-- body:end -->