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>
9.1 KiB
kind, slug, title, topic, project, status, sourceRevision, rootTreeNode, evidenceCapturedOn, assets, evidence, source
| kind | slug | title | topic | project | status | sourceRevision | rootTreeNode | evidenceCapturedOn | assets | evidence | source | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| CASE | a-startup-probe-that-never-runs | startup probe가 production에서 한 번도 실행되지 않는다 | redis-command-admission | clean-architecture-backend-template | 게시 전 | 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916 | case:a-startup-probe-that-never-runs | 2026-09-02 |
|
|
|
startup probe가 production에서 한 번도 실행되지 않는다
기동 시 서버 능력을 확인하는 탐침이 있다. 그것을 만들거나 부르는 프로덕션 코드가 없어 한 번도 실행되지 않는다.
관계
- @Bean이 있다는 것은 조립 증거가 아니다 이 사례가 그 규칙의 형태다.
- 시작 검증기가 도는지는 그 능력에 자동설정 루트가 있는지와 일치한다 시작 검증기가 도는지를 자동설정 루트로 확인하는 절차다.
- 하위 시스템 전체가 미배선인데 그것을 켜는 플래그는 시작 검사를 수행한다 플래그와 실행의 어긋남이 반대 방향으로 나타난 사례다.
문제
기동 탐침은 서버가 실제로 무엇인지 묻는다. 그것이 확인하는 것은 넷이다. 서버 버전, 클러스터와 데이터베이스 번호, 명시적으로 켠 능력의 실재, 그리고 복제 배포의 쓰기 내구성이다.
넷째의 javadoc 이 이 저장소의 실측 사고 기록을 숫자째로 담고 있다.
결론
그 기동 실패는 일어나지 않는다.
두 탐침 클래스를 언급하는 프로덕션 코드는 다른 설정 클래스의 javadoc 링크 하나뿐이고, 확인 메서드를 부르는 프로덕션 코드는 0 이다. 자동설정이 만드는 빈 일곱에 탐침은 없다.
로직은 완성되어 있고 테스트 열여덟 케이스가 네 규칙을 고정한다. 없는 것은 호출 지점 하나다.
검증 환경
OpenJDK : 21.0.12 확인 방식 : 정적 도달성 확인 소스 수정 : x
재현 조건
- 기동 탐침의 클래스 javadoc 과 확인 메서드 본문을 읽고, 무엇을 몇 가지 확인하는지 센다.
- 넷째 항목의 javadoc 에 적힌 사고 기록과 결론, 그리고 검사가 두 겹인 이유를 읽는다.
- 두 탐침 클래스를 언급하는 프로덕션 코드를 세고 그것이 무엇인지 확인한다.
- 확인 메서드를 부르는 프로덕션 코드를 센다.
- 자동설정이 만드는 빈을 나열하고 그중 탐침이 있는지 센다.
- 두 테스트 파일의 케이스 수를 센다.
본문
기동 탐침은 서버가 실제로 무엇인지 한 번, 기동 시에 묻는다.
이 탐침이 무엇을 막는지부터 본다. 그것이 실행되지 않는다는 판정이 무엇을 잃는 것인지가 거기서 정해진다.
확인하는 것은 넷이다
:::evidence key="a-startup-probe-that-never-runs" alt="코드베이스에서 기동 탐침이 자기를 소개하는 문단과 확인 메서드 본문이 부르는 두 검사, 넷째 항목의 javadoc 이 담은 실측과 결론과 검사가 두 겹인 이유, 두 탐침을 언급하는 프로덕션 코드 하나와 그것이 javadoc 링크라는 것과 확인 메서드를 부르는 코드 수, 자동설정이 만드는 빈 일곱과 그중 탐침의 수, 그리고 로직을 고정하는 테스트 케이스 수를 뽑은 출력 70줄. 탐침을 부르는 프로덕션 코드가 0 이고 자동설정의 빈 일곱에 탐침이 없다는 것이 그 출력에 보인다." caption="탐침의 소개 문단과 두 검사 · 넷째의 실측과 두 겹 검사 · 언급 1(javadoc 링크) · 호출 0 · 빈 일곱에 탐침 없음 · 테스트 18케이스 — 70줄" zoom="true" :::
확인 메서드가 두 호출로 넷을 덮는다. 앞의 호출이 서버 버전과 배포 모드와 데이터베이스 번호와 명령 목록으로 능력을 판정하고, 뒤의 호출이 복제 배포의 쓰기 내구성을 요구한다.
클래스 javadoc 이 왜 서버에 묻는지 적는다. 설정은 배포가 무엇을 의도하는지 말하고 서버만이 무엇이 참인지 말한다는 것, 관리형 Redis 가 광고하는 버전이 모듈의 존재를 뜻하지 않는다는 것, 그리고 복제 배포의 쓰기 내구성은 어떤 클라이언트도 보상할 수 없는 서버 설정이라는 것이다.
같은 문단이 시점의 값도 적는다. 빠진 능력을 첫 요청에서 발견하면 장애이고, 여기서 발견하면 실패한 배포다.
넷째 항목의 javadoc 은 실측을 숫자째로 담는다
그 javadoc 은 이것이 SDK 가 보상할 수 없는 유일한 서버 설정이라고 적는다.
승격으로 밀려난 주 노드는 그 사실을 즉시 알지 못한다. 아는 순간까지 쓰기에 계속 성공을 답하고, 새 주 노드에서 재동기화할 때 그 쓰기들이 버려진다.
센티널 레인이 그것을 쟀다. 11초 동안 2,086건이 승인된 뒤 폐기됐고, 같은 실행에서 호출자에게 실패로 보인 명령은 통틀어 하나뿐이었다.
그 아래 문장이 왜 아무도 못 보는지 적는다. 서버가 답했으므로 드라이버도, 이 SDK 도, 호출자도 전부 성공으로 기록한다. 더할 지표도, 재시도할 실패도, 그것을 서술할 확신 값도 없다.
그래서 경고가 아니라 기동 실패다
복제 최소 개수와 상한이 걸린 최대 지연이 그 상황을 호출자가 대응할 수 있는 거절로 바꾼다. 같은 승격이 그때는 2,086건 대신 한 건을 잃었다.
그래서 그 설정 없는 복제 배포는 경고가 아니라 기동 실패라고 적는다. 보증을 무의미하게 만드는 설정은 조용히 성능을 낮추는 대신 컨텍스트를 멈춘다는 것이 이 SDK 의 원칙이라는 것이다.
면제는 가능하다. 배포가 정말로 쓰기 하나를 잃어도 괜찮을 수 있고 이 SDK 가 서버를 소유하지 않기 때문이다. 다만 면제에는 명시적 설정이 필요해서, 그 거래가 사고 중에 발견되는 대신 기록으로 남는다.
그 검사 자체도 한 번 고쳐졌다
같은 javadoc 이 검사가 두 겹인 이유를 적는다.
복제 개수만으로는 몇 개가 연결되어 있어야 하는지만 정해진다. 얼마나 뒤처져도 되는지는 최대 지연이 정하고, Redis 는 그 값 0 을 지연 요구 없음으로 다룬다.
그래서 복제 둘을 요구하면서 지연 상한을 0 으로 둔 배포는, 임의로 뒤처진 복제 둘이 붙어 있기만 하면 쓰기를 받는다. 개수 요구가 없애려던 바로 그 노출이 그대로 남는다.
개수만 검사하던 동안 그 설정이 통과했다. 그러면서 실패 메시지는 운영자에게 지연 상한을 설정하라고 말하고 있었다.
그 기동 실패는 일어나지 않는다
두 탐침 클래스를 언급하는 프로덕션 코드가 하나뿐이다. 그것도 다른 설정 클래스의 javadoc 안에 있는 링크다.
확인 메서드를 부르는 프로덕션 코드는 0 이다.
자동설정은 빈 일곱을 만든다. 설정과 그 검증, 자격증명, 런타임 클라이언트와 소유자, 그리고 헬스 지표 둘이다. 그중 탐침은 0 이다.
없는 것은 호출 지점 하나다
로직은 완성되어 있다. 두 테스트 파일의 열여덟 케이스가 네 규칙을 고정한다.
탐침이 연결을 들고 있지 않은 것은 설계된 것이다. 서버 사실을 인자로 받아서, 같은 로직을 단위 테스트와 실제 레인이 함께 쓰고 어느 계정이 물을지를 호출자가 정한다.
그 사실 중 둘을 읽는 명령이 관리 평면이라 애플리케이션 계정은 거부된다. 그래서 조립은 관리 계정이 설정된 배포에서만 완전하다.
지금 남은 것은 장애 쪽이다
빠진 능력을 첫 요청에서 발견하면 장애이고 여기서 발견하면 실패한 배포다. 조립이 없으므로 남은 것은 앞쪽이다.
복제 내구성은 그마저도 아니다. 서버가 성공을 답하므로 장애로도 나타나지 않는다.
확인하지 못한 것
애플리케이션을 부팅해 탐침이 실행되지 않는 것을 관측하지 않았다. 정적으로 도달성만 확인했고, 위 실측값은 이 저장소의 센티널 레인이 잰 것을 javadoc 에서 인용한 것이지 이 기록을 위해 다시 잰 것이 아니다.