Files
document-haness/docs/clean-architecture-backend-template/tech-log-studio/operator-approval-and-destructive-operations/case/case-blocking-means-startup-fails-and-nothing-runs-it.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

108 lines
6.1 KiB
Markdown

---
kind: CASE
slug: blocking-means-startup-fails-and-nothing-runs-it
title: BLOCKING 이면 기동이 실패한다는 보장이 어떤 배선에서도 실행되지 않는다
topic: operator-approval-and-destructive-operations
project: clean-architecture-backend-template
status: 게시 전
sourceRevision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916
rootTreeNode: case:blocking-means-startup-fails-and-nothing-runs-it
evidenceCapturedOn: 2026-09-01
assets:
- key: blocking-means-startup-fails-and-nothing-runs-it
file: ../../../final/evidence/rendered/blocking-means-startup-fails-and-nothing-runs-it.svg
evidence:
- ../../../final/evidence/raw/blocking-means-startup-fails-and-nothing-runs-it.txt
source:
- 원본 분석 절은 analysis/messaging/messaging-admin-api.md §17 P2 이다.
---
# BLOCKING 이면 기동이 실패한다는 보장이 어떤 배선에서도 실행되지 않는다
토폴로지 검증에서 차단 심각도는 기동을 실패시킨다고 두 javadoc 이 적는다. 그 판정을 부르는 production 코드가 없고, 그것을 부를 수 있는 유일한 진입점도 호출자가 없으며, 서비스 빈을 스타터가 만들지 않는다.
## 관계
- **승인·검증·실행의 분리와 그것을 타입으로 표현하기**
이 사례가 속한 표면이다.
- **검증기는 발행이 아니라 주입이 강제다**
이 사례가 어기는 규칙이다.
- **시작 검증기가 도는지는 그 능력에 자동설정 루트가 있는지와 일치한다**
같은 계열의 판정 규칙이다.
- **시작 검증기 13개 규칙이 유일한 조립 지점에서 호출되지 않는다**
같은 형태가 gRPC 쪽에서 나타난 사례다.
## 문제
목적지 프로파일은 보장을 선언한다. 내구성이 필요하다거나, 순서가 필요하다거나, 특정 복제 수준이 필요하다는 선언이다.
브로커의 실제 토폴로지가 그 보장을 줄 수 없으면 그것은 기동 시점에 잡아야 한다. 런타임에 발견하면 이미 메시지를 받은 뒤다.
## 결론
타입은 그 상황을 정확히 표현하고, 표현한 것을 아무도 읽지 않는다.
심각도 열거형의 차단 값 javadoc 이 적는다.
> The destination cannot deliver a declared guarantee; startup must fail.
검증 보고서의 수용 가능성 요구 메서드 javadoc 이 적는다.
> Fails startup when any blocking issue was found.
그 메서드의 production 호출부가 0이다. 그것을 부를 수 있는 유일한 진입점인 토폴로지 검증 메서드도 호출부가 0이고, 그 메서드를 가진 서비스 빈을 스타터가 만들지 않는다.
결과: 복제 계수가 1인 목적지에 내구성을 선언해도 컨텍스트는 정상 기동한다.
고치는 방법이 같은 리프에 이미 있다. 내구성 검증기가 초기화 콜백으로 저널 내구성을 기동 시점에 검사하고 실패시킨다. 같은 모양의 빈 하나면 된다. 다만 브로커 검사기가 없으면 검증할 수 없으므로 그 조건부는 유지해야 한다.
이 항목이 무거운 이유는 리프가 출하 애플리케이션 소속이고, 보장이 문서와 타입과 테스트 세 겹으로 존재하는데 배선만 없다는 점이다. 읽는 사람은 보장이 있다고 믿을 근거를 세 개 갖는다.
그리고 토폴로지 검증 스택이 이 가족에 두 벌 있다. 파티션 스케일업에 대해 한쪽은 권고로 두어 기동을 허용하고 다른 쪽은 차이로 보아 거부한다. 둘 다 호출자가 0이라 지금은 충돌하지 않지만, 배선하는 순간 어느 스택을 고르느냐가 스케일업한 배포의 기동 여부를 가른다.
## 검증 환경
OpenJDK : 21.0.12
Gradle : 9.0.0
확인 방식 : 두 메서드의 호출자 전수 검색과 스타터의 빈 목록 확인
소스 수정 : x
## 재현 조건
원문은 final/evidence/raw/302-admin-api-topology-guarantee-unwired.txt (EVD-302) 에 있다.
1. 차단 심각도와 수용 가능성 요구 메서드의 javadoc 을 읽는다.
2. 그 메서드의 호출자를 저장소에서 검색한다.
3. 그것을 부를 수 있는 진입점의 호출자를 검색한다.
4. 스타터가 그 서비스 빈을 만드는지 확인한다.
5. 같은 리프의 내구성 검증기가 어떻게 배선되어 있는지 확인한다.
## 본문
<!-- body:start -->
`BLOCKING` 의 javadoc 이 "The destination cannot deliver a declared guarantee; startup must fail" 이라고 적고, `requireAcceptable()` 의 javadoc 이 "Fails startup when any blocking issue was found" 라고 적는다.
## MessagingAdminDurabilityValidator 참조 위치
:::evidence key="blocking-means-startup-fails-and-nothing-runs-it" alt="코드베이스에서 MessagingAdminDurabilityValidator 를 검색한 출력 3줄. 이 기록이 세는 참조가 그 출력에 그대로 보인다." caption="MessagingAdminDurabilityValidator 코드베이스 검색 — 3줄 · exit 0" zoom="true"
:::
## 세 겹으로 호출자가 없다
그 메서드의 production 호출부가 0 이고, 그것을 부를 수 있는 유일한 진입점도 호출부가 0 이며, 그 서비스 빈을 스타터가 만들지 않는다. 결과적으로 복제 계수 1인 목적지에 내구성을 선언해도 컨텍스트는 정상 기동한다. 타입은 그 상황을 정확히 표현할 수 있고 표현한 것을 아무도 읽지 않는다.
## 고치는 방법이 같은 리프에 이미 있다
`MessagingAdminDurabilityValidator``InitializingBean` 으로 저널 내구성을 기동 시점에 검사하고 실패시킨다. 같은 모양의 빈 하나면 된다.
## 이 항목이 무거운 이유
이 리프가 `app-bootstrap` 소속이고 보장이 문서·타입·테스트 세 겹으로 존재하는데 배선만 없다 — 읽는 사람은 보장이 있다고 믿을 근거를 세 개 갖는다. 그리고 토폴로지 검증 스택이 이 리프에 두 벌 있고 파티션 스케일업에 대한 판정이 서로 반대라, 배선하는 순간 어느 스택을 고르느냐가 스케일업한 배포의 기동 여부를 가른다. P2.
## 확인하지 못한 것
컨텍스트를 세워 기동 성공을 관측하지 않았다. 호출부 부재로 판정했다.
<!-- body:end -->